@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
|
@@ -14,7 +14,9 @@ def _now() -> float:
|
|
|
14
14
|
return time.monotonic()
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
# `{name}` (any name without braces or slashes) or a `:name` segment; a colon
|
|
18
|
+
# inside a segment (`/ops/{id}:cancel`) is literal.
|
|
19
|
+
_PATH_PARAM_RE = re.compile(r"\{([^{}/]+)\}|(?:(?<=/)|^):([a-zA-Z_][a-zA-Z0-9_]*)")
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
@dataclass
|
|
@@ -79,8 +81,8 @@ def resolve_invalidation_targets_for_mutation(
|
|
|
79
81
|
) -> list[str]:
|
|
80
82
|
"""Expand ``METHOD /path/{id}`` template invalidation targets to concrete selectors.
|
|
81
83
|
|
|
82
|
-
Targets without placeholders are passed through.
|
|
83
|
-
be resolved
|
|
84
|
+
Targets without placeholders are passed through. A target whose placeholders cannot
|
|
85
|
+
all be resolved stays a pattern, so it marks every instance stale (TS parity).
|
|
84
86
|
"""
|
|
85
87
|
resolved: list[str] = []
|
|
86
88
|
for entry in targets:
|
|
@@ -96,6 +98,7 @@ def resolve_invalidation_targets_for_mutation(
|
|
|
96
98
|
try:
|
|
97
99
|
concrete = interpolate_path(template, params)
|
|
98
100
|
except ValueError:
|
|
101
|
+
resolved.append(entry)
|
|
99
102
|
continue
|
|
100
103
|
resolved.append(f"{method} {concrete}")
|
|
101
104
|
return resolved
|
|
@@ -136,6 +139,158 @@ def lookup_stale(key: str, stale_map: "OrderedDict[str, Any]") -> bool:
|
|
|
136
139
|
return _now() < until
|
|
137
140
|
|
|
138
141
|
|
|
142
|
+
class _StaleStore:
|
|
143
|
+
"""Stale state shared by the async and sync trackers; callers hold their own lock.
|
|
144
|
+
|
|
145
|
+
Concrete keys are looked up directly; keys that still hold ``{name}``
|
|
146
|
+
placeholders are also indexed per method, so a lookup scans only the patterns
|
|
147
|
+
of its method, not every entry. Expired concrete entries go on access, expired
|
|
148
|
+
patterns when scanned, and the rest when the map is over capacity.
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
def __init__(
|
|
152
|
+
self, stale_time: float, stale_max_entries: int, max_sources_per_target: int
|
|
153
|
+
) -> None:
|
|
154
|
+
self.enabled = stale_time > 0
|
|
155
|
+
self.stale_time = max(stale_time, 0.0)
|
|
156
|
+
self.max_entries = max(stale_max_entries, 1)
|
|
157
|
+
self.max_sources = max(max_sources_per_target, 1)
|
|
158
|
+
self.map: OrderedDict[str, _StaleEntry] = OrderedDict()
|
|
159
|
+
self.patterns: dict[str, dict[str, None]] = {}
|
|
160
|
+
self.seq = 0
|
|
161
|
+
|
|
162
|
+
def delete(self, key: str) -> None:
|
|
163
|
+
if self.map.pop(key, None) is None:
|
|
164
|
+
return
|
|
165
|
+
method, path = _split_key(key)
|
|
166
|
+
bucket = self.patterns.get(method)
|
|
167
|
+
if bucket is not None and _has_unresolved(path):
|
|
168
|
+
bucket.pop(key, None)
|
|
169
|
+
if not bucket:
|
|
170
|
+
del self.patterns[method]
|
|
171
|
+
|
|
172
|
+
def upsert(
|
|
173
|
+
self, key: str, until: float, seq: int, mutation_selector: str | None
|
|
174
|
+
) -> None:
|
|
175
|
+
existing = self.map.get(key)
|
|
176
|
+
if existing is not None:
|
|
177
|
+
existing.until = until
|
|
178
|
+
existing.seq = seq
|
|
179
|
+
if mutation_selector and mutation_selector not in existing.by:
|
|
180
|
+
if len(existing.by) < self.max_sources:
|
|
181
|
+
existing.by.append(mutation_selector)
|
|
182
|
+
self.map.move_to_end(key)
|
|
183
|
+
return
|
|
184
|
+
by = [mutation_selector] if mutation_selector else []
|
|
185
|
+
self.map[key] = _StaleEntry(by=by, seq=seq, until=until)
|
|
186
|
+
method, path = _split_key(key)
|
|
187
|
+
if _has_unresolved(path):
|
|
188
|
+
self.patterns.setdefault(method, {})[key] = None
|
|
189
|
+
|
|
190
|
+
def invalidate(self, patterns: list[str]) -> None:
|
|
191
|
+
self.evict_expired()
|
|
192
|
+
targets = resolve_invalidation_targets(patterns, self.map)
|
|
193
|
+
self.seq += 1
|
|
194
|
+
until = _now() + self.stale_time
|
|
195
|
+
for t in targets:
|
|
196
|
+
self.upsert(t, until, self.seq, None)
|
|
197
|
+
self.enforce_capacity()
|
|
198
|
+
|
|
199
|
+
def mark_stale(
|
|
200
|
+
self,
|
|
201
|
+
invalidate: list[str],
|
|
202
|
+
params: dict[str, str] | None,
|
|
203
|
+
mutation_selector: str,
|
|
204
|
+
) -> None:
|
|
205
|
+
self.seq += 1
|
|
206
|
+
until = _now() + self.stale_time
|
|
207
|
+
for target in resolve_invalidation_targets_for_mutation(invalidate, params):
|
|
208
|
+
self.upsert(target, until, self.seq, mutation_selector)
|
|
209
|
+
self.enforce_capacity()
|
|
210
|
+
|
|
211
|
+
def mark(self, key: str) -> None:
|
|
212
|
+
self.seq += 1
|
|
213
|
+
self.upsert(key, _now() + self.stale_time, self.seq, None)
|
|
214
|
+
self.enforce_capacity()
|
|
215
|
+
|
|
216
|
+
def lookup(
|
|
217
|
+
self, concrete_selector: str, concrete_path: str, method: str, now: float
|
|
218
|
+
) -> tuple[list[str], bool]:
|
|
219
|
+
all_by: list[str] = []
|
|
220
|
+
exact = self.map.get(concrete_selector)
|
|
221
|
+
if exact is not None:
|
|
222
|
+
if exact.until > now:
|
|
223
|
+
all_by.extend(exact.by)
|
|
224
|
+
else:
|
|
225
|
+
self.delete(concrete_selector)
|
|
226
|
+
expired: list[str] = []
|
|
227
|
+
for key in self.patterns.get(method, {}):
|
|
228
|
+
entry = self.map[key]
|
|
229
|
+
if entry.until <= now:
|
|
230
|
+
expired.append(key)
|
|
231
|
+
continue
|
|
232
|
+
if key != concrete_selector and path_matches_pattern(
|
|
233
|
+
concrete_path, _split_key(key)[1]
|
|
234
|
+
):
|
|
235
|
+
all_by.extend(entry.by)
|
|
236
|
+
for key in expired:
|
|
237
|
+
self.delete(key)
|
|
238
|
+
deduped = list(dict.fromkeys(all_by))
|
|
239
|
+
return deduped, len(deduped) > 0
|
|
240
|
+
|
|
241
|
+
def clear(
|
|
242
|
+
self, concrete_selector: str, concrete_path: str, method: str, seq_snapshot: int
|
|
243
|
+
) -> None:
|
|
244
|
+
exact = self.map.get(concrete_selector)
|
|
245
|
+
if exact and exact.seq <= seq_snapshot:
|
|
246
|
+
self.delete(concrete_selector)
|
|
247
|
+
to_delete = [
|
|
248
|
+
key
|
|
249
|
+
for key in self.patterns.get(method, {})
|
|
250
|
+
if self.map[key].seq <= seq_snapshot
|
|
251
|
+
and path_matches_pattern(concrete_path, _split_key(key)[1])
|
|
252
|
+
]
|
|
253
|
+
for key in to_delete:
|
|
254
|
+
self.delete(key)
|
|
255
|
+
|
|
256
|
+
def request_meta(
|
|
257
|
+
self, concrete_selector: str, concrete_path: str, method: str
|
|
258
|
+
) -> _RequestMeta:
|
|
259
|
+
by, is_stale = self.lookup(concrete_selector, concrete_path, method, _now())
|
|
260
|
+
return _RequestMeta(
|
|
261
|
+
selector=concrete_selector,
|
|
262
|
+
is_stale=is_stale,
|
|
263
|
+
invalidated_by=by,
|
|
264
|
+
seq_snapshot=self.seq,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
def evict_expired(self) -> None:
|
|
268
|
+
now = _now()
|
|
269
|
+
for key in [k for k, v in self.map.items() if now >= v.until]:
|
|
270
|
+
self.delete(key)
|
|
271
|
+
|
|
272
|
+
def enforce_capacity(self) -> None:
|
|
273
|
+
if len(self.map) <= self.max_entries:
|
|
274
|
+
return
|
|
275
|
+
self.evict_expired()
|
|
276
|
+
target = max(self.max_entries // 2, 1)
|
|
277
|
+
while len(self.map) > target:
|
|
278
|
+
self.delete(next(iter(self.map)))
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _split_key(key: str) -> tuple[str, str]:
|
|
282
|
+
space_idx = key.find(" ")
|
|
283
|
+
if space_idx == -1:
|
|
284
|
+
return key, ""
|
|
285
|
+
return key[:space_idx], key[space_idx + 1 :]
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _split_method_path(method_or_key: str, path: str | None) -> tuple[str, str]:
|
|
289
|
+
if path is None:
|
|
290
|
+
return _split_key(method_or_key)
|
|
291
|
+
return method_or_key, path
|
|
292
|
+
|
|
293
|
+
|
|
139
294
|
class _StaleTracker:
|
|
140
295
|
"""Async-aware stale tracker backed by ``asyncio.Lock``."""
|
|
141
296
|
|
|
@@ -145,31 +300,24 @@ class _StaleTracker:
|
|
|
145
300
|
stale_max_entries: int = 1000,
|
|
146
301
|
max_sources_per_target: int = 16,
|
|
147
302
|
) -> None:
|
|
148
|
-
"""
|
|
149
|
-
self.
|
|
150
|
-
self._stale_time = max(stale_time, 0.0)
|
|
151
|
-
self._max_entries = max(stale_max_entries, 1)
|
|
152
|
-
self._max_sources = max(max_sources_per_target, 1)
|
|
153
|
-
self._map: OrderedDict[str, _StaleEntry] = OrderedDict()
|
|
303
|
+
"""stale_time == 0 disables the tracker (no stale window applied)."""
|
|
304
|
+
self._store = _StaleStore(stale_time, stale_max_entries, max_sources_per_target)
|
|
154
305
|
self._lock = asyncio.Lock()
|
|
155
|
-
self._seq = 0
|
|
156
306
|
|
|
157
307
|
@property
|
|
158
308
|
def enabled(self) -> bool:
|
|
159
|
-
return self.
|
|
309
|
+
return self._store.enabled
|
|
310
|
+
|
|
311
|
+
@property
|
|
312
|
+
def _map(self) -> "OrderedDict[str, _StaleEntry]":
|
|
313
|
+
return self._store.map
|
|
160
314
|
|
|
161
315
|
async def invalidate(self, patterns: list[str]) -> None:
|
|
162
316
|
"""Mark every existing key matching *patterns* as freshly stale."""
|
|
163
|
-
if not self.
|
|
317
|
+
if not self.enabled:
|
|
164
318
|
return
|
|
165
319
|
async with self._lock:
|
|
166
|
-
self.
|
|
167
|
-
targets = resolve_invalidation_targets(patterns, self._map)
|
|
168
|
-
self._seq += 1
|
|
169
|
-
until = _now() + self._stale_time
|
|
170
|
-
for t in targets:
|
|
171
|
-
self._upsert(t, until, self._seq, mutation_selector=None)
|
|
172
|
-
self._enforce_capacity()
|
|
320
|
+
self._store.invalidate(patterns)
|
|
173
321
|
|
|
174
322
|
async def mark_stale(
|
|
175
323
|
self,
|
|
@@ -178,27 +326,17 @@ class _StaleTracker:
|
|
|
178
326
|
mutation_selector: str,
|
|
179
327
|
) -> None:
|
|
180
328
|
"""Bump seq, expand templated invalidation entries, store stale keys."""
|
|
181
|
-
if not self.
|
|
329
|
+
if not self.enabled or not invalidate:
|
|
182
330
|
return
|
|
183
331
|
async with self._lock:
|
|
184
|
-
self.
|
|
185
|
-
until = _now() + self._stale_time
|
|
186
|
-
resolved = resolve_invalidation_targets_for_mutation(invalidate, params)
|
|
187
|
-
for target in resolved:
|
|
188
|
-
self._upsert(
|
|
189
|
-
target, until, self._seq, mutation_selector=mutation_selector,
|
|
190
|
-
)
|
|
191
|
-
self._enforce_capacity()
|
|
332
|
+
self._store.mark_stale(invalidate, params, mutation_selector)
|
|
192
333
|
|
|
193
334
|
async def mark(self, key: str) -> None:
|
|
194
335
|
"""Force *key* into the stale map. Used by SSE/WS open hooks and tests."""
|
|
195
|
-
if not self.
|
|
336
|
+
if not self.enabled:
|
|
196
337
|
return
|
|
197
338
|
async with self._lock:
|
|
198
|
-
self.
|
|
199
|
-
until = _now() + self._stale_time
|
|
200
|
-
self._upsert(key, until, self._seq, mutation_selector=None)
|
|
201
|
-
self._enforce_capacity()
|
|
339
|
+
self._store.mark(key)
|
|
202
340
|
|
|
203
341
|
async def is_stale(self, method_or_key: str, path: str | None = None) -> bool:
|
|
204
342
|
"""Return True if (method, path) is currently stale.
|
|
@@ -206,21 +344,13 @@ class _StaleTracker:
|
|
|
206
344
|
Accepts either ``is_stale("GET /users")`` or ``is_stale("GET", "/users")``.
|
|
207
345
|
Walks pattern entries too.
|
|
208
346
|
"""
|
|
209
|
-
if not self.
|
|
347
|
+
if not self.enabled:
|
|
210
348
|
return False
|
|
211
|
-
|
|
212
|
-
method, concrete_path = self._split_key(method_or_key)
|
|
213
|
-
else:
|
|
214
|
-
method, concrete_path = method_or_key, path
|
|
349
|
+
method, concrete_path = _split_method_path(method_or_key, path)
|
|
215
350
|
async with self._lock:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
concrete_path=concrete_path,
|
|
220
|
-
method=method,
|
|
221
|
-
now=now,
|
|
222
|
-
)
|
|
223
|
-
return is_stale
|
|
351
|
+
return self._store.lookup(
|
|
352
|
+
f"{method} {concrete_path}", concrete_path, method, _now()
|
|
353
|
+
)[1]
|
|
224
354
|
|
|
225
355
|
async def lookup_stale(
|
|
226
356
|
self,
|
|
@@ -229,10 +359,10 @@ class _StaleTracker:
|
|
|
229
359
|
method: str,
|
|
230
360
|
) -> tuple[list[str], bool]:
|
|
231
361
|
"""Return (invalidated_by_list, is_stale): exact + pattern lookup with sweep."""
|
|
232
|
-
if not self.
|
|
362
|
+
if not self.enabled:
|
|
233
363
|
return [], False
|
|
234
364
|
async with self._lock:
|
|
235
|
-
return self.
|
|
365
|
+
return self._store.lookup(concrete_selector, concrete_path, method, _now())
|
|
236
366
|
|
|
237
367
|
async def clear_stale(
|
|
238
368
|
self,
|
|
@@ -242,25 +372,10 @@ class _StaleTracker:
|
|
|
242
372
|
seq_snapshot: int,
|
|
243
373
|
) -> None:
|
|
244
374
|
"""Drop seq-older entries matching *concrete_path* (exact + pattern keys)."""
|
|
245
|
-
if not self.
|
|
375
|
+
if not self.enabled:
|
|
246
376
|
return
|
|
247
377
|
async with self._lock:
|
|
248
|
-
|
|
249
|
-
if exact and exact.seq <= seq_snapshot:
|
|
250
|
-
del self._map[concrete_selector]
|
|
251
|
-
to_delete: list[str] = []
|
|
252
|
-
for key, entry in self._map.items():
|
|
253
|
-
if entry.seq > seq_snapshot:
|
|
254
|
-
continue
|
|
255
|
-
key_method, key_pattern = self._split_key(key)
|
|
256
|
-
if "{" not in key_pattern and ":" not in key_pattern:
|
|
257
|
-
continue
|
|
258
|
-
if key_method != method:
|
|
259
|
-
continue
|
|
260
|
-
if path_matches_pattern(concrete_path, key_pattern):
|
|
261
|
-
to_delete.append(key)
|
|
262
|
-
for key in to_delete:
|
|
263
|
-
del self._map[key]
|
|
378
|
+
self._store.clear(concrete_selector, concrete_path, method, seq_snapshot)
|
|
264
379
|
|
|
265
380
|
async def build_request_meta(
|
|
266
381
|
self,
|
|
@@ -268,98 +383,14 @@ class _StaleTracker:
|
|
|
268
383
|
concrete_path: str,
|
|
269
384
|
method: str,
|
|
270
385
|
) -> _RequestMeta | None:
|
|
271
|
-
if not self.
|
|
386
|
+
if not self.enabled:
|
|
272
387
|
return None
|
|
273
388
|
async with self._lock:
|
|
274
|
-
|
|
275
|
-
concrete_selector, concrete_path, method, _now(),
|
|
276
|
-
)
|
|
277
|
-
return _RequestMeta(
|
|
278
|
-
selector=concrete_selector,
|
|
279
|
-
is_stale=is_stale,
|
|
280
|
-
invalidated_by=by,
|
|
281
|
-
seq_snapshot=self._seq,
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
def _upsert(
|
|
285
|
-
self,
|
|
286
|
-
key: str,
|
|
287
|
-
until: float,
|
|
288
|
-
seq: int,
|
|
289
|
-
mutation_selector: str | None,
|
|
290
|
-
) -> None:
|
|
291
|
-
existing = self._map.get(key)
|
|
292
|
-
if existing is not None:
|
|
293
|
-
existing.until = until
|
|
294
|
-
existing.seq = seq
|
|
295
|
-
if mutation_selector and mutation_selector not in existing.by:
|
|
296
|
-
if len(existing.by) < self._max_sources:
|
|
297
|
-
existing.by.append(mutation_selector)
|
|
298
|
-
self._map.move_to_end(key)
|
|
299
|
-
return
|
|
300
|
-
by = [mutation_selector] if mutation_selector else []
|
|
301
|
-
self._map[key] = _StaleEntry(by=by, seq=seq, until=until)
|
|
302
|
-
self._map.move_to_end(key)
|
|
303
|
-
|
|
304
|
-
def _lookup_locked(
|
|
305
|
-
self,
|
|
306
|
-
concrete_selector: str,
|
|
307
|
-
concrete_path: str,
|
|
308
|
-
method: str,
|
|
309
|
-
now: float,
|
|
310
|
-
) -> tuple[list[str], bool]:
|
|
311
|
-
all_by: list[str] = []
|
|
312
|
-
exact = self._map.get(concrete_selector)
|
|
313
|
-
if exact is not None:
|
|
314
|
-
if exact.until > now:
|
|
315
|
-
all_by.extend(exact.by)
|
|
316
|
-
else:
|
|
317
|
-
del self._map[concrete_selector]
|
|
318
|
-
expired: list[str] = []
|
|
319
|
-
for key, entry in self._map.items():
|
|
320
|
-
if entry.until <= now:
|
|
321
|
-
expired.append(key)
|
|
322
|
-
continue
|
|
323
|
-
if "{" not in key and ":" not in key:
|
|
324
|
-
continue
|
|
325
|
-
if key == concrete_selector:
|
|
326
|
-
continue
|
|
327
|
-
key_method, key_pattern = self._split_key(key)
|
|
328
|
-
if key_method != method:
|
|
329
|
-
continue
|
|
330
|
-
if path_matches_pattern(concrete_path, key_pattern):
|
|
331
|
-
all_by.extend(entry.by)
|
|
332
|
-
for key in expired:
|
|
333
|
-
del self._map[key]
|
|
334
|
-
deduped: list[str] = []
|
|
335
|
-
seen: set[str] = set()
|
|
336
|
-
for src in all_by:
|
|
337
|
-
if src in seen:
|
|
338
|
-
continue
|
|
339
|
-
seen.add(src)
|
|
340
|
-
deduped.append(src)
|
|
341
|
-
return deduped, len(deduped) > 0
|
|
342
|
-
|
|
343
|
-
def _evict_expired(self) -> None:
|
|
344
|
-
now = _now()
|
|
345
|
-
expired = [k for k, v in self._map.items() if now >= v.until]
|
|
346
|
-
for k in expired:
|
|
347
|
-
del self._map[k]
|
|
348
|
-
|
|
349
|
-
def _enforce_capacity(self) -> None:
|
|
350
|
-
if len(self._map) <= self._max_entries:
|
|
351
|
-
return
|
|
352
|
-
self._evict_expired()
|
|
353
|
-
target = max(self._max_entries // 2, 1)
|
|
354
|
-
while len(self._map) > target:
|
|
355
|
-
self._map.popitem(last=False)
|
|
389
|
+
return self._store.request_meta(concrete_selector, concrete_path, method)
|
|
356
390
|
|
|
357
391
|
@staticmethod
|
|
358
392
|
def _split_key(key: str) -> tuple[str, str]:
|
|
359
|
-
|
|
360
|
-
if space_idx == -1:
|
|
361
|
-
return key, ""
|
|
362
|
-
return key[:space_idx], key[space_idx + 1 :]
|
|
393
|
+
return _split_key(key)
|
|
363
394
|
|
|
364
395
|
|
|
365
396
|
class _StaleTrackerSync:
|
|
@@ -371,30 +402,23 @@ class _StaleTrackerSync:
|
|
|
371
402
|
stale_max_entries: int = 1000,
|
|
372
403
|
max_sources_per_target: int = 16,
|
|
373
404
|
) -> None:
|
|
374
|
-
"""
|
|
375
|
-
self.
|
|
376
|
-
self._stale_time = max(stale_time, 0.0)
|
|
377
|
-
self._max_entries = max(stale_max_entries, 1)
|
|
378
|
-
self._max_sources = max(max_sources_per_target, 1)
|
|
379
|
-
self._map: OrderedDict[str, _StaleEntry] = OrderedDict()
|
|
405
|
+
"""stale_time == 0 disables the tracker (no stale window applied)."""
|
|
406
|
+
self._store = _StaleStore(stale_time, stale_max_entries, max_sources_per_target)
|
|
380
407
|
self._lock = threading.Lock()
|
|
381
|
-
self._seq = 0
|
|
382
408
|
|
|
383
409
|
@property
|
|
384
410
|
def enabled(self) -> bool:
|
|
385
|
-
return self.
|
|
411
|
+
return self._store.enabled
|
|
412
|
+
|
|
413
|
+
@property
|
|
414
|
+
def _map(self) -> "OrderedDict[str, _StaleEntry]":
|
|
415
|
+
return self._store.map
|
|
386
416
|
|
|
387
417
|
def invalidate(self, patterns: list[str]) -> None:
|
|
388
|
-
if not self.
|
|
418
|
+
if not self.enabled:
|
|
389
419
|
return
|
|
390
420
|
with self._lock:
|
|
391
|
-
self.
|
|
392
|
-
targets = resolve_invalidation_targets(patterns, self._map)
|
|
393
|
-
self._seq += 1
|
|
394
|
-
until = _now() + self._stale_time
|
|
395
|
-
for t in targets:
|
|
396
|
-
self._upsert(t, until, self._seq, None)
|
|
397
|
-
self._enforce_capacity()
|
|
421
|
+
self._store.invalidate(patterns)
|
|
398
422
|
|
|
399
423
|
def mark_stale(
|
|
400
424
|
self,
|
|
@@ -402,37 +426,25 @@ class _StaleTrackerSync:
|
|
|
402
426
|
params: dict[str, str] | None,
|
|
403
427
|
mutation_selector: str,
|
|
404
428
|
) -> None:
|
|
405
|
-
if not self.
|
|
429
|
+
if not self.enabled or not invalidate:
|
|
406
430
|
return
|
|
407
431
|
with self._lock:
|
|
408
|
-
self.
|
|
409
|
-
until = _now() + self._stale_time
|
|
410
|
-
resolved = resolve_invalidation_targets_for_mutation(invalidate, params)
|
|
411
|
-
for target in resolved:
|
|
412
|
-
self._upsert(target, until, self._seq, mutation_selector)
|
|
413
|
-
self._enforce_capacity()
|
|
432
|
+
self._store.mark_stale(invalidate, params, mutation_selector)
|
|
414
433
|
|
|
415
434
|
def mark(self, key: str) -> None:
|
|
416
|
-
if not self.
|
|
435
|
+
if not self.enabled:
|
|
417
436
|
return
|
|
418
437
|
with self._lock:
|
|
419
|
-
self.
|
|
420
|
-
until = _now() + self._stale_time
|
|
421
|
-
self._upsert(key, until, self._seq, None)
|
|
422
|
-
self._enforce_capacity()
|
|
438
|
+
self._store.mark(key)
|
|
423
439
|
|
|
424
440
|
def is_stale(self, method_or_key: str, path: str | None = None) -> bool:
|
|
425
|
-
if not self.
|
|
441
|
+
if not self.enabled:
|
|
426
442
|
return False
|
|
427
|
-
|
|
428
|
-
method, concrete_path = _StaleTracker._split_key(method_or_key)
|
|
429
|
-
else:
|
|
430
|
-
method, concrete_path = method_or_key, path
|
|
443
|
+
method, concrete_path = _split_method_path(method_or_key, path)
|
|
431
444
|
with self._lock:
|
|
432
|
-
|
|
433
|
-
f"{method} {concrete_path}", concrete_path, method, _now()
|
|
434
|
-
)
|
|
435
|
-
return is_stale
|
|
445
|
+
return self._store.lookup(
|
|
446
|
+
f"{method} {concrete_path}", concrete_path, method, _now()
|
|
447
|
+
)[1]
|
|
436
448
|
|
|
437
449
|
def lookup_stale(
|
|
438
450
|
self,
|
|
@@ -440,10 +452,10 @@ class _StaleTrackerSync:
|
|
|
440
452
|
concrete_path: str,
|
|
441
453
|
method: str,
|
|
442
454
|
) -> tuple[list[str], bool]:
|
|
443
|
-
if not self.
|
|
455
|
+
if not self.enabled:
|
|
444
456
|
return [], False
|
|
445
457
|
with self._lock:
|
|
446
|
-
return self.
|
|
458
|
+
return self._store.lookup(concrete_selector, concrete_path, method, _now())
|
|
447
459
|
|
|
448
460
|
def clear_stale(
|
|
449
461
|
self,
|
|
@@ -452,25 +464,10 @@ class _StaleTrackerSync:
|
|
|
452
464
|
method: str,
|
|
453
465
|
seq_snapshot: int,
|
|
454
466
|
) -> None:
|
|
455
|
-
if not self.
|
|
467
|
+
if not self.enabled:
|
|
456
468
|
return
|
|
457
469
|
with self._lock:
|
|
458
|
-
|
|
459
|
-
if exact and exact.seq <= seq_snapshot:
|
|
460
|
-
del self._map[concrete_selector]
|
|
461
|
-
to_delete: list[str] = []
|
|
462
|
-
for key, entry in self._map.items():
|
|
463
|
-
if entry.seq > seq_snapshot:
|
|
464
|
-
continue
|
|
465
|
-
key_method, key_pattern = _StaleTracker._split_key(key)
|
|
466
|
-
if "{" not in key_pattern and ":" not in key_pattern:
|
|
467
|
-
continue
|
|
468
|
-
if key_method != method:
|
|
469
|
-
continue
|
|
470
|
-
if path_matches_pattern(concrete_path, key_pattern):
|
|
471
|
-
to_delete.append(key)
|
|
472
|
-
for key in to_delete:
|
|
473
|
-
del self._map[key]
|
|
470
|
+
self._store.clear(concrete_selector, concrete_path, method, seq_snapshot)
|
|
474
471
|
|
|
475
472
|
def build_request_meta(
|
|
476
473
|
self,
|
|
@@ -478,91 +475,10 @@ class _StaleTrackerSync:
|
|
|
478
475
|
concrete_path: str,
|
|
479
476
|
method: str,
|
|
480
477
|
) -> _RequestMeta | None:
|
|
481
|
-
if not self.
|
|
478
|
+
if not self.enabled:
|
|
482
479
|
return None
|
|
483
480
|
with self._lock:
|
|
484
|
-
|
|
485
|
-
concrete_selector, concrete_path, method, _now(),
|
|
486
|
-
)
|
|
487
|
-
return _RequestMeta(
|
|
488
|
-
selector=concrete_selector,
|
|
489
|
-
is_stale=is_stale,
|
|
490
|
-
invalidated_by=by,
|
|
491
|
-
seq_snapshot=self._seq,
|
|
492
|
-
)
|
|
493
|
-
|
|
494
|
-
def _upsert(
|
|
495
|
-
self,
|
|
496
|
-
key: str,
|
|
497
|
-
until: float,
|
|
498
|
-
seq: int,
|
|
499
|
-
mutation_selector: str | None,
|
|
500
|
-
) -> None:
|
|
501
|
-
existing = self._map.get(key)
|
|
502
|
-
if existing is not None:
|
|
503
|
-
existing.until = until
|
|
504
|
-
existing.seq = seq
|
|
505
|
-
if mutation_selector and mutation_selector not in existing.by:
|
|
506
|
-
if len(existing.by) < self._max_sources:
|
|
507
|
-
existing.by.append(mutation_selector)
|
|
508
|
-
self._map.move_to_end(key)
|
|
509
|
-
return
|
|
510
|
-
by = [mutation_selector] if mutation_selector else []
|
|
511
|
-
self._map[key] = _StaleEntry(by=by, seq=seq, until=until)
|
|
512
|
-
self._map.move_to_end(key)
|
|
513
|
-
|
|
514
|
-
def _lookup_locked(
|
|
515
|
-
self,
|
|
516
|
-
concrete_selector: str,
|
|
517
|
-
concrete_path: str,
|
|
518
|
-
method: str,
|
|
519
|
-
now: float,
|
|
520
|
-
) -> tuple[list[str], bool]:
|
|
521
|
-
all_by: list[str] = []
|
|
522
|
-
exact = self._map.get(concrete_selector)
|
|
523
|
-
if exact is not None:
|
|
524
|
-
if exact.until > now:
|
|
525
|
-
all_by.extend(exact.by)
|
|
526
|
-
else:
|
|
527
|
-
del self._map[concrete_selector]
|
|
528
|
-
expired: list[str] = []
|
|
529
|
-
for key, entry in self._map.items():
|
|
530
|
-
if entry.until <= now:
|
|
531
|
-
expired.append(key)
|
|
532
|
-
continue
|
|
533
|
-
if "{" not in key and ":" not in key:
|
|
534
|
-
continue
|
|
535
|
-
if key == concrete_selector:
|
|
536
|
-
continue
|
|
537
|
-
key_method, key_pattern = _StaleTracker._split_key(key)
|
|
538
|
-
if key_method != method:
|
|
539
|
-
continue
|
|
540
|
-
if path_matches_pattern(concrete_path, key_pattern):
|
|
541
|
-
all_by.extend(entry.by)
|
|
542
|
-
for key in expired:
|
|
543
|
-
del self._map[key]
|
|
544
|
-
deduped: list[str] = []
|
|
545
|
-
seen: set[str] = set()
|
|
546
|
-
for src in all_by:
|
|
547
|
-
if src in seen:
|
|
548
|
-
continue
|
|
549
|
-
seen.add(src)
|
|
550
|
-
deduped.append(src)
|
|
551
|
-
return deduped, len(deduped) > 0
|
|
552
|
-
|
|
553
|
-
def _evict_expired(self) -> None:
|
|
554
|
-
now = _now()
|
|
555
|
-
expired = [k for k, v in self._map.items() if now >= v.until]
|
|
556
|
-
for k in expired:
|
|
557
|
-
del self._map[k]
|
|
558
|
-
|
|
559
|
-
def _enforce_capacity(self) -> None:
|
|
560
|
-
if len(self._map) <= self._max_entries:
|
|
561
|
-
return
|
|
562
|
-
self._evict_expired()
|
|
563
|
-
target = max(self._max_entries // 2, 1)
|
|
564
|
-
while len(self._map) > target:
|
|
565
|
-
self._map.popitem(last=False)
|
|
481
|
+
return self._store.request_meta(concrete_selector, concrete_path, method)
|
|
566
482
|
|
|
567
483
|
|
|
568
484
|
__all__ = [
|