@lovrozagar/honey 0.6.5 → 0.7.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 +514 -192
- package/bin/honey.js +25 -0
- package/dist/accepts.d.ts +7 -1
- package/dist/accepts.d.ts.map +1 -1
- package/dist/accepts.js +126 -0
- package/dist/accepts.js.map +1 -0
- package/dist/body-kind.d.ts +26 -0
- package/dist/body-kind.d.ts.map +1 -0
- package/dist/body-kind.js +70 -0
- package/dist/body-kind.js.map +1 -0
- package/dist/body-limit.d.ts +5 -1
- package/dist/body-limit.d.ts.map +1 -1
- package/dist/body-limit.js +126 -0
- package/dist/body-limit.js.map +1 -0
- package/dist/build/index.d.ts +19 -3
- package/dist/build/index.d.ts.map +1 -1
- package/dist/build/index.js +173 -0
- package/dist/build/index.js.map +1 -0
- package/dist/cli-args.d.ts +33 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +102 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-go/auth.go +26 -0
- package/dist/cli-go/config.go +192 -0
- package/dist/cli-go/errors.go +75 -0
- package/dist/cli-go/multipart.go +79 -0
- package/dist/cli-go/output.go +163 -0
- package/dist/cli-go/root.go +30 -0
- package/dist/cli-go/stream.go +88 -0
- package/dist/cli-go/version.go +5 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +209 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/defaults.js +48 -0
- package/dist/client/defaults.js.map +1 -0
- package/dist/client/error.d.ts +35 -0
- package/dist/client/error.d.ts.map +1 -1
- package/dist/client/error.js +71 -0
- package/dist/client/error.js.map +1 -0
- package/dist/client/http.d.ts +67 -8
- package/dist/client/http.d.ts.map +1 -1
- package/dist/client/http.js +571 -0
- package/dist/client/http.js.map +1 -0
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +95 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/path.d.ts +26 -0
- package/dist/client/path.d.ts.map +1 -0
- package/dist/client/path.js +163 -0
- package/dist/client/path.js.map +1 -0
- package/dist/client/redirect-policy.d.ts +12 -0
- package/dist/client/redirect-policy.d.ts.map +1 -0
- package/dist/client/redirect-policy.js +20 -0
- package/dist/client/redirect-policy.js.map +1 -0
- package/dist/client/sdk.d.ts +36 -0
- package/dist/client/sdk.d.ts.map +1 -1
- package/dist/client/sdk.js +292 -0
- package/dist/client/sdk.js.map +1 -0
- package/dist/client/sse.d.ts +13 -0
- package/dist/client/sse.d.ts.map +1 -1
- package/dist/client/sse.js +129 -0
- package/dist/client/sse.js.map +1 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/ws.d.ts +9 -2
- package/dist/client/ws.d.ts.map +1 -1
- package/dist/client/ws.js +112 -0
- package/dist/client/ws.js.map +1 -0
- package/dist/client-go/errors.go +236 -0
- package/dist/client-go/export.go +44 -0
- package/dist/client-go/invalidation.go +371 -0
- package/dist/client-go/nullable.go +62 -0
- package/dist/client-go/realtime.go +354 -0
- package/dist/client-go/result.go +20 -0
- package/dist/client-go/runtime.go +975 -0
- package/dist/client-go/sse.go +159 -0
- package/dist/client-go/transport.go +495 -0
- package/dist/client-go/ws.go +128 -0
- package/dist/client-info.d.ts +36 -0
- package/dist/client-info.d.ts.map +1 -0
- package/dist/client-info.js +53 -0
- package/dist/client-info.js.map +1 -0
- package/dist/client-mcp/README.md +10 -0
- package/dist/client-mcp/server.ts +221 -0
- package/dist/client-mcp/types.ts +19 -0
- package/dist/client-python/_errors.py +115 -0
- package/dist/client-python/_invalidation.py +494 -0
- package/dist/client-python/_realtime.py +179 -0
- package/dist/client-python/_runtime.py +860 -0
- package/dist/client-python/_sse.py +155 -0
- package/dist/client-python/_transport.py +366 -0
- package/dist/client-python/_ws.py +159 -0
- package/dist/client-python/py.typed +0 -0
- package/dist/client-rust/errors.rs +220 -0
- package/dist/client-rust/invalidation.rs +412 -0
- package/dist/client-rust/invalidation_sync.rs +93 -0
- package/dist/client-rust/nullable.rs +17 -0
- package/dist/client-rust/realtime.rs +702 -0
- package/dist/client-rust/result.rs +22 -0
- package/dist/client-rust/runtime.rs +980 -0
- package/dist/client-rust/runtime_sync.rs +484 -0
- package/dist/client-rust/sse.rs +188 -0
- package/dist/client-rust/ws.rs +167 -0
- package/dist/codegen-go-cli.d.ts.map +1 -1
- package/dist/codegen-go-cli.js +964 -0
- package/dist/codegen-go-cli.js.map +1 -0
- package/dist/codegen-go.d.ts +15 -3
- package/dist/codegen-go.d.ts.map +1 -1
- package/dist/codegen-go.js +872 -0
- package/dist/codegen-go.js.map +1 -0
- package/dist/codegen-hash.js +9 -0
- package/dist/codegen-hash.js.map +1 -0
- package/dist/codegen-ir.d.ts +69 -2
- package/dist/codegen-ir.d.ts.map +1 -1
- package/dist/codegen-ir.js +661 -0
- package/dist/codegen-ir.js.map +1 -0
- package/dist/codegen-lang.d.ts +65 -0
- package/dist/codegen-lang.d.ts.map +1 -0
- package/dist/codegen-lang.js +526 -0
- package/dist/codegen-lang.js.map +1 -0
- package/dist/codegen-load.d.ts +31 -0
- package/dist/codegen-load.d.ts.map +1 -0
- package/dist/codegen-load.js +138 -0
- package/dist/codegen-load.js.map +1 -0
- package/dist/codegen-loaders.js +55 -0
- package/dist/codegen-loaders.js.map +1 -0
- package/dist/codegen-mcp.d.ts.map +1 -1
- package/dist/codegen-mcp.js +368 -0
- package/dist/codegen-mcp.js.map +1 -0
- package/dist/codegen-python.d.ts +13 -1
- package/dist/codegen-python.d.ts.map +1 -1
- package/dist/codegen-python.js +828 -0
- package/dist/codegen-python.js.map +1 -0
- package/dist/codegen-route-tree-intern.d.ts +15 -5
- package/dist/codegen-route-tree-intern.d.ts.map +1 -1
- package/dist/codegen-route-tree-intern.js +221 -0
- package/dist/codegen-route-tree-intern.js.map +1 -0
- package/dist/codegen-rust.d.ts.map +1 -1
- package/dist/codegen-rust.js +1293 -0
- package/dist/codegen-rust.js.map +1 -0
- package/dist/codegen-sanitize.d.ts.map +1 -1
- package/dist/codegen-sanitize.js +56 -0
- package/dist/codegen-sanitize.js.map +1 -0
- package/dist/codegen-schema-naming.d.ts +5 -0
- package/dist/codegen-schema-naming.d.ts.map +1 -1
- package/dist/codegen-schema-naming.js +150 -0
- package/dist/codegen-schema-naming.js.map +1 -0
- package/dist/codegen-sdk-model.d.ts +71 -0
- package/dist/codegen-sdk-model.d.ts.map +1 -0
- package/dist/codegen-sdk-model.js +179 -0
- package/dist/codegen-sdk-model.js.map +1 -0
- package/dist/codegen.d.ts +41 -23
- package/dist/codegen.d.ts.map +1 -1
- package/dist/codegen.js +4610 -0
- package/dist/codegen.js.map +1 -0
- package/dist/context.d.ts +36 -6
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +242 -0
- package/dist/context.js.map +1 -0
- package/dist/cookie-sign.d.ts +16 -2
- package/dist/cookie-sign.d.ts.map +1 -1
- package/dist/cookie-sign.js +104 -0
- package/dist/cookie-sign.js.map +1 -0
- package/dist/cookie.d.ts +12 -0
- package/dist/cookie.d.ts.map +1 -1
- package/dist/cookie.js +138 -0
- package/dist/cookie.js.map +1 -0
- package/dist/cors.d.ts +1 -0
- package/dist/cors.d.ts.map +1 -1
- package/dist/cors.js +87 -0
- package/dist/cors.js.map +1 -0
- package/dist/crypto.d.ts +6 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +38 -0
- package/dist/crypto.js.map +1 -0
- package/dist/csrf.d.ts +19 -0
- package/dist/csrf.d.ts.map +1 -1
- package/dist/csrf.js +79 -0
- package/dist/csrf.js.map +1 -0
- package/dist/curl-logger.d.ts +14 -3
- package/dist/curl-logger.d.ts.map +1 -1
- package/dist/curl-logger.js +199 -0
- package/dist/curl-logger.js.map +1 -0
- package/dist/detect-runtime.js +13 -0
- package/dist/detect-runtime.js.map +1 -0
- package/dist/dict.d.ts +11 -0
- package/dist/dict.d.ts.map +1 -0
- package/dist/dict.js +13 -0
- package/dist/dict.js.map +1 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +44 -0
- package/dist/error.js.map +1 -0
- package/dist/errors.js +39 -0
- package/dist/errors.js.map +1 -0
- package/dist/etag.d.ts +2 -0
- package/dist/etag.d.ts.map +1 -1
- package/dist/etag.js +82 -0
- package/dist/etag.js.map +1 -0
- package/dist/feature-detect.d.ts +25 -0
- package/dist/feature-detect.d.ts.map +1 -0
- package/dist/feature-detect.js +144 -0
- package/dist/feature-detect.js.map +1 -0
- package/dist/feature-load.js +36 -0
- package/dist/feature-load.js.map +1 -0
- package/dist/feature-slots.d.ts +44 -0
- package/dist/feature-slots.d.ts.map +1 -0
- package/dist/feature-slots.js +48 -0
- package/dist/feature-slots.js.map +1 -0
- package/dist/fetch-request.d.ts +10 -0
- package/dist/fetch-request.d.ts.map +1 -0
- package/dist/fetch-request.js +13 -0
- package/dist/fetch-request.js.map +1 -0
- package/dist/gen-process.d.ts +15 -0
- package/dist/gen-process.d.ts.map +1 -0
- package/dist/gen-process.js +43 -0
- package/dist/gen-process.js.map +1 -0
- package/dist/gen-write.d.ts +19 -0
- package/dist/gen-write.d.ts.map +1 -0
- package/dist/gen-write.js +120 -0
- package/dist/gen-write.js.map +1 -0
- package/dist/glob.d.ts +21 -0
- package/dist/glob.d.ts.map +1 -0
- package/dist/glob.js +115 -0
- package/dist/glob.js.map +1 -0
- package/dist/go-type-emitter.d.ts +18 -4
- package/dist/go-type-emitter.d.ts.map +1 -1
- package/dist/go-type-emitter.js +594 -0
- package/dist/go-type-emitter.js.map +1 -0
- package/dist/honey-response.d.ts.map +1 -1
- package/dist/honey-response.js +338 -0
- package/dist/honey-response.js.map +1 -0
- package/dist/i18n-slot.d.ts +8 -0
- package/dist/i18n-slot.d.ts.map +1 -1
- package/dist/i18n-slot.js +14 -0
- package/dist/i18n-slot.js.map +1 -0
- package/dist/i18n.d.ts +3 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +250 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +410 -149
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2324 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +3 -5
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +140 -0
- package/dist/init.js.map +1 -0
- package/dist/input.js +4 -0
- package/dist/input.js.map +1 -0
- package/dist/invalidate-check.d.ts +11 -0
- package/dist/invalidate-check.d.ts.map +1 -1
- package/dist/invalidate-check.js +163 -0
- package/dist/invalidate-check.js.map +1 -0
- package/dist/invoke-user.d.ts +35 -0
- package/dist/invoke-user.d.ts.map +1 -0
- package/dist/invoke-user.js +73 -0
- package/dist/invoke-user.js.map +1 -0
- package/dist/ip-restrict.d.ts +13 -1
- package/dist/ip-restrict.d.ts.map +1 -1
- package/dist/ip-restrict.js +60 -0
- package/dist/ip-restrict.js.map +1 -0
- package/dist/ip.d.ts +39 -0
- package/dist/ip.d.ts.map +1 -0
- package/dist/ip.js +209 -0
- package/dist/ip.js.map +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +113 -0
- package/dist/logger.js.map +1 -0
- package/dist/media-type.d.ts +30 -0
- package/dist/media-type.d.ts.map +1 -0
- package/dist/media-type.js +97 -0
- package/dist/media-type.js.map +1 -0
- package/dist/meta-spec-merge.d.ts +32 -0
- package/dist/meta-spec-merge.d.ts.map +1 -0
- package/dist/meta-spec-merge.js +68 -0
- package/dist/meta-spec-merge.js.map +1 -0
- package/dist/meta-spec.d.ts +16 -3
- package/dist/meta-spec.d.ts.map +1 -1
- package/dist/meta-spec.js +535 -0
- package/dist/meta-spec.js.map +1 -0
- package/dist/middleware.d.ts +23 -6
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +253 -0
- package/dist/middleware.js.map +1 -0
- package/dist/node-request.d.ts +57 -12
- package/dist/node-request.d.ts.map +1 -1
- package/dist/node-request.js +407 -0
- package/dist/node-request.js.map +1 -0
- package/dist/node.d.ts +20 -3
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +396 -0
- package/dist/node.js.map +1 -0
- package/dist/openapi/collect.d.ts +6 -3
- package/dist/openapi/collect.d.ts.map +1 -1
- package/dist/openapi/collect.js +30 -0
- package/dist/openapi/collect.js.map +1 -0
- package/dist/openapi/docs-page.d.ts +42 -0
- package/dist/openapi/docs-page.d.ts.map +1 -0
- package/dist/openapi/docs-page.js +80 -0
- package/dist/openapi/docs-page.js.map +1 -0
- package/dist/openapi/document.d.ts +4 -0
- package/dist/openapi/document.d.ts.map +1 -1
- package/dist/openapi/document.js +785 -0
- package/dist/openapi/document.js.map +1 -0
- package/dist/openapi/json-schema-slot.d.ts +7 -0
- package/dist/openapi/json-schema-slot.d.ts.map +1 -1
- package/dist/openapi/json-schema-slot.js +38 -0
- package/dist/openapi/json-schema-slot.js.map +1 -0
- package/dist/openapi/register.d.ts.map +1 -1
- package/dist/openapi/register.js +20 -0
- package/dist/openapi/register.js.map +1 -0
- package/dist/openapi/scalar.d.ts +3 -1
- package/dist/openapi/scalar.d.ts.map +1 -1
- package/dist/openapi/scalar.js +21 -0
- package/dist/openapi/scalar.js.map +1 -0
- package/dist/openapi/serve.d.ts +9 -0
- package/dist/openapi/serve.d.ts.map +1 -0
- package/dist/openapi/serve.js +36 -0
- package/dist/openapi/serve.js.map +1 -0
- package/dist/openapi/spec-factory.d.ts +30 -1
- package/dist/openapi/spec-factory.d.ts.map +1 -1
- package/dist/openapi/spec-factory.js +52 -0
- package/dist/openapi/spec-factory.js.map +1 -0
- package/dist/openapi/spec.d.ts +14 -5
- package/dist/openapi/spec.d.ts.map +1 -1
- package/dist/openapi/spec.js +50 -0
- package/dist/openapi/spec.js.map +1 -0
- package/dist/openapi/swagger.d.ts +3 -1
- package/dist/openapi/swagger.d.ts.map +1 -1
- package/dist/openapi/swagger.js +22 -0
- package/dist/openapi/swagger.js.map +1 -0
- package/dist/pattern.d.ts +71 -0
- package/dist/pattern.d.ts.map +1 -0
- package/dist/pattern.js +239 -0
- package/dist/pattern.js.map +1 -0
- package/dist/peer.d.ts +17 -0
- package/dist/peer.d.ts.map +1 -0
- package/dist/peer.js +50 -0
- package/dist/peer.js.map +1 -0
- package/dist/plugin.d.ts +67 -16
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +649 -0
- package/dist/plugin.js.map +1 -0
- package/dist/powered-by.d.ts.map +1 -1
- package/dist/powered-by.js +11 -0
- package/dist/powered-by.js.map +1 -0
- package/dist/pretty-json.d.ts.map +1 -1
- package/dist/pretty-json.js +47 -0
- package/dist/pretty-json.js.map +1 -0
- package/dist/producer-stream.d.ts +47 -0
- package/dist/producer-stream.d.ts.map +1 -0
- package/dist/producer-stream.js +267 -0
- package/dist/producer-stream.js.map +1 -0
- package/dist/proxy.d.ts +47 -8
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +274 -0
- package/dist/proxy.js.map +1 -0
- package/dist/python-type-emitter.d.ts +14 -1
- package/dist/python-type-emitter.d.ts.map +1 -1
- package/dist/python-type-emitter.js +157 -0
- package/dist/python-type-emitter.js.map +1 -0
- package/dist/realtime/bus.d.ts +17 -1
- package/dist/realtime/bus.d.ts.map +1 -1
- package/dist/realtime/bus.js +112 -0
- package/dist/realtime/bus.js.map +1 -0
- package/dist/realtime/register.d.ts +3 -0
- package/dist/realtime/register.d.ts.map +1 -0
- package/dist/realtime/register.js +10 -0
- package/dist/realtime/register.js.map +1 -0
- package/dist/realtime/route.d.ts +65 -26
- package/dist/realtime/route.d.ts.map +1 -1
- package/dist/realtime/route.js +72 -0
- package/dist/realtime/route.js.map +1 -0
- package/dist/realtime/server.d.ts +43 -0
- package/dist/realtime/server.d.ts.map +1 -0
- package/dist/realtime/server.js +255 -0
- package/dist/realtime/server.js.map +1 -0
- package/dist/request-id.d.ts +7 -0
- package/dist/request-id.d.ts.map +1 -1
- package/dist/request-id.js +16 -0
- package/dist/request-id.js.map +1 -0
- package/dist/request-limits.d.ts +3 -0
- package/dist/request-limits.d.ts.map +1 -0
- package/dist/request-limits.js +3 -0
- package/dist/request-limits.js.map +1 -0
- package/dist/request-path.d.ts +33 -0
- package/dist/request-path.d.ts.map +1 -0
- package/dist/request-path.js +178 -0
- package/dist/request-path.js.map +1 -0
- package/dist/request-to-curl.d.ts +7 -1
- package/dist/request-to-curl.d.ts.map +1 -1
- package/dist/request-to-curl.js +48 -0
- package/dist/request-to-curl.js.map +1 -0
- package/dist/response.d.ts +25 -2
- package/dist/response.d.ts.map +1 -1
- package/dist/response.js +313 -0
- package/dist/response.js.map +1 -0
- package/dist/rust-type-emitter.d.ts +14 -2
- package/dist/rust-type-emitter.d.ts.map +1 -1
- package/dist/rust-type-emitter.js +463 -0
- package/dist/rust-type-emitter.js.map +1 -0
- package/dist/secure-headers.d.ts.map +1 -1
- package/dist/secure-headers.js +53 -0
- package/dist/secure-headers.js.map +1 -0
- package/dist/serve-register.d.ts +4 -0
- package/dist/serve-register.d.ts.map +1 -1
- package/dist/serve-register.js +9 -0
- package/dist/serve-register.js.map +1 -0
- package/dist/serve-slot.d.ts +3 -0
- package/dist/serve-slot.d.ts.map +1 -1
- package/dist/serve-slot.js +52 -0
- package/dist/serve-slot.js.map +1 -0
- package/dist/serve.d.ts +18 -1
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +157 -0
- package/dist/serve.js.map +1 -0
- package/dist/server-timing.d.ts.map +1 -1
- package/dist/server-timing.js +51 -0
- package/dist/server-timing.js.map +1 -0
- package/dist/static.d.ts +9 -0
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +102 -0
- package/dist/static.js.map +1 -0
- package/dist/telemetry/otel.d.ts +2 -0
- package/dist/telemetry/otel.d.ts.map +1 -1
- package/dist/telemetry/otel.js +135 -0
- package/dist/telemetry/otel.js.map +1 -0
- package/dist/testing.d.ts +12 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +124 -0
- package/dist/testing.js.map +1 -0
- package/dist/timeout.d.ts +6 -0
- package/dist/timeout.d.ts.map +1 -1
- package/dist/timeout.js +36 -0
- package/dist/timeout.js.map +1 -0
- package/dist/tree.d.ts +133 -36
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +437 -0
- package/dist/tree.js.map +1 -0
- package/dist/trust.d.ts +21 -0
- package/dist/trust.d.ts.map +1 -0
- package/dist/trust.js +100 -0
- package/dist/trust.js.map +1 -0
- package/dist/ts-type-emitter.d.ts.map +1 -1
- package/dist/ts-type-emitter.js +150 -0
- package/dist/ts-type-emitter.js.map +1 -0
- package/dist/type-emitter.d.ts +16 -2
- package/dist/type-emitter.d.ts.map +1 -1
- package/dist/type-emitter.js +729 -0
- package/dist/type-emitter.js.map +1 -0
- package/dist/type-extractor.d.ts +8 -4
- package/dist/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor.js +776 -0
- package/dist/type-extractor.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +96 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +14 -2
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +335 -0
- package/dist/validation.js.map +1 -0
- package/dist/with-headers.d.ts +15 -0
- package/dist/with-headers.d.ts.map +1 -0
- package/dist/with-headers.js +45 -0
- package/dist/with-headers.js.map +1 -0
- package/dist/ws/bun.d.ts +11 -5
- package/dist/ws/bun.d.ts.map +1 -1
- package/dist/ws/bun.js +82 -0
- package/dist/ws/bun.js.map +1 -0
- package/dist/ws/cloudflare.d.ts +25 -3
- package/dist/ws/cloudflare.d.ts.map +1 -1
- package/dist/ws/cloudflare.js +117 -0
- package/dist/ws/cloudflare.js.map +1 -0
- package/dist/ws/deno.d.ts +4 -4
- package/dist/ws/deno.d.ts.map +1 -1
- package/dist/ws/deno.js +133 -0
- package/dist/ws/deno.js.map +1 -0
- package/dist/ws/node.d.ts +20 -3
- package/dist/ws/node.d.ts.map +1 -1
- package/dist/ws/node.js +173 -0
- package/dist/ws/node.js.map +1 -0
- package/dist/ws/session.d.ts +11 -0
- package/dist/ws/session.d.ts.map +1 -0
- package/dist/ws/session.js +60 -0
- package/dist/ws/session.js.map +1 -0
- package/dist/ws/shared.d.ts +65 -0
- package/dist/ws/shared.d.ts.map +1 -0
- package/dist/ws/shared.js +103 -0
- package/dist/ws/shared.js.map +1 -0
- package/dist/ws-origin.d.ts +20 -0
- package/dist/ws-origin.d.ts.map +1 -0
- package/dist/ws-origin.js +41 -0
- package/dist/ws-origin.js.map +1 -0
- package/dist/yaml.d.ts +15 -1
- package/dist/yaml.d.ts.map +1 -1
- package/dist/yaml.js +101 -0
- package/dist/yaml.js.map +1 -0
- package/docs/invalidate-spec.md +13 -1
- package/docs/meta-spec.md +36 -12
- package/docs/packaging.md +43 -24
- package/docs/regression-matrix/README.md +32 -0
- package/docs/regression-matrix/review.md +44 -0
- package/docs/regression-matrix/ws1-3.md +97 -0
- package/docs/regression-matrix/ws4-8.md +107 -0
- package/docs/regression-matrix/ws9-12.md +266 -0
- package/docs/sdk.md +102 -52
- package/package.json +183 -52
- package/src/accepts.ts +91 -33
- package/src/body-kind.ts +67 -0
- package/src/body-limit.ts +102 -87
- package/src/build/index.ts +104 -54
- package/src/cli-args.ts +123 -0
- package/src/cli-go/auth.go +12 -1
- package/src/cli-go/config.go +29 -2
- package/src/cli-go/errors.go +28 -10
- package/src/cli-go/multipart.go +51 -27
- package/src/cli-go/output.go +58 -4
- package/src/cli-go/root.go +1 -1
- package/src/cli-go/version.go +2 -2
- package/src/cli.ts +154 -148
- package/src/client/error.ts +56 -1
- package/src/client/http.ts +479 -256
- package/src/client/index.ts +55 -17
- package/src/client/path.ts +169 -0
- package/src/client/redirect-policy.ts +19 -0
- package/src/client/sdk.ts +180 -101
- package/src/client/sse.ts +92 -66
- package/src/client/ws.ts +67 -31
- package/src/client-go/errors.go +41 -12
- package/src/client-go/export.go +44 -0
- package/src/client-go/invalidation.go +52 -54
- package/src/client-go/nullable.go +62 -0
- package/src/client-go/realtime.go +147 -110
- package/src/client-go/runtime.go +646 -88
- package/src/client-go/sse.go +104 -94
- package/src/client-go/transport.go +67 -27
- package/src/client-go/ws.go +49 -25
- package/src/client-info.ts +79 -0
- package/src/client-mcp/server.ts +133 -3
- package/src/client-python/_invalidation.py +207 -291
- package/src/client-python/_realtime.py +63 -40
- package/src/client-python/_runtime.py +501 -119
- package/src/client-python/_sse.py +130 -74
- package/src/client-python/_transport.py +37 -9
- package/src/client-python/_ws.py +50 -22
- package/src/client-rust/errors.rs +21 -1
- package/src/client-rust/invalidation.rs +202 -231
- package/src/client-rust/invalidation_sync.rs +16 -229
- package/src/client-rust/nullable.rs +17 -0
- package/src/client-rust/realtime.rs +217 -217
- package/src/client-rust/runtime.rs +602 -177
- package/src/client-rust/runtime_sync.rs +169 -145
- package/src/client-rust/sse.rs +142 -121
- package/src/client-rust/ws.rs +61 -37
- package/src/codegen-go-cli.ts +607 -728
- package/src/codegen-go.ts +710 -770
- package/src/codegen-ir.ts +381 -75
- package/src/codegen-lang.ts +517 -0
- package/src/codegen-load.ts +150 -0
- package/src/codegen-mcp.ts +207 -108
- package/src/codegen-python.ts +684 -816
- package/src/codegen-route-tree-intern.ts +51 -25
- package/src/codegen-rust.ts +946 -1240
- package/src/codegen-sanitize.ts +0 -4
- package/src/codegen-schema-naming.ts +19 -6
- package/src/codegen-sdk-model.ts +228 -0
- package/src/codegen.ts +1488 -1140
- package/src/context.ts +130 -11
- package/src/cookie-sign.ts +85 -16
- package/src/cookie.ts +66 -11
- package/src/cors.ts +55 -54
- package/src/crypto.ts +27 -5
- package/src/csrf.ts +57 -25
- package/src/curl-logger.ts +155 -114
- package/src/dict.ts +12 -0
- package/src/error.ts +4 -2
- package/src/etag.ts +58 -34
- package/src/feature-detect.ts +147 -0
- package/src/feature-slots.ts +70 -0
- package/src/fetch-request.ts +13 -0
- package/src/gen-process.ts +42 -0
- package/src/gen-write.ts +127 -0
- package/src/glob.ts +109 -0
- package/src/go-type-emitter.ts +406 -155
- package/src/honey-response.ts +36 -9
- package/src/i18n-slot.ts +10 -0
- package/src/i18n.ts +98 -23
- package/src/index.ts +1893 -1761
- package/src/init.ts +40 -28
- package/src/invalidate-check.ts +42 -4
- package/src/invoke-user.ts +95 -0
- package/src/ip-restrict.ts +47 -161
- package/src/ip.ts +194 -0
- package/src/logger.ts +65 -36
- package/src/media-type.ts +104 -0
- package/src/meta-spec-merge.ts +80 -0
- package/src/meta-spec.ts +0 -0
- package/src/middleware.ts +112 -12
- package/src/node-request.ts +242 -52
- package/src/node.ts +318 -75
- package/src/openapi/collect.ts +19 -44
- package/src/openapi/docs-page.ts +89 -0
- package/src/openapi/document.ts +503 -224
- package/src/openapi/json-schema-slot.ts +40 -0
- package/src/openapi/register.ts +7 -2
- package/src/openapi/scalar.ts +11 -10
- package/src/openapi/serve.ts +39 -0
- package/src/openapi/spec-factory.ts +50 -1
- package/src/openapi/spec.ts +53 -30
- package/src/openapi/swagger.ts +12 -11
- package/src/pattern.ts +245 -0
- package/src/peer.ts +53 -0
- package/src/plugin.ts +270 -185
- package/src/powered-by.ts +2 -2
- package/src/pretty-json.ts +25 -9
- package/src/producer-stream.ts +296 -0
- package/src/proxy.ts +271 -55
- package/src/python-type-emitter.ts +68 -56
- package/src/realtime/bus.ts +56 -9
- package/src/realtime/register.ts +13 -0
- package/src/realtime/route.ts +129 -80
- package/src/realtime/server.ts +298 -0
- package/src/request-id.ts +13 -3
- package/src/request-limits.ts +2 -0
- package/src/request-path.ts +165 -0
- package/src/request-to-curl.ts +28 -7
- package/src/response.ts +143 -103
- package/src/rust-type-emitter.ts +265 -170
- package/src/secure-headers.ts +8 -4
- package/src/serve-register.ts +4 -0
- package/src/serve-slot.ts +38 -0
- package/src/serve.ts +113 -25
- package/src/server-timing.ts +11 -7
- package/src/static.ts +85 -32
- package/src/telemetry/otel.ts +29 -7
- package/src/testing.ts +76 -14
- package/src/timeout.ts +15 -7
- package/src/tree.ts +405 -333
- package/src/trust.ts +117 -0
- package/src/ts-type-emitter.ts +18 -12
- package/src/type-emitter.ts +227 -89
- package/src/type-extractor.ts +562 -424
- package/src/types.ts +8 -0
- package/src/validation.ts +221 -96
- package/src/with-headers.ts +45 -0
- package/src/ws/bun.ts +53 -15
- package/src/ws/cloudflare.ts +81 -19
- package/src/ws/deno.ts +124 -36
- package/src/ws/node.ts +173 -79
- package/src/ws/session.ts +73 -0
- package/src/ws/shared.ts +140 -0
- package/src/ws-origin.ts +53 -0
- package/src/yaml.ts +45 -22
- package/dist/client-mcp/server.d.ts +0 -10
- package/dist/client-mcp/server.d.ts.map +0 -1
- package/dist/client-mcp/types.d.ts +0 -16
- package/dist/client-mcp/types.d.ts.map +0 -1
- package/dist/cloudflare/realtime.d.ts +0 -30
- package/dist/cloudflare/realtime.d.ts.map +0 -1
- package/dist/realtime/buffer.d.ts +0 -18
- package/dist/realtime/buffer.d.ts.map +0 -1
- package/dist/realtime/longpoll.d.ts +0 -23
- package/dist/realtime/longpoll.d.ts.map +0 -1
- package/dist/realtime/protocol.d.ts +0 -50
- package/dist/realtime/protocol.d.ts.map +0 -1
- package/dist/realtime/runtime.d.ts +0 -74
- package/dist/realtime/runtime.d.ts.map +0 -1
- package/src/cloudflare/realtime.ts +0 -234
- package/src/realtime/buffer.ts +0 -101
- package/src/realtime/longpoll.ts +0 -148
- package/src/realtime/protocol.ts +0 -128
- package/src/realtime/runtime.ts +0 -427
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/* Code generated by honey. DO NOT EDIT. */
|
|
2
2
|
|
|
3
3
|
use crate::errors::Error;
|
|
4
|
+
use crate::sse::SseParser;
|
|
4
5
|
use bytes::Bytes;
|
|
5
6
|
use serde::{de::DeserializeOwned, Serialize};
|
|
6
7
|
use std::collections::HashMap;
|
|
7
8
|
use std::collections::VecDeque;
|
|
8
9
|
use std::marker::PhantomData;
|
|
9
10
|
use std::pin::Pin;
|
|
11
|
+
use std::time::Duration;
|
|
10
12
|
|
|
11
13
|
/// TransportKind tags which transport a connection was opened with.
|
|
12
14
|
/// The behaviour-bearing abstraction is the [`Transport`] trait.
|
|
@@ -51,6 +53,12 @@ impl std::fmt::Display for RealtimeError {
|
|
|
51
53
|
impl std::error::Error for RealtimeError {}
|
|
52
54
|
|
|
53
55
|
/// ResumableConnectionOpts configures reconnect behaviour and auth.
|
|
56
|
+
///
|
|
57
|
+
/// `max_reconnect_attempts` caps consecutive failed reconnects (default 5; 0
|
|
58
|
+
/// means unlimited). Reconnects back off exponentially from
|
|
59
|
+
/// `reconnect_delay_ms` (default 1000) up to 30 s, with jitter. `headers` go
|
|
60
|
+
/// on every transport request; the generated SDK fills in config headers and
|
|
61
|
+
/// auth. `http_client` lets SSE / long-poll share the SDK's client.
|
|
54
62
|
#[derive(Debug, Clone, Default)]
|
|
55
63
|
pub struct ResumableConnectionOpts {
|
|
56
64
|
pub reconnect_token: Option<String>,
|
|
@@ -59,6 +67,7 @@ pub struct ResumableConnectionOpts {
|
|
|
59
67
|
pub reconnect_delay_ms: Option<u64>,
|
|
60
68
|
pub last_event_id: Option<String>,
|
|
61
69
|
pub headers: HashMap<String, String>,
|
|
70
|
+
pub http_client: Option<reqwest::Client>,
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
/// TransportOpts is handed to each `Transport::connect`.
|
|
@@ -74,37 +83,35 @@ pub struct TransportOpts {
|
|
|
74
83
|
pub reconnect_delay_ms: Option<u64>,
|
|
75
84
|
}
|
|
76
85
|
|
|
86
|
+
const MAX_RECONNECT_DELAY: Duration = Duration::from_secs(30);
|
|
87
|
+
const OPEN_TIMEOUT: Duration = Duration::from_secs(30);
|
|
88
|
+
const POLL_TIMEOUT: Duration = Duration::from_secs(60);
|
|
89
|
+
|
|
77
90
|
type WsStream = tokio_tungstenite::WebSocketStream<
|
|
78
91
|
tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>,
|
|
79
92
|
>;
|
|
80
93
|
|
|
81
94
|
type ByteStream = Pin<Box<dyn futures_util::Stream<Item = Result<Bytes, reqwest::Error>> + Send>>;
|
|
82
95
|
|
|
83
|
-
/// SseState holds mutable state for an active SSE
|
|
96
|
+
/// SseState holds mutable state for an active SSE connection.
|
|
84
97
|
pub struct SseState {
|
|
85
98
|
pub byte_stream: ByteStream,
|
|
86
|
-
pub buf: Vec<u8>,
|
|
87
99
|
pub last_event_id: Option<String>,
|
|
88
100
|
pub retry_hint_ms: u64,
|
|
89
|
-
|
|
101
|
+
parser: SseParser,
|
|
102
|
+
pending: VecDeque<crate::sse::SseEvent>,
|
|
90
103
|
http_client: reqwest::Client,
|
|
91
104
|
url: String,
|
|
92
105
|
extra_headers: HashMap<String, String>,
|
|
93
|
-
max_reconnect_attempts: u32,
|
|
94
|
-
reconnect_delay_ms: u64,
|
|
95
|
-
reconnect_attempts: u32,
|
|
96
106
|
}
|
|
97
107
|
|
|
98
|
-
/// LongpollState holds mutable state for a long-poll
|
|
108
|
+
/// LongpollState holds mutable state for a long-poll connection.
|
|
99
109
|
pub struct LongpollState {
|
|
100
110
|
pub client: reqwest::Client,
|
|
101
111
|
pub url: String,
|
|
102
112
|
pub cursor: Option<String>,
|
|
103
113
|
pub pending_events: VecDeque<serde_json::Value>,
|
|
104
114
|
pub headers: HashMap<String, String>,
|
|
105
|
-
max_reconnect_attempts: u32,
|
|
106
|
-
reconnect_delay_ms: u64,
|
|
107
|
-
reconnect_attempts: u32,
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
/// TransportConn is the live per-transport connection.
|
|
@@ -132,6 +139,15 @@ pub trait Transport: Send + Sync + 'static {
|
|
|
132
139
|
) -> Result<Box<dyn TransportConn>, RealtimeError>;
|
|
133
140
|
}
|
|
134
141
|
|
|
142
|
+
/// Payloads that are not JSON arrive as a JSON string instead of tearing the connection down.
|
|
143
|
+
fn decode_payload(text: &str) -> serde_json::Value {
|
|
144
|
+
serde_json::from_str(text).unwrap_or_else(|_| serde_json::Value::String(text.to_string()))
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
fn connect_err(e: impl std::fmt::Display) -> RealtimeError {
|
|
148
|
+
RealtimeError::Connect(Error::Other(e.to_string()))
|
|
149
|
+
}
|
|
150
|
+
|
|
135
151
|
/* ------------------------------------------------------------------ */
|
|
136
152
|
/* WS adapter */
|
|
137
153
|
/* ------------------------------------------------------------------ */
|
|
@@ -160,19 +176,13 @@ impl Transport for WsTransport {
|
|
|
160
176
|
opts: &TransportOpts,
|
|
161
177
|
) -> Result<Box<dyn TransportConn>, RealtimeError> {
|
|
162
178
|
use tokio_tungstenite::tungstenite::client::IntoClientRequest;
|
|
163
|
-
let ws_url = url
|
|
164
|
-
let mut req = ws_url
|
|
165
|
-
.as_str()
|
|
166
|
-
.into_client_request()
|
|
167
|
-
.map_err(|e| RealtimeError::Connect(Error::Other(e.to_string())))?;
|
|
179
|
+
let ws_url = crate::runtime::to_ws_url(url);
|
|
180
|
+
let mut req = ws_url.as_str().into_client_request().map_err(connect_err)?;
|
|
168
181
|
if let Some(ref protos) = opts.protocols {
|
|
169
182
|
if !protos.is_empty() {
|
|
170
183
|
req.headers_mut().insert(
|
|
171
184
|
"Sec-WebSocket-Protocol",
|
|
172
|
-
protos
|
|
173
|
-
.join(", ")
|
|
174
|
-
.parse()
|
|
175
|
-
.map_err(|_| RealtimeError::Connect(Error::Other("invalid protocol header".into())))?,
|
|
185
|
+
protos.join(", ").parse().map_err(|_| connect_err("invalid protocol header"))?,
|
|
176
186
|
);
|
|
177
187
|
}
|
|
178
188
|
}
|
|
@@ -184,9 +194,7 @@ impl Transport for WsTransport {
|
|
|
184
194
|
req.headers_mut().insert(name, val);
|
|
185
195
|
}
|
|
186
196
|
}
|
|
187
|
-
let (stream, _) = tokio_tungstenite::connect_async(req)
|
|
188
|
-
.await
|
|
189
|
-
.map_err(|e| RealtimeError::Connect(Error::Other(e.to_string())))?;
|
|
197
|
+
let (stream, _) = tokio_tungstenite::connect_async(req).await.map_err(connect_err)?;
|
|
190
198
|
Ok(Box::new(WsConn { stream: Box::new(stream) }))
|
|
191
199
|
}
|
|
192
200
|
}
|
|
@@ -199,10 +207,9 @@ impl TransportConn for WsConn {
|
|
|
199
207
|
async fn send_json(&mut self, value: serde_json::Value) -> Result<(), RealtimeError> {
|
|
200
208
|
use futures_util::SinkExt;
|
|
201
209
|
use tokio_tungstenite::tungstenite::Message;
|
|
202
|
-
let encoded = serde_json::
|
|
203
|
-
.map_err(|e| RealtimeError::Send(Error::Json(e)))?;
|
|
210
|
+
let encoded = serde_json::to_string(&value).map_err(|e| RealtimeError::Send(Error::Json(e)))?;
|
|
204
211
|
self.stream
|
|
205
|
-
.send(Message::Text(
|
|
212
|
+
.send(Message::Text(encoded))
|
|
206
213
|
.await
|
|
207
214
|
.map_err(|e| RealtimeError::Send(Error::Other(e.to_string())))
|
|
208
215
|
}
|
|
@@ -213,15 +220,10 @@ impl TransportConn for WsConn {
|
|
|
213
220
|
match self.stream.next().await {
|
|
214
221
|
None => return Err(RealtimeError::Closed),
|
|
215
222
|
Some(Err(e)) => return Err(RealtimeError::Recv(Error::Other(e.to_string()))),
|
|
216
|
-
Some(Ok(Message::Text(t))) =>
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
Some(Ok(Message::Binary(b))) => {
|
|
221
|
-
return serde_json::from_slice(&b)
|
|
222
|
-
.map_err(|e| RealtimeError::Recv(Error::Json(e)));
|
|
223
|
-
}
|
|
224
|
-
Some(Ok(_)) => continue, /* ping/pong/close — skip */
|
|
223
|
+
Some(Ok(Message::Text(t))) => return Ok(decode_payload(&t)),
|
|
224
|
+
Some(Ok(Message::Binary(b))) => return Ok(decode_payload(&String::from_utf8_lossy(&b))),
|
|
225
|
+
Some(Ok(Message::Close(_))) => return Err(RealtimeError::Closed),
|
|
226
|
+
Some(Ok(_)) => continue, /* ping/pong — skip */
|
|
225
227
|
}
|
|
226
228
|
}
|
|
227
229
|
}
|
|
@@ -249,10 +251,17 @@ pub struct SseTransport {
|
|
|
249
251
|
}
|
|
250
252
|
|
|
251
253
|
/// SseConn is the live SSE connection returned by [`SseTransport::connect`].
|
|
254
|
+
/// A dropped or ended stream is reported as an error; ResumableConnection reconnects.
|
|
252
255
|
pub struct SseConn {
|
|
253
256
|
state: SseState,
|
|
254
257
|
}
|
|
255
258
|
|
|
259
|
+
fn pick_client(own: &Option<reqwest::Client>, opts: &TransportOpts) -> reqwest::Client {
|
|
260
|
+
own.clone()
|
|
261
|
+
.or_else(|| opts.http_client.clone())
|
|
262
|
+
.unwrap_or_else(crate::runtime::default_http_client)
|
|
263
|
+
}
|
|
264
|
+
|
|
256
265
|
#[async_trait::async_trait]
|
|
257
266
|
impl Transport for SseTransport {
|
|
258
267
|
fn name(&self) -> &'static str {
|
|
@@ -266,14 +275,8 @@ impl Transport for SseTransport {
|
|
|
266
275
|
url: &str,
|
|
267
276
|
opts: &TransportOpts,
|
|
268
277
|
) -> Result<Box<dyn TransportConn>, RealtimeError> {
|
|
269
|
-
let client = self
|
|
270
|
-
|
|
271
|
-
.clone()
|
|
272
|
-
.or_else(|| opts.http_client.clone())
|
|
273
|
-
.unwrap_or_else(reqwest::Client::new);
|
|
274
|
-
let state = build_sse_state(url.to_string(), client, opts)
|
|
275
|
-
.await
|
|
276
|
-
.map_err(|e| RealtimeError::Connect(Error::Other(e.to_string())))?;
|
|
278
|
+
let client = pick_client(&self.http_client, opts);
|
|
279
|
+
let state = build_sse_state(url.to_string(), client, opts).await?;
|
|
277
280
|
Ok(Box::new(SseConn { state }))
|
|
278
281
|
}
|
|
279
282
|
}
|
|
@@ -284,75 +287,36 @@ impl TransportConn for SseConn {
|
|
|
284
287
|
TransportKind::Sse
|
|
285
288
|
}
|
|
286
289
|
async fn send_json(&mut self, value: serde_json::Value) -> Result<(), RealtimeError> {
|
|
287
|
-
/* SSE is server → client; send POSTs back to the endpoint. */
|
|
288
|
-
self.state
|
|
289
|
-
|
|
290
|
-
.
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
290
|
+
/* SSE is server → client; send POSTs back to the endpoint with the same headers. */
|
|
291
|
+
let mut req = self.state.http_client.post(self.state.url.as_str()).json(&value);
|
|
292
|
+
for (k, v) in &self.state.extra_headers {
|
|
293
|
+
req = req.header(k.as_str(), v.as_str());
|
|
294
|
+
}
|
|
295
|
+
let resp = req.send().await.map_err(|e| RealtimeError::Send(Error::Other(e.to_string())))?;
|
|
296
|
+
if !resp.status().is_success() {
|
|
297
|
+
return Err(RealtimeError::Send(Error::Other(format!("status {}", resp.status()))));
|
|
298
|
+
}
|
|
295
299
|
Ok(())
|
|
296
300
|
}
|
|
297
301
|
async fn recv_json(&mut self) -> Result<serde_json::Value, RealtimeError> {
|
|
298
|
-
use crate::sse::{find_double_newline, parse_sse_block};
|
|
299
302
|
use futures_util::StreamExt;
|
|
300
303
|
loop {
|
|
301
|
-
if let Some(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
let block_str = String::from_utf8_lossy(&block);
|
|
305
|
-
let trimmed = block_str.trim();
|
|
306
|
-
if !trimmed.is_empty() {
|
|
307
|
-
if let Some(ev) = parse_sse_block(trimmed) {
|
|
308
|
-
if !ev.id.is_empty() {
|
|
309
|
-
self.state.last_event_id = Some(ev.id.clone());
|
|
310
|
-
}
|
|
311
|
-
if ev.retry > 0 {
|
|
312
|
-
self.state.retry_hint_ms = ev.retry as u64;
|
|
313
|
-
}
|
|
314
|
-
return serde_json::from_str(&ev.data)
|
|
315
|
-
.map_err(|e| RealtimeError::Recv(Error::Json(e)));
|
|
316
|
-
}
|
|
304
|
+
if let Some(ev) = self.state.pending.pop_front() {
|
|
305
|
+
if !ev.id.is_empty() {
|
|
306
|
+
self.state.last_event_id = Some(ev.id.clone());
|
|
317
307
|
}
|
|
318
|
-
|
|
308
|
+
if ev.retry > 0 {
|
|
309
|
+
self.state.retry_hint_ms = (ev.retry as u64).min(MAX_RECONNECT_DELAY.as_millis() as u64);
|
|
310
|
+
}
|
|
311
|
+
return Ok(decode_payload(&ev.data));
|
|
319
312
|
}
|
|
320
313
|
match self.state.byte_stream.next().await {
|
|
321
314
|
Some(Ok(bytes)) => {
|
|
322
|
-
self.state.
|
|
323
|
-
|
|
324
|
-
Some(Err(e)) => {
|
|
325
|
-
return Err(RealtimeError::Recv(Error::Other(e.to_string())));
|
|
326
|
-
}
|
|
327
|
-
None => {
|
|
328
|
-
/* stream ended — attempt transport-level reconnect */
|
|
329
|
-
self.state.reconnect_attempts += 1;
|
|
330
|
-
if self.state.reconnect_attempts >= self.state.max_reconnect_attempts {
|
|
331
|
-
return Err(RealtimeError::Closed);
|
|
332
|
-
}
|
|
333
|
-
let delay_ms = if self.state.retry_hint_ms > 0 {
|
|
334
|
-
self.state.retry_hint_ms
|
|
335
|
-
} else {
|
|
336
|
-
self.state.reconnect_delay_ms
|
|
337
|
-
};
|
|
338
|
-
tokio::time::sleep(tokio::time::Duration::from_millis(delay_ms)).await;
|
|
339
|
-
let reopen_opts = TransportOpts {
|
|
340
|
-
last_event_id: self.state.last_event_id.clone(),
|
|
341
|
-
headers: self.state.extra_headers.clone(),
|
|
342
|
-
max_reconnect_attempts: Some(self.state.max_reconnect_attempts),
|
|
343
|
-
reconnect_delay_ms: Some(self.state.reconnect_delay_ms),
|
|
344
|
-
..Default::default()
|
|
345
|
-
};
|
|
346
|
-
let new_state = build_sse_state(
|
|
347
|
-
self.state.url.clone(),
|
|
348
|
-
self.state.http_client.clone(),
|
|
349
|
-
&reopen_opts,
|
|
350
|
-
)
|
|
351
|
-
.await
|
|
352
|
-
.map_err(|e| RealtimeError::Connect(Error::Other(e.to_string())))?;
|
|
353
|
-
self.state.byte_stream = new_state.byte_stream;
|
|
354
|
-
self.state.buf.clear();
|
|
315
|
+
let events = self.state.parser.feed(&bytes).map_err(RealtimeError::Recv)?;
|
|
316
|
+
self.state.pending.extend(events);
|
|
355
317
|
}
|
|
318
|
+
Some(Err(e)) => return Err(RealtimeError::Recv(Error::Other(e.to_string()))),
|
|
319
|
+
None => return Err(RealtimeError::Closed),
|
|
356
320
|
}
|
|
357
321
|
}
|
|
358
322
|
}
|
|
@@ -390,84 +354,83 @@ impl Transport for LongpollTransport {
|
|
|
390
354
|
url: &str,
|
|
391
355
|
opts: &TransportOpts,
|
|
392
356
|
) -> Result<Box<dyn TransportConn>, RealtimeError> {
|
|
393
|
-
let client = self
|
|
394
|
-
.http_client
|
|
395
|
-
.clone()
|
|
396
|
-
.or_else(|| opts.http_client.clone())
|
|
397
|
-
.unwrap_or_else(reqwest::Client::new);
|
|
398
357
|
let state = LongpollState {
|
|
399
|
-
client,
|
|
358
|
+
client: pick_client(&self.http_client, opts),
|
|
400
359
|
url: url.to_string(),
|
|
401
360
|
cursor: None,
|
|
402
361
|
pending_events: VecDeque::new(),
|
|
403
362
|
headers: opts.headers.clone(),
|
|
404
|
-
max_reconnect_attempts: opts.max_reconnect_attempts.unwrap_or(5),
|
|
405
|
-
reconnect_delay_ms: opts.reconnect_delay_ms.unwrap_or(1000),
|
|
406
|
-
reconnect_attempts: 0,
|
|
407
363
|
};
|
|
408
364
|
Ok(Box::new(LongpollConn { state }))
|
|
409
365
|
}
|
|
410
366
|
}
|
|
411
367
|
|
|
368
|
+
fn with_query(url: &str, key: &str, value: &str) -> String {
|
|
369
|
+
let sep = if url.contains('?') { '&' } else { '?' };
|
|
370
|
+
format!(
|
|
371
|
+
"{}{}{}={}",
|
|
372
|
+
url,
|
|
373
|
+
sep,
|
|
374
|
+
crate::runtime::escape_query(key),
|
|
375
|
+
crate::runtime::escape_query(value)
|
|
376
|
+
)
|
|
377
|
+
}
|
|
378
|
+
|
|
412
379
|
#[async_trait::async_trait]
|
|
413
380
|
impl TransportConn for LongpollConn {
|
|
414
381
|
fn kind(&self) -> TransportKind {
|
|
415
382
|
TransportKind::Longpoll
|
|
416
383
|
}
|
|
417
384
|
async fn send_json(&mut self, value: serde_json::Value) -> Result<(), RealtimeError> {
|
|
418
|
-
self.state
|
|
419
|
-
|
|
420
|
-
.
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
385
|
+
let mut req = self.state.client.post(self.state.url.as_str()).json(&value);
|
|
386
|
+
for (k, v) in &self.state.headers {
|
|
387
|
+
req = req.header(k.as_str(), v.as_str());
|
|
388
|
+
}
|
|
389
|
+
let resp = req.send().await.map_err(|e| RealtimeError::Send(Error::Other(e.to_string())))?;
|
|
390
|
+
if !resp.status().is_success() {
|
|
391
|
+
return Err(RealtimeError::Send(Error::Other(format!("status {}", resp.status()))));
|
|
392
|
+
}
|
|
425
393
|
Ok(())
|
|
426
394
|
}
|
|
395
|
+
/// recv_json returns the next queued event, polling when the queue is empty.
|
|
396
|
+
/// A failed or non-2xx poll is returned as an error (ResumableConnection backs off).
|
|
427
397
|
async fn recv_json(&mut self) -> Result<serde_json::Value, RealtimeError> {
|
|
428
398
|
loop {
|
|
429
399
|
if let Some(ev) = self.state.pending_events.pop_front() {
|
|
430
400
|
return Ok(ev);
|
|
431
401
|
}
|
|
432
402
|
let request_url = match &self.state.cursor {
|
|
433
|
-
Some(c) =>
|
|
403
|
+
Some(c) => with_query(&self.state.url, "cursor", c),
|
|
434
404
|
None => self.state.url.clone(),
|
|
435
405
|
};
|
|
436
|
-
let mut req = self.state.client.get(request_url.as_str());
|
|
406
|
+
let mut req = self.state.client.get(request_url.as_str()).timeout(POLL_TIMEOUT);
|
|
437
407
|
for (k, v) in &self.state.headers {
|
|
438
408
|
req = req.header(k.as_str(), v.as_str());
|
|
439
409
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
struct PollResponse {
|
|
459
|
-
#[serde(default)]
|
|
460
|
-
events: Vec<serde_json::Value>,
|
|
461
|
-
cursor: Option<String>,
|
|
410
|
+
let resp = req.send().await.map_err(|e| RealtimeError::Recv(Error::Other(e.to_string())))?;
|
|
411
|
+
if !resp.status().is_success() {
|
|
412
|
+
return Err(RealtimeError::Recv(Error::Other(format!(
|
|
413
|
+
"longpoll status {}",
|
|
414
|
+
resp.status()
|
|
415
|
+
))));
|
|
416
|
+
}
|
|
417
|
+
let bytes = resp.bytes().await.map_err(|e| RealtimeError::Recv(Error::Other(e.to_string())))?;
|
|
418
|
+
if bytes.is_empty() {
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
match serde_json::from_slice::<serde_json::Value>(&bytes)
|
|
422
|
+
.map_err(|e| RealtimeError::Recv(Error::Json(e)))?
|
|
423
|
+
{
|
|
424
|
+
serde_json::Value::Array(events) => self.state.pending_events.extend(events),
|
|
425
|
+
serde_json::Value::Object(mut obj) => {
|
|
426
|
+
if let Some(c) = obj.get("cursor").and_then(|c| c.as_str()) {
|
|
427
|
+
self.state.cursor = Some(c.to_string());
|
|
462
428
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
.map_err(|e| RealtimeError::Recv(Error::Json(e)))?;
|
|
466
|
-
self.state.cursor = parsed.cursor;
|
|
467
|
-
for ev in parsed.events {
|
|
468
|
-
self.state.pending_events.push_back(ev);
|
|
429
|
+
if let Some(serde_json::Value::Array(events)) = obj.remove("events") {
|
|
430
|
+
self.state.pending_events.extend(events);
|
|
469
431
|
}
|
|
470
432
|
}
|
|
433
|
+
other => self.state.pending_events.push_back(other),
|
|
471
434
|
}
|
|
472
435
|
}
|
|
473
436
|
}
|
|
@@ -483,6 +446,10 @@ impl TransportConn for LongpollConn {
|
|
|
483
446
|
|
|
484
447
|
/// ResumableConnection is a typed, self-reconnecting realtime channel.
|
|
485
448
|
/// Send/Recv type parameters encode the message types flowing in each direction.
|
|
449
|
+
///
|
|
450
|
+
/// `recv` is cancel-safe with respect to the connection: if a `recv` future is
|
|
451
|
+
/// dropped mid-reconnect (`select!`, `timeout`), the next `recv` or `send`
|
|
452
|
+
/// reopens the chain instead of reporting the connection closed.
|
|
486
453
|
pub struct ResumableConnection<Send, Recv> {
|
|
487
454
|
state: ConnectionState,
|
|
488
455
|
url: String,
|
|
@@ -492,6 +459,7 @@ pub struct ResumableConnection<Send, Recv> {
|
|
|
492
459
|
conn: Option<Box<dyn TransportConn>>,
|
|
493
460
|
proven_index: Option<usize>,
|
|
494
461
|
reconnect_attempts: u32,
|
|
462
|
+
closed: bool,
|
|
495
463
|
_send: PhantomData<Send>,
|
|
496
464
|
_recv: PhantomData<Recv>,
|
|
497
465
|
}
|
|
@@ -509,16 +477,14 @@ where
|
|
|
509
477
|
transports: Vec<Box<dyn Transport>>,
|
|
510
478
|
) -> Result<Self, RealtimeError> {
|
|
511
479
|
if transports.is_empty() {
|
|
512
|
-
return Err(RealtimeError::Connect(Error::Other(
|
|
513
|
-
"no transports configured".into(),
|
|
514
|
-
)));
|
|
480
|
+
return Err(RealtimeError::Connect(Error::Other("no transports configured".into())));
|
|
515
481
|
}
|
|
516
482
|
let transport_opts = TransportOpts {
|
|
517
483
|
reconnect_token: opts.reconnect_token.clone(),
|
|
518
484
|
protocols: opts.protocols.clone(),
|
|
519
485
|
last_event_id: opts.last_event_id.clone(),
|
|
520
486
|
headers: opts.headers.clone(),
|
|
521
|
-
http_client:
|
|
487
|
+
http_client: opts.http_client.clone(),
|
|
522
488
|
max_reconnect_attempts: opts.max_reconnect_attempts,
|
|
523
489
|
reconnect_delay_ms: opts.reconnect_delay_ms,
|
|
524
490
|
};
|
|
@@ -531,6 +497,7 @@ where
|
|
|
531
497
|
conn: None,
|
|
532
498
|
proven_index: None,
|
|
533
499
|
reconnect_attempts: 0,
|
|
500
|
+
closed: false,
|
|
534
501
|
_send: PhantomData,
|
|
535
502
|
_recv: PhantomData,
|
|
536
503
|
};
|
|
@@ -560,9 +527,7 @@ where
|
|
|
560
527
|
|
|
561
528
|
/// proven_transport returns the kind of the last successfully-opened transport.
|
|
562
529
|
pub fn proven_transport(&self) -> Option<TransportKind> {
|
|
563
|
-
self.proven_index
|
|
564
|
-
.and_then(|i| self.transports.get(i))
|
|
565
|
-
.map(|t| t.kind())
|
|
530
|
+
self.proven_index.and_then(|i| self.transports.get(i)).map(|t| t.kind())
|
|
566
531
|
}
|
|
567
532
|
|
|
568
533
|
/// current_transport returns the kind of the currently-active transport.
|
|
@@ -570,58 +535,52 @@ where
|
|
|
570
535
|
self.conn.as_ref().map(|c| c.kind())
|
|
571
536
|
}
|
|
572
537
|
|
|
573
|
-
/// send serialises a message and writes it to the active transport
|
|
538
|
+
/// send serialises a message and writes it to the active transport,
|
|
539
|
+
/// reopening the chain first if a previous reconnect was interrupted.
|
|
574
540
|
pub async fn send(&mut self, data: &SendMsg) -> Result<(), RealtimeError> {
|
|
575
|
-
|
|
541
|
+
self.ensure_open().await?;
|
|
576
542
|
let v = serde_json::to_value(data).map_err(|e| RealtimeError::Send(Error::Json(e)))?;
|
|
543
|
+
let conn = self.conn.as_mut().ok_or(RealtimeError::Closed)?;
|
|
577
544
|
conn.send_json(v).await
|
|
578
545
|
}
|
|
579
546
|
|
|
580
|
-
/// recv reads the next message
|
|
581
|
-
///
|
|
582
|
-
///
|
|
583
|
-
/// and TS `createResumableConnection`'s recv loop. Gives up after
|
|
584
|
-
/// `max_reconnect_attempts` attempts and returns the last error.
|
|
547
|
+
/// recv reads the next message, reconnecting with exponential backoff and
|
|
548
|
+
/// jitter on transport failure. Gives up after `max_reconnect_attempts`
|
|
549
|
+
/// consecutive failures and returns the last error.
|
|
585
550
|
pub async fn recv(&mut self) -> Result<RecvMsg, RealtimeError> {
|
|
586
|
-
let max_attempts = self.opts.max_reconnect_attempts.unwrap_or(5);
|
|
587
|
-
let delay_ms = self.opts.reconnect_delay_ms.unwrap_or(1000);
|
|
588
551
|
loop {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
conn.recv_json().await
|
|
552
|
+
self.ensure_open().await?;
|
|
553
|
+
let result = match self.conn.as_mut() {
|
|
554
|
+
Some(conn) => conn.recv_json().await,
|
|
555
|
+
None => continue,
|
|
592
556
|
};
|
|
593
557
|
match result {
|
|
594
558
|
Ok(v) => {
|
|
595
559
|
self.reconnect_attempts = 0;
|
|
596
|
-
return serde_json::from_value(v)
|
|
597
|
-
.map_err(|e| RealtimeError::Recv(Error::Json(e)));
|
|
560
|
+
return serde_json::from_value(v).map_err(|e| RealtimeError::Recv(Error::Json(e)));
|
|
598
561
|
}
|
|
599
562
|
Err(err) => {
|
|
600
|
-
self.
|
|
601
|
-
|
|
602
|
-
self.state = ConnectionState::Disconnected;
|
|
603
|
-
return Err(err);
|
|
563
|
+
if self.closed {
|
|
564
|
+
return Err(RealtimeError::Closed);
|
|
604
565
|
}
|
|
605
566
|
self.state = ConnectionState::Reconnecting;
|
|
606
|
-
/* drop the dead conn + invalidate proven so chain retries from the top */
|
|
567
|
+
/* drop the dead conn + invalidate proven so the chain retries from the top */
|
|
607
568
|
if let Some(mut c) = self.conn.take() {
|
|
608
569
|
let _ = c.close().await;
|
|
609
570
|
}
|
|
610
571
|
self.proven_index = None;
|
|
611
|
-
if
|
|
612
|
-
tokio::time::sleep(tokio::time::Duration::from_millis(delay_ms)).await;
|
|
613
|
-
}
|
|
614
|
-
if let Err(open_err) = self.open_chain().await {
|
|
572
|
+
if let Err(e) = self.reconnect(err).await {
|
|
615
573
|
self.state = ConnectionState::Disconnected;
|
|
616
|
-
return Err(
|
|
574
|
+
return Err(e);
|
|
617
575
|
}
|
|
618
576
|
}
|
|
619
577
|
}
|
|
620
578
|
}
|
|
621
579
|
}
|
|
622
580
|
|
|
623
|
-
/// close gracefully shuts down the connection.
|
|
581
|
+
/// close gracefully shuts down the connection; later calls return Closed.
|
|
624
582
|
pub async fn close(&mut self) -> Result<(), RealtimeError> {
|
|
583
|
+
self.closed = true;
|
|
625
584
|
if let Some(mut c) = self.conn.take() {
|
|
626
585
|
let _ = c.close().await;
|
|
627
586
|
}
|
|
@@ -629,74 +588,115 @@ where
|
|
|
629
588
|
Ok(())
|
|
630
589
|
}
|
|
631
590
|
|
|
591
|
+
async fn ensure_open(&mut self) -> Result<(), RealtimeError> {
|
|
592
|
+
if self.closed {
|
|
593
|
+
return Err(RealtimeError::Closed);
|
|
594
|
+
}
|
|
595
|
+
if self.conn.is_some() {
|
|
596
|
+
return Ok(());
|
|
597
|
+
}
|
|
598
|
+
/* a reconnect future was dropped mid-way: pick up where it left off */
|
|
599
|
+
self.state = ConnectionState::Reconnecting;
|
|
600
|
+
self.reconnect(RealtimeError::Closed).await
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
async fn reconnect(&mut self, mut last: RealtimeError) -> Result<(), RealtimeError> {
|
|
604
|
+
let max_attempts = self.opts.max_reconnect_attempts.unwrap_or(5);
|
|
605
|
+
loop {
|
|
606
|
+
self.reconnect_attempts += 1;
|
|
607
|
+
if max_attempts > 0 && self.reconnect_attempts > max_attempts {
|
|
608
|
+
return Err(last);
|
|
609
|
+
}
|
|
610
|
+
tokio::time::sleep(self.backoff(self.reconnect_attempts)).await;
|
|
611
|
+
match self.open_chain().await {
|
|
612
|
+
Ok(()) => return Ok(()),
|
|
613
|
+
Err(e) => last = e,
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
fn backoff(&self, attempt: u32) -> Duration {
|
|
619
|
+
let base = Duration::from_millis(self.opts.reconnect_delay_ms.unwrap_or(1000));
|
|
620
|
+
let mut d = base;
|
|
621
|
+
for _ in 1..attempt {
|
|
622
|
+
if d >= MAX_RECONNECT_DELAY {
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
d *= 2;
|
|
626
|
+
}
|
|
627
|
+
let d = d.min(MAX_RECONNECT_DELAY);
|
|
628
|
+
/* jitter in [d/2, d] without a rand dependency */
|
|
629
|
+
let nanos = std::time::SystemTime::now()
|
|
630
|
+
.duration_since(std::time::UNIX_EPOCH)
|
|
631
|
+
.map(|t| t.subsec_nanos() as u64)
|
|
632
|
+
.unwrap_or(0);
|
|
633
|
+
let half = d.as_millis() as u64 / 2;
|
|
634
|
+
Duration::from_millis(half + if half == 0 { 0 } else { nanos % (half + 1) })
|
|
635
|
+
}
|
|
636
|
+
|
|
632
637
|
async fn open_chain(&mut self) -> Result<(), RealtimeError> {
|
|
633
|
-
|
|
638
|
+
let mut order: Vec<usize> = Vec::with_capacity(self.transports.len());
|
|
634
639
|
if let Some(i) = self.proven_index {
|
|
635
|
-
|
|
636
|
-
if let Ok(c) = t.connect(&self.url, &self.transport_opts).await {
|
|
637
|
-
self.conn = Some(c);
|
|
638
|
-
self.state = ConnectionState::Connected;
|
|
639
|
-
return Ok(());
|
|
640
|
-
}
|
|
641
|
-
}
|
|
640
|
+
order.push(i);
|
|
642
641
|
}
|
|
643
|
-
|
|
642
|
+
order.extend((0..self.transports.len()).filter(|i| Some(*i) != self.proven_index));
|
|
644
643
|
let mut last_err: Option<RealtimeError> = None;
|
|
645
|
-
for
|
|
646
|
-
|
|
647
|
-
|
|
644
|
+
for i in order {
|
|
645
|
+
let Some(t) = self.transports.get(i) else { continue };
|
|
646
|
+
match tokio::time::timeout(OPEN_TIMEOUT, t.connect(&self.url, &self.transport_opts)).await {
|
|
647
|
+
Ok(Ok(c)) => {
|
|
648
648
|
self.conn = Some(c);
|
|
649
649
|
self.proven_index = Some(i);
|
|
650
650
|
self.state = ConnectionState::Connected;
|
|
651
651
|
return Ok(());
|
|
652
652
|
}
|
|
653
|
-
Err(e) => last_err = Some(e),
|
|
653
|
+
Ok(Err(e)) => last_err = Some(e),
|
|
654
|
+
Err(_) => last_err = Some(connect_err("transport open timed out")),
|
|
654
655
|
}
|
|
655
656
|
}
|
|
656
|
-
Err(last_err.unwrap_or(RealtimeError::Connect(Error::Other(
|
|
657
|
-
"all transports failed".into(),
|
|
658
|
-
))))
|
|
657
|
+
Err(last_err.unwrap_or(RealtimeError::Connect(Error::Other("all transports failed".into()))))
|
|
659
658
|
}
|
|
660
|
-
|
|
661
659
|
}
|
|
662
660
|
|
|
661
|
+
/// build_sse_state opens the stream; a non-2xx status or a non-event-stream
|
|
662
|
+
/// content type is a connect error, so the chain moves on.
|
|
663
663
|
async fn build_sse_state(
|
|
664
664
|
url: String,
|
|
665
665
|
http_client: reqwest::Client,
|
|
666
666
|
opts: &TransportOpts,
|
|
667
|
-
) -> Result<SseState,
|
|
668
|
-
let mut req_builder = http_client
|
|
669
|
-
.get(url.as_str())
|
|
670
|
-
.header("Accept", "text/event-stream");
|
|
667
|
+
) -> Result<SseState, RealtimeError> {
|
|
668
|
+
let mut req_builder = http_client.get(url.as_str()).header("Accept", "text/event-stream");
|
|
671
669
|
if let Some(ref last_event_id) = opts.last_event_id {
|
|
672
670
|
req_builder = req_builder.header("Last-Event-ID", last_event_id.as_str());
|
|
673
671
|
}
|
|
674
672
|
for (k, v) in &opts.headers {
|
|
675
673
|
req_builder = req_builder.header(k.as_str(), v.as_str());
|
|
676
674
|
}
|
|
677
|
-
if !opts
|
|
678
|
-
.headers
|
|
679
|
-
.keys()
|
|
680
|
-
.any(|k| k.eq_ignore_ascii_case("x-request-id"))
|
|
681
|
-
{
|
|
675
|
+
if !opts.headers.keys().any(|k| k.eq_ignore_ascii_case("x-request-id")) {
|
|
682
676
|
req_builder = req_builder.header("x-request-id", uuid::Uuid::new_v4().to_string());
|
|
683
677
|
}
|
|
684
|
-
let resp = req_builder.send().await?;
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
let
|
|
678
|
+
let resp = req_builder.send().await.map_err(connect_err)?;
|
|
679
|
+
if !resp.status().is_success() {
|
|
680
|
+
return Err(connect_err(format!("sse status {}", resp.status())));
|
|
681
|
+
}
|
|
682
|
+
let is_event_stream = resp
|
|
683
|
+
.headers()
|
|
684
|
+
.get(reqwest::header::CONTENT_TYPE)
|
|
685
|
+
.and_then(|v| v.to_str().ok())
|
|
686
|
+
.map(|v| v.to_ascii_lowercase().starts_with("text/event-stream"))
|
|
687
|
+
.unwrap_or(false);
|
|
688
|
+
if !is_event_stream {
|
|
689
|
+
return Err(connect_err("sse response is not text/event-stream"));
|
|
690
|
+
}
|
|
689
691
|
let byte_stream: ByteStream = Box::pin(resp.bytes_stream());
|
|
690
692
|
Ok(SseState {
|
|
691
693
|
byte_stream,
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
694
|
+
last_event_id: opts.last_event_id.clone(),
|
|
695
|
+
retry_hint_ms: opts.reconnect_delay_ms.unwrap_or(1000),
|
|
696
|
+
parser: SseParser::new(),
|
|
697
|
+
pending: VecDeque::new(),
|
|
695
698
|
http_client,
|
|
696
699
|
url,
|
|
697
|
-
extra_headers,
|
|
698
|
-
max_reconnect_attempts,
|
|
699
|
-
reconnect_delay_ms,
|
|
700
|
-
reconnect_attempts: 0,
|
|
700
|
+
extra_headers: opts.headers.clone(),
|
|
701
701
|
})
|
|
702
702
|
}
|