This is an automated email from the ASF dual-hosted git repository.

shreemaan-abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new ee7dc10b4 chore: release 3.19.0 (#13976)
ee7dc10b4 is described below

commit ee7dc10b45b5791f44150d89051eacb8fdde05de
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Mon Sep 28 13:15:19 2026 +0800

    chore: release 3.19.0 (#13976)
---
 .requirements                            |  2 +-
 CHANGELOG.md                             | 62 ++++++++++++++++++++++++++++++++
 apisix/core/version.lua                  |  2 +-
 ci/check_changelog_prs.ts                |  4 +++
 docs/en/latest/config.json               |  2 +-
 docs/en/latest/plugins/batch-requests.md | 18 ++++++----
 docs/zh/latest/config.json               |  2 +-
 docs/zh/latest/plugins/batch-requests.md | 18 ++++++----
 8 files changed, 94 insertions(+), 16 deletions(-)

diff --git a/.requirements b/.requirements
index 1dbfc0f7e..f633665c6 100644
--- a/.requirements
+++ b/.requirements
@@ -18,4 +18,4 @@
 APISIX_PACKAGE_NAME=apisix
 
 APISIX_RUNTIME=1.3.18
-APISIX_DASHBOARD_COMMIT=045e3142867e3b7d5d1b8ec40bf8f66a7ce24a64
+APISIX_DASHBOARD_COMMIT=fa2fd0f60f8afffb096476333b9ba63b4c518fa3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e2ab2afb1..03359db9b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,7 @@ title: Changelog
 
 ## Table of Contents
 
+- [3.19.0](#3190)
 - [3.18.0](#3180)
 - [3.17.0](#3170)
 - [3.16.0](#3160)
@@ -86,6 +87,67 @@ title: Changelog
 - [0.7.0](#070)
 - [0.6.0](#060)
 
+## 3.19.0
+
+**The changes marked with :warning: are not backward compatible.**
+
+### Change
+
+- :warning: feat(upstream): verify the upstream certificate against 
configurable CAs. `upstream.tls.verify` was only read by the `kafka` scheme and 
is now honoured for `https` and `grpcs` as well, so an upstream that already 
carried `verify: true` starts rejecting a certificate it cannot validate; 
`tls.ca_certs` picks the trust anchors per upstream 
[#13863](https://github.com/apache/apisix/pull/13863)
+- :warning: fix(openid-connect): validate the introspection issuer. With an 
explicit `claim_validator.issuer.valid_issuers`, a successful remote 
introspection response must now carry a string `iss` matching one of them, or 
the request is rejected with 401; omit the allowlist to keep the previous 
behavior [#13916](https://github.com/apache/apisix/pull/13916)
+- :warning: fix(batch-requests): bound aggregated response bodies. New 
`max_response_body_size` (1 MiB) and `max_response_body_size_total` (10 MiB) 
plugin metadata; a pipeline above either limit now returns 502 instead of the 
full aggregate [#13906](https://github.com/apache/apisix/pull/13906)
+- :warning: fix(basic-auth): reject an empty consumer password. `password` 
requires `minLength: 1`, so the Admin API rejects an empty value and a consumer 
already stored with one fails closed with 401 
[#13884](https://github.com/apache/apisix/pull/13884)
+- :warning: fix(ai-proxy-multi): reject instances that share a name. 
`instance.name` is the instance identity across the balancer, the health 
checker, `ai-rate-limiting` and `semantic_opts.fallback`, so a route whose 
instances share a name is now rejected on write and dropped on reload 
[#13851](https://github.com/apache/apisix/pull/13851)
+- :warning: fix(workflow): reject invalid case expressions and missing action 
conf. A `case` expression that was silently accepted and then matched every 
request is now a schema error, and `actions` is pinned to exactly one `[name, 
conf]` pair, so a rule carrying several actions (only the first ever ran) or an 
action without its conf is rejected on write and dropped on reload 
[#13862](https://github.com/apache/apisix/pull/13862)
+- :warning: feat(websocket): label successful WebSocket upgrades with 
`request_type=websocket`. On existing `enable_websocket` routes, successful 101 
responses change from `traditional_http` to `websocket` in 
`apisix_http_status`, `apisix_http_latency` and `apisix_bandwidth`; update 
PromQL selectors, recording rules, dashboards and alerts that filter on the old 
value. The new `ws`/`wss` proxy path reports the same label 
[#13909](https://github.com/apache/apisix/pull/13909)
+  This also includes the cached-variable correction from 
[#13915](https://github.com/apache/apisix/pull/13915), so a plugin that 
resolves `$request_type` before the upgrade cannot leave the old value cached.
+- :warning: fix(redis): send the TLS SNI and add `redis_server_name`. For the 
single-node `policy: redis` path with `redis_ssl_verify: true`, `redis_host` 
(or `redis_server_name`) is now used for hostname verification, so a DNS alias 
not covered by the certificate fails; set `redis_server_name` to the 
certificate identity or replace the certificate. Cluster and Sentinel policies 
are unchanged, and an IP literal sends no SNI 
[#13938](https://github.com/apache/apisix/pull/13938)
+- :warning: fix(feishu-auth, dingtalk-auth): bind the authorization code to 
the session that started the login. Existing browser flows that only forward 
the code now return 401; the application serving `redirect_uri` must pass the 
generated `state` to the identity provider and preserve it on the callback. The 
header code path (`X-Feishu-Code` / `X-DingTalk-Code`) is unchanged 
[#13806](https://github.com/apache/apisix/pull/13806)
+- :warning: fix(jwe-decrypt): accept JWE tokens that authenticate the 
protected header, as RFC 7516 requires, and reject an explicitly unsupported 
`alg` or `enc` with 400. Token generators that emit misleading values must use 
`alg: dir` and `enc: A256GCM`; legacy no-AAD tokens and headers that omit those 
fields remain accepted [#13889](https://github.com/apache/apisix/pull/13889)
+- :warning: fix(control): always report healthcheck nodes as a JSON array. The 
JSON type of `nodes` and the top-level `/v1/healthcheck` response changes from 
`{}` to `[]` when empty, so strict clients must accept an empty array 
[#13891](https://github.com/apache/apisix/pull/13891)
+
+### Core
+
+- feat(stream): support TLS passthrough on the stream proxy, so a stream route 
can pick its upstream from the SNI in the prereaded ClientHello and still 
forward the session encrypted 
[#13912](https://github.com/apache/apisix/pull/13912)
+- feat(stream): match a stream route by several SNIs through the new `snis` 
field, mutually exclusive with `sni` 
[#13911](https://github.com/apache/apisix/pull/13911)
+- feat(websocket): add the `ws`/`wss` upstream scheme, which proxies frames 
through APISIX itself and exposes the `ws_handshake`, `ws_client_frame`, 
`ws_upstream_frame` and `ws_close` plugin phases plus the `core.websocket` API 
[#13939](https://github.com/apache/apisix/pull/13939)
+- fix(websocket): address review findings on the `ws`/`wss` proxy path: 
dispatch on `ctx.upstream_scheme` so an inline upstream picked by 
`traffic-split` takes it, send the Host `proxy_pass` would send and use it as 
the SNI, answer the client with the subprotocol the upstream selected, retry 
after a non-101 answer, keep the request URI out of the connect failure log, 
and reject `tls.ca_certs`, which these schemes cannot apply 
[#13977](https://github.com/apache/apisix/pull/13977)
+- feat(upstream): slow start for newly observed upstream nodes via 
`warm_up_conf` [#13941](https://github.com/apache/apisix/pull/13941)
+- feat: improve API-driven standalone update reliability: workers report 
application of the configuration digest for each tracked resource type, `PUT 
/apisix/admin/configs` accepts a `wait` parameter and answers 200 once every 
worker has loaded the configuration (202 otherwise), and the shdict format 
carries the digest outside the JSON 
[#13904](https://github.com/apache/apisix/pull/13904)
+- feat(control-api): report the health checks a plugin owns, so 
`ai-proxy-multi` instance checkers show up in `/v1/healthcheck` 
[#13899](https://github.com/apache/apisix/pull/13899)
+- chore: upgrade lua-resty-dns-client to 7.1.2, fixing `finalCacheOnly` so a 
CNAME chain no longer fails with `empty record received` when the answer 
carries an EDNS(0) OPT record or is not in chain order 
[#13875](https://github.com/apache/apisix/pull/13875)
+- fix(etcd): watch from the revision the configuration was read at, so a write 
made while APISIX is starting is no longer lost 
[#13917](https://github.com/apache/apisix/pull/13917)
+- fix(etcd): check etcd availability before starting the watcher, so config 
objects do not wait on a watcher that never connected 
[#13934](https://github.com/apache/apisix/pull/13934)
+- fix(etcd): do not block writes when the deployment role cannot be read 
[#13885](https://github.com/apache/apisix/pull/13885)
+- fix(standalone): stop aborting stream connections before the first config 
arrives [#13855](https://github.com/apache/apisix/pull/13855)
+- fix(standalone): harden the declarative configuration paths: validate the 
shape of the request body instead of 500ing, log the parser error rather than 
the body (which can carry credentials and private keys), check a stream route's 
`superior_id` self reference during validation, and guard null deployment 
sections in the CLI [#13886](https://github.com/apache/apisix/pull/13886)
+- fix(plugin): align unavailable plugin handling: reject unknown plugin names 
before persistence, keep data-plane loading tolerant of them, and warn when one 
is skipped [#13928](https://github.com/apache/apisix/pull/13928)
+- fix: preserve servlet upstream URI boundaries by encoding the original path 
before proxying when servlet-style normalization is enabled 
[#13914](https://github.com/apache/apisix/pull/13914)
+
+### Plugins
+
+- feat: add the `openapi-to-mcp` plugin, serving an HTTP API to MCP clients 
from its OpenAPI document over Streamable HTTP and HTTP+SSE 
[#13942](https://github.com/apache/apisix/pull/13942)
+- feat(websocket): add the `websocket-proxy` plugin to customize proxy 
behaviors, starting with `client_max_payload_len` / `upstream_max_payload_len` 
for `ws`/`wss` upstreams [#13972](https://github.com/apache/apisix/pull/13972)
+- feat(graphql-limit-count): rate limit by GraphQL query cost. New 
`complexity` and `node_quantifier` cost strategies with per-field weights 
stored as `graphql_cost_decorations` under a Service; `depth` stays the default 
[#13840](https://github.com/apache/apisix/pull/13840)
+- feat: chaitin-waf response logging through `log_resp`, `resp_body_size` and 
`extra_ignored_content_types`, reported asynchronously after the response has 
been handed back to the client 
[#13763](https://github.com/apache/apisix/pull/13763)
+- feat(ai-proxy-multi): let configured HTTP statuses trigger a fallback via 
`fallback_http_statuses` [#13852](https://github.com/apache/apisix/pull/13852)
+- feat(saml-auth): add the lua-resty-saml 0.2.6 validation options 
`idp_issuers`, `sp_acs_url`, `sp_audiences`, `clock_skew`, `replay_dict` and 
`replay_ttl` [#13964](https://github.com/apache/apisix/pull/13964)
+- fix(ai-proxy): return 502 when a streaming upstream produces no output, 
instead of falling through to `balancer_by_lua` and answering nothing 
[#13870](https://github.com/apache/apisix/pull/13870)
+- fix(ai-proxy): do not turn a streaming read error after partial output into 
a 5xx, and do not retry a request whose partial output already reached the 
client [#13876](https://github.com/apache/apisix/pull/13876)
+- fix(ai-proxy): avoid aborting streams on empty flushes 
[#13947](https://github.com/apache/apisix/pull/13947)
+- fix(ai-providers): encode the Vertex AI model path segment 
[#13872](https://github.com/apache/apisix/pull/13872)
+- fix(ai-cache): key the passthrough protocol on the client method, path and 
query, so two upstream endpoints no longer collide on one cache entry 
[#13887](https://github.com/apache/apisix/pull/13887)
+- fix(ai-aliyun-content-moderation): report final results without usage 
[#13922](https://github.com/apache/apisix/pull/13922)
+- fix(jwe-decrypt): reject malformed tokens with 400 instead of returning 500 
[#13844](https://github.com/apache/apisix/pull/13844)
+- fix(basic-auth): split credentials on the first colon only, so a password 
containing `:` is no longer truncated 
[#13836](https://github.com/apache/apisix/pull/13836)
+- fix(data-mask): keep request header masking effective in the log phase, 
where `set_header()` silently did nothing on a 400 response 
[#13839](https://github.com/apache/apisix/pull/13839)
+- fix(redirect): compare `X-Forwarded-Proto` case-insensitively, so a proxy 
forwarding `HTTPS` no longer triggers an `http_to_https` redirect loop 
[#13865](https://github.com/apache/apisix/pull/13865)
+- fix(ua-restriction): deny the request when any User-Agent header matches the 
`deny_list` [#13869](https://github.com/apache/apisix/pull/13869)
+- fix(traffic-label): cache the compiled match expressions outside the plugin 
config, so the route configuration stays JSON encodable 
[#13901](https://github.com/apache/apisix/pull/13901)
+- fix(aws-lambda): request `/` for a path-less `function_uri` and log function 
error responses [#13908](https://github.com/apache/apisix/pull/13908)
+- fix(ext-plugin-post-resp): set `upstream_addr` and `upstream_response_time` 
for loggers [#13940](https://github.com/apache/apisix/pull/13940)
+- fix(openapi-to-mcp): apply schema defaults before validation, keep the 
resolved `base_url` and headers for the lifetime of an SSE session, and reject 
a document that is not an OpenAPI document 
[#13956](https://github.com/apache/apisix/pull/13956)
+
 ## 3.18.0
 
 **The changes marked with :warning: are not backward compatible.**
diff --git a/apisix/core/version.lua b/apisix/core/version.lua
index b02e89d44..2f6b77207 100644
--- a/apisix/core/version.lua
+++ b/apisix/core/version.lua
@@ -20,5 +20,5 @@
 -- @module core.version
 
 return {
-    VERSION = "3.18.0"
+    VERSION = "3.19.0"
 }
diff --git a/ci/check_changelog_prs.ts b/ci/check_changelog_prs.ts
index b69b20d73..b9fc4f6da 100755
--- a/ci/check_changelog_prs.ts
+++ b/ci/check_changelog_prs.ts
@@ -69,6 +69,10 @@ const IGNORE_PRS = [
     // "fix(ci)", "fix(dev-image)", "build:") dodges the docs/chore/test/ci 
type
     // filter but which do not belong in a user changelog.
     13526, 13554, 13679, 13709, 13815, 13824,
+    // 3.19.0
+    // CI-only changes whose "fix(ci)" subject prefix dodges the 
docs/chore/test/ci
+    // type filter but which do not belong in a user changelog.
+    13921, 13923,
 ];
 
 
diff --git a/docs/en/latest/config.json b/docs/en/latest/config.json
index 7397a7cf7..bf2424a50 100644
--- a/docs/en/latest/config.json
+++ b/docs/en/latest/config.json
@@ -1,5 +1,5 @@
 {
-  "version": "3.18.0",
+  "version": "3.19.0",
   "sidebar": [
     {
       "type": "category",
diff --git a/docs/en/latest/plugins/batch-requests.md 
b/docs/en/latest/plugins/batch-requests.md
index fd5be40dd..90bc1eb14 100644
--- a/docs/en/latest/plugins/batch-requests.md
+++ b/docs/en/latest/plugins/batch-requests.md
@@ -69,7 +69,7 @@ plugins:
 
 ## Configuration
 
-By default, the maximum body size that can be sent to `/apisix/batch-requests` 
can't be larger than 1 MiB. You can change this configuration of the Plugin 
through the endpoint `apisix/admin/plugin_metadata/batch-requests`:
+By default, the maximum body size that can be sent to `/apisix/batch-requests` 
and the maximum response body size for each pipeline request are both 1 MiB. 
The maximum total response body size for a pipeline is 10 MiB. You can change 
these global Plugin metadata settings through the endpoint 
`/apisix/admin/plugin_metadata/batch-requests`:
 
 :::note
 You can fetch the `admin_key` from `config.yaml` and save to an environment 
variable with the following command:
@@ -83,16 +83,22 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' 
conf/config.yaml | sed 's/"/
 ```shell
 curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/batch-requests -H 
"X-API-KEY: $admin_key" -X PUT -d '
 {
-    "max_body_size": 4194304
+    "max_body_size": 4194304,
+    "max_response_body_size": 2097152,
+    "max_response_body_size_total": 20971520
 }'
 ```
 
+These metadata settings are global and apply to every request handled by the 
`batch-requests` Plugin.
+
 ## Metadata
 
-| Name               | Type    | Required | Default | Valid values | 
Description                                              |
-| ------------------ | ------- | -------- | ------- | ------------ | 
-------------------------------------------------------- |
-| max_body_size      | integer | True     | 1048576 | [1, ...]     | Maximum 
size of the request body in bytes.               |
-| max_pipeline_items | integer | True     | 1000    | [1, ...]     | Maximum 
number of requests allowed in a single pipeline. |
+| Name                         | Type    | Required | Default  | Valid values 
| Description                                                        |
+| ---------------------------- | ------- | -------- | -------- | ------------ 
| ------------------------------------------------------------------ |
+| max_body_size                | integer | True     | 1048576  | [1, ...]     
| Maximum size of the request body in bytes.                         |
+| max_pipeline_items           | integer | True     | 1000     | [1, ...]     
| Maximum number of requests allowed in a single pipeline.           |
+| max_response_body_size       | integer | False    | 1048576  | [1, ...]     
| Maximum response body size in bytes for each pipeline request.     |
+| max_response_body_size_total | integer | False    | 10485760 | [1, ...]     
| Maximum total response body size in bytes for a single pipeline.   |
 
 ## Request and response format
 
diff --git a/docs/zh/latest/config.json b/docs/zh/latest/config.json
index baf9fb0b1..36da7ac93 100644
--- a/docs/zh/latest/config.json
+++ b/docs/zh/latest/config.json
@@ -1,5 +1,5 @@
 {
-  "version": "3.18.0",
+  "version": "3.19.0",
   "sidebar": [
     {
       "type": "category",
diff --git a/docs/zh/latest/plugins/batch-requests.md 
b/docs/zh/latest/plugins/batch-requests.md
index d43e9abe3..68eec33f6 100644
--- a/docs/zh/latest/plugins/batch-requests.md
+++ b/docs/zh/latest/plugins/batch-requests.md
@@ -69,7 +69,7 @@ plugins:
 
 ## 配置插件
 
-默认情况下,可以发送到 `/apisix/batch-requests` 的最大请求体不能大于 1 MiB。你可以通过 
`apisix/admin/plugin_metadata/batch-requests` 更改插件的此配置:
+默认情况下,可以发送到 `/apisix/batch-requests` 的最大请求体和每个 pipeline 请求的最大响应体均为 1 MiB,单个 
pipeline 的响应体总大小上限为 10 MiB。你可以通过 `/apisix/admin/plugin_metadata/batch-requests` 
更改这些全局插件元数据配置:
 
 :::note
 
@@ -85,16 +85,22 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' 
conf/config.yaml | sed 's/"/
 curl http://127.0.0.1:9180/apisix/admin/plugin_metadata/batch-requests \
 -H "X-API-KEY: $admin_key" -X PUT -d '
 {
-    "max_body_size": 4194304
+    "max_body_size": 4194304,
+    "max_response_body_size": 2097152,
+    "max_response_body_size_total": 20971520
 }'
 ```
 
+这些元数据配置在全局范围内生效,并应用于 `batch-requests` 插件处理的所有请求。
+
 ## 元数据
 
-| 名称               | 类型     | 必选项 | 默认值   | 有效值 | 描述                          |
-| ------------------ | ------- | -------| ------- | ------ | 
---------------------------- |
-| max_body_size      | integer | 是     | 1048576 |[1, ...]| 请求体的最大大小,单位:bytes。 
|
-| max_pipeline_items | integer | 是     | 1000    |[1, ...]| 单个 pipeline 
中允许的最大请求数量。 |
+| 名称                         | 类型    | 必选项 | 默认值   | 有效值   | 描述                
                             |
+| ---------------------------- | ------- | ------ | -------- | -------- | 
------------------------------------------------ |
+| max_body_size                | integer | 是     | 1048576  | [1, ...] | 
请求体的最大大小,单位:bytes。                  |
+| max_pipeline_items           | integer | 是     | 1000     | [1, ...] | 单个 
pipeline 中允许的最大请求数量。             |
+| max_response_body_size       | integer | 否     | 1048576  | [1, ...] | 每个 
pipeline 请求的最大响应体大小,单位:bytes。 |
+| max_response_body_size_total | integer | 否     | 10485760 | [1, ...] | 单个 
pipeline 的最大响应体总大小,单位:bytes。  |
 
 ## 请求和响应格式
 

Reply via email to