zuplo 6.71.20 → 6.71.21
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/docs/handlers/websocket-handler.mdx +23 -7
- package/docs/handlers/websocket-pipeline-handler.mdx +189 -0
- package/docs/mcp-gateway/cross-app-access/overview.mdx +2 -3
- package/docs/mcp-gateway/introduction.mdx +0 -9
- package/docs/policies/_index.md +1 -0
- package/docs/policies/rate-limit-inbound/schema.json +8 -4
- package/docs/policies/traffic-splitting-inbound/doc.md +67 -0
- package/docs/policies/traffic-splitting-inbound/intro.md +5 -0
- package/docs/policies/traffic-splitting-inbound/schema.json +121 -0
- package/package.json +4 -4
|
@@ -5,22 +5,35 @@ sidebar_label: WebSocket Handler
|
|
|
5
5
|
|
|
6
6
|
:::note
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
or sign up for an Enterprise account.
|
|
8
|
+
WebSocket handlers are an Enterprise-only feature at this time. Please contact
|
|
9
|
+
us to trial this or sign up for an Enterprise account.
|
|
10
10
|
|
|
11
11
|
:::
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
Zuplo provides two handlers for proxying WebSocket connections to your backend
|
|
14
|
+
WebSocket APIs:
|
|
15
|
+
|
|
16
|
+
- **`webSocketHandler`** proxies WebSocket traffic straight through to your
|
|
17
|
+
backend without inspecting the messages. Use this when you only need to
|
|
18
|
+
authenticate, rate limit, or route the connection.
|
|
19
|
+
- **`webSocketPipelineHandler`** does everything `webSocketHandler` does and
|
|
20
|
+
additionally runs every message through a policy pipeline, so you can inspect,
|
|
21
|
+
transform, or drop individual messages in either direction. See the
|
|
22
|
+
[WebSocket Pipeline Handler](./websocket-pipeline-handler.mdx).
|
|
23
|
+
|
|
24
|
+
Both handlers can be configured alongside other existing policies like
|
|
25
|
+
[Rate Limiting](../policies/rate-limit-inbound.mdx),
|
|
26
|
+
[API Keys](../policies/api-key-inbound.mdx), etc. and are available for use on
|
|
17
27
|
all environments.
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
These handlers are only configurable via the JSON View on a project's Route
|
|
20
30
|
Designer or directly in your project's `*.oas.json` file.
|
|
21
31
|
|
|
22
32
|
## Setup in `routes.oas.json`
|
|
23
33
|
|
|
34
|
+
This section covers the passthrough `webSocketHandler`. To intercept messages,
|
|
35
|
+
see the [WebSocket Pipeline Handler](./websocket-pipeline-handler.mdx).
|
|
36
|
+
|
|
24
37
|
Configuration of the WebSocket Handler is similar to other available handlers.
|
|
25
38
|
Set the name of the path that your WebSocket API route will use, set the use of
|
|
26
39
|
the `webSocketHandler` export from `@zuplo/runtime` module in the handler
|
|
@@ -62,6 +75,9 @@ The WebSocket Handler accepts the following options in the `options` property:
|
|
|
62
75
|
- **`rewritePattern`** (required): The URL pattern for the backend WebSocket
|
|
63
76
|
endpoint. Supports JavaScript string interpolation syntax for dynamic URL
|
|
64
77
|
construction based on request data and environment variables.
|
|
78
|
+
- **`policies`** (optional, `webSocketPipelineHandler` only): Configures the
|
|
79
|
+
message-interception policies that run on each WebSocket frame. See the
|
|
80
|
+
[WebSocket Pipeline Handler](./websocket-pipeline-handler.mdx).
|
|
65
81
|
|
|
66
82
|
Similar to other handlers using `rewritePattern`, it supports JavaScript string
|
|
67
83
|
interpolation syntax and can be used to shape the URL based on data from the
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: WebSocket Pipeline Handler
|
|
3
|
+
sidebar_label: WebSocket Pipeline Handler
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
:::note
|
|
7
|
+
|
|
8
|
+
The WebSocket Pipeline Handler is an Enterprise-only feature. Please contact us
|
|
9
|
+
to trial this or sign up for an Enterprise account.
|
|
10
|
+
|
|
11
|
+
:::
|
|
12
|
+
|
|
13
|
+
The `webSocketPipelineHandler` proxies WebSocket connections exactly like the
|
|
14
|
+
[WebSocket Handler](./websocket-handler.mdx), but additionally passes every
|
|
15
|
+
WebSocket message through a pipeline of **policy functions** before forwarding
|
|
16
|
+
it. Each policy can inspect, transform, or drop the message. Use this to redact
|
|
17
|
+
sensitive fields, enforce a message schema, filter events, or add observability
|
|
18
|
+
to real-time traffic.
|
|
19
|
+
|
|
20
|
+
Messages are intercepted in both directions, configured independently:
|
|
21
|
+
|
|
22
|
+
- **`inbound`** policies process messages traveling from the client to your
|
|
23
|
+
backend.
|
|
24
|
+
- **`outbound`** policies process messages traveling from your backend to the
|
|
25
|
+
client.
|
|
26
|
+
|
|
27
|
+
:::note
|
|
28
|
+
|
|
29
|
+
The pipeline only intercepts **message** events. Connection lifecycle events are
|
|
30
|
+
handled automatically: when either side closes, the other side is closed, and
|
|
31
|
+
socket errors are logged and forwarded. There is no policy hook for `close` or
|
|
32
|
+
`error` events.
|
|
33
|
+
|
|
34
|
+
:::
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
Use the `webSocketPipelineHandler` export and add an `inbound` and/or `outbound`
|
|
39
|
+
array under `options.policies`. Each entry points to an exported function in one
|
|
40
|
+
of your project's modules.
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
"/my-websocket": {
|
|
44
|
+
"x-zuplo-path": {
|
|
45
|
+
"pathMode": "open-api"
|
|
46
|
+
},
|
|
47
|
+
"get": {
|
|
48
|
+
"summary": "WebSocket route with message interception",
|
|
49
|
+
"x-zuplo-route": {
|
|
50
|
+
"corsPolicy": "none",
|
|
51
|
+
"handler": {
|
|
52
|
+
"export": "webSocketPipelineHandler",
|
|
53
|
+
"module": "$import(@zuplo/runtime)",
|
|
54
|
+
"options": {
|
|
55
|
+
"rewritePattern": "https://myservice.com/websocket",
|
|
56
|
+
"policies": {
|
|
57
|
+
"inbound": [
|
|
58
|
+
{
|
|
59
|
+
"module": "$import(./modules/websocket-policies)",
|
|
60
|
+
"export": "redactInbound"
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"outbound": [
|
|
64
|
+
{
|
|
65
|
+
"module": "$import(./modules/websocket-policies)",
|
|
66
|
+
"export": "filterOutbound"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"policies": {
|
|
73
|
+
"inbound": []
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"operationId": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
:::caution{title="Two different policies blocks"}
|
|
82
|
+
|
|
83
|
+
The `policies` object inside `handler.options` configures the **message**
|
|
84
|
+
policies that run on each WebSocket frame. This is separate from the route-level
|
|
85
|
+
`policies` block (the `inbound` array next to `handler`), which configures the
|
|
86
|
+
standard request policies — such as [API Key](../policies/api-key-inbound.mdx)
|
|
87
|
+
or [Rate Limiting](../policies/rate-limit-inbound.mdx) — that run once during
|
|
88
|
+
the initial connection upgrade.
|
|
89
|
+
|
|
90
|
+
:::
|
|
91
|
+
|
|
92
|
+
The `rewritePattern` option behaves identically to the
|
|
93
|
+
[WebSocket Handler](./websocket-handler.mdx#handler-options), including
|
|
94
|
+
JavaScript string interpolation.
|
|
95
|
+
|
|
96
|
+
## Writing a message policy
|
|
97
|
+
|
|
98
|
+
A message policy is an exported function that matches the following signature:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { ZuploContext, ZuploRequest } from "@zuplo/runtime";
|
|
102
|
+
|
|
103
|
+
async function webSocketPolicy(
|
|
104
|
+
data: string,
|
|
105
|
+
target: WebSocket,
|
|
106
|
+
source: WebSocket,
|
|
107
|
+
request: ZuploRequest,
|
|
108
|
+
context: ZuploContext,
|
|
109
|
+
): Promise<unknown>;
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| Parameter | Description |
|
|
113
|
+
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
114
|
+
| `data` | The message payload. For text protocols this is a string; binary frames arrive in the platform's binary form (for example, an `ArrayBuffer`). For an `inbound` policy this is the message from the client; for an `outbound` policy it is the message from the backend. |
|
|
115
|
+
| `target` | The destination socket the message is being forwarded to. For `inbound` this is the backend connection; for `outbound` it is the client connection. |
|
|
116
|
+
| `source` | The socket the message originated from. Call `source.send(...)` to send a message back to the originator, such as an acknowledgement or error. |
|
|
117
|
+
| `request` | The original [`ZuploRequest`](../programmable-api/zuplo-request.mdx) from the connection upgrade. |
|
|
118
|
+
| `context` | The [`ZuploContext`](../programmable-api/zuplo-context.mdx) for the connection. |
|
|
119
|
+
|
|
120
|
+
The return value controls what happens next:
|
|
121
|
+
|
|
122
|
+
- **Return the data** (modified or unchanged) to forward it to `target`. When
|
|
123
|
+
multiple policies are configured, the return value is passed as `data` to the
|
|
124
|
+
next policy in the array.
|
|
125
|
+
- **Return `undefined`** to drop the message. It is not forwarded, and no
|
|
126
|
+
further policies run for that message.
|
|
127
|
+
|
|
128
|
+
Policies run in the order they appear in the `inbound` / `outbound` array, and
|
|
129
|
+
each policy may be asynchronous. If a policy throws, Zuplo logs the error and
|
|
130
|
+
drops the message.
|
|
131
|
+
|
|
132
|
+
## Example: redact fields from inbound messages
|
|
133
|
+
|
|
134
|
+
This inbound policy parses each JSON message from the client, removes a
|
|
135
|
+
sensitive field, and forwards the result to the backend.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { ZuploContext, ZuploRequest } from "@zuplo/runtime";
|
|
139
|
+
|
|
140
|
+
export async function redactInbound(
|
|
141
|
+
data: string,
|
|
142
|
+
target: WebSocket,
|
|
143
|
+
source: WebSocket,
|
|
144
|
+
request: ZuploRequest,
|
|
145
|
+
context: ZuploContext,
|
|
146
|
+
) {
|
|
147
|
+
let message: Record<string, unknown>;
|
|
148
|
+
try {
|
|
149
|
+
message = JSON.parse(data);
|
|
150
|
+
} catch (err) {
|
|
151
|
+
context.log.warn("Dropping non-JSON WebSocket message");
|
|
152
|
+
return undefined; // drop messages that aren't valid JSON
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
delete message.ssn;
|
|
156
|
+
|
|
157
|
+
return JSON.stringify(message);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Example: filter outbound messages
|
|
162
|
+
|
|
163
|
+
This outbound policy inspects messages from the backend and drops internal
|
|
164
|
+
events so they never reach the client. Other messages pass through unchanged.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { ZuploContext, ZuploRequest } from "@zuplo/runtime";
|
|
168
|
+
|
|
169
|
+
export async function filterOutbound(
|
|
170
|
+
data: string,
|
|
171
|
+
target: WebSocket,
|
|
172
|
+
source: WebSocket,
|
|
173
|
+
request: ZuploRequest,
|
|
174
|
+
context: ZuploContext,
|
|
175
|
+
) {
|
|
176
|
+
const message = JSON.parse(data);
|
|
177
|
+
|
|
178
|
+
if (message.type === "internal") {
|
|
179
|
+
return undefined; // drop internal events; the client never sees them
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return data;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
You can configure multiple policies in each direction to compose behavior — for
|
|
187
|
+
example, one policy to validate a message against a schema and a second to
|
|
188
|
+
redact fields. Because each policy receives the previous policy's output, order
|
|
189
|
+
matters.
|
|
@@ -10,9 +10,8 @@ description: |
|
|
|
10
10
|
|
|
11
11
|
:::note{title="Beta"}
|
|
12
12
|
|
|
13
|
-
Cross App Access support is in beta and
|
|
14
|
-
|
|
15
|
-
model and policy options may change before general availability.
|
|
13
|
+
Cross App Access support is in beta. The configuration model and policy options
|
|
14
|
+
may change before general availability.
|
|
16
15
|
|
|
17
16
|
:::
|
|
18
17
|
|
|
@@ -7,15 +7,6 @@ description:
|
|
|
7
7
|
analytics.
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
:::note{title="Beta"}
|
|
11
|
-
|
|
12
|
-
The MCP Gateway is in beta. The configuration model and APIs may change before
|
|
13
|
-
general availability. Build with it, share feedback — just pin a
|
|
14
|
-
[compatibility date](./code-config/compatibility-dates.mdx) and expect the
|
|
15
|
-
occasional rough edge.
|
|
16
|
-
|
|
17
|
-
:::
|
|
18
|
-
|
|
19
10
|
The Zuplo MCP Gateway fronts one or more remote
|
|
20
11
|
[Model Context Protocol](https://modelcontextprotocol.io) (MCP) servers with a
|
|
21
12
|
single, OAuth-protected endpoint that AI clients connect to. Users sign in once
|
package/docs/policies/_index.md
CHANGED
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
| sleep-inbound | Sleep / Delay | Add a delay to the incoming request. Useful for testing. | api-gateway |
|
|
100
100
|
| stripe-webhook-verification-inbound | Stripe Webhook Auth | The Stripe Webhook policy validates the authenticity of an incoming Stripe webhook. | api-gateway |
|
|
101
101
|
| supabase-jwt-auth-inbound | Supabase JWT Auth | The Supabase JWT Authentication policy supports user JWT tokens created by Supabase. | api-gateway |
|
|
102
|
+
| traffic-splitting-inbound | Traffic Splitting | Splits traffic randomly across a set of weighted base paths. On each request one base path is selected (weighted by `weight`) and written to the request custom context at `customOutputProperty`. Reference it from a later URL Rewrite `rewritePattern` or URL Forward `baseUrl`, e.g. `${context.custom.trafficSplitting.basePath}`. | api-gateway |
|
|
102
103
|
| transform-body-inbound | Transform Request Body | Transform the body of an incoming request. | api-gateway |
|
|
103
104
|
| transform-body-outbound | Transform Response Body | Transform the body of an outgoing response. | api-gateway |
|
|
104
105
|
| upstream-azure-ad-service-auth-inbound | Upstream Azure AD Service Auth | Uses Azure Active Directory to add an Authorization header to the request in order to authenticate requests using Azure identity. | api-gateway |
|
|
@@ -96,14 +96,16 @@
|
|
|
96
96
|
{
|
|
97
97
|
"rateLimitBy": "ip",
|
|
98
98
|
"requestsAllowed": 2,
|
|
99
|
-
"timeWindowMinutes": 1
|
|
99
|
+
"timeWindowMinutes": 1,
|
|
100
|
+
"mode": "async"
|
|
100
101
|
},
|
|
101
102
|
{
|
|
102
103
|
"rateLimitBy": "function",
|
|
103
104
|
"identifier": {
|
|
104
105
|
"export": "$import(./modules/my-module)",
|
|
105
106
|
"module": "default"
|
|
106
|
-
}
|
|
107
|
+
},
|
|
108
|
+
"mode": "async"
|
|
107
109
|
}
|
|
108
110
|
]
|
|
109
111
|
}
|
|
@@ -115,7 +117,8 @@
|
|
|
115
117
|
"options": {
|
|
116
118
|
"rateLimitBy": "ip",
|
|
117
119
|
"requestsAllowed": 2,
|
|
118
|
-
"timeWindowMinutes": 1
|
|
120
|
+
"timeWindowMinutes": 1,
|
|
121
|
+
"mode": "async"
|
|
119
122
|
}
|
|
120
123
|
},
|
|
121
124
|
{
|
|
@@ -126,7 +129,8 @@
|
|
|
126
129
|
"identifier": {
|
|
127
130
|
"export": "$import(./modules/my-module)",
|
|
128
131
|
"module": "default"
|
|
129
|
-
}
|
|
132
|
+
},
|
|
133
|
+
"mode": "async"
|
|
130
134
|
}
|
|
131
135
|
}
|
|
132
136
|
]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
On each request this policy selects one of the configured `basePaths` at random,
|
|
2
|
+
weighted by each entry's `weight`. Weights are relative — they do not need to
|
|
3
|
+
add up to 100. The selected URL is written to the request custom context at the
|
|
4
|
+
path given by `customOutputProperty`.
|
|
5
|
+
|
|
6
|
+
### Using the selected base path
|
|
7
|
+
|
|
8
|
+
The selected URL is stored on `context.custom` and is intended to be consumed by
|
|
9
|
+
a later handler on the same route. Reference it using the `customOutputProperty`
|
|
10
|
+
path you configured. For example, with
|
|
11
|
+
`"customOutputProperty": "trafficSplitting.basePath"`:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
// URL Rewrite handler
|
|
15
|
+
{
|
|
16
|
+
"handler": {
|
|
17
|
+
"export": "urlRewriteHandler",
|
|
18
|
+
"module": "$import(@zuplo/runtime)",
|
|
19
|
+
"options": {
|
|
20
|
+
"rewritePattern": "${context.custom.trafficSplitting.basePath}/users/${params.id}"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
// URL Forward handler
|
|
28
|
+
{
|
|
29
|
+
"handler": {
|
|
30
|
+
"export": "urlForwardHandler",
|
|
31
|
+
"module": "$import(@zuplo/runtime)",
|
|
32
|
+
"options": {
|
|
33
|
+
"baseUrl": "${context.custom.trafficSplitting.basePath}"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> The `redirect` handler's `location` is not interpolated — use the URL Rewrite
|
|
40
|
+
> or URL Forward handler to route to the selected base path.
|
|
41
|
+
|
|
42
|
+
### Only one value is in effect
|
|
43
|
+
|
|
44
|
+
`customOutputProperty` resolves to a single value. If more than one Traffic
|
|
45
|
+
Splitting policy on a route writes to the same property, the **last policy to
|
|
46
|
+
run wins** — its selection is the one the handler sees. In practice you should
|
|
47
|
+
configure a single Traffic Splitting policy per output property.
|
|
48
|
+
|
|
49
|
+
### Environment variables
|
|
50
|
+
|
|
51
|
+
Because each `url` is a string value, you can reference environment variables in
|
|
52
|
+
it, including mixed strings:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"basePaths": [
|
|
57
|
+
{ "url": "$env(STABLE_BASE_URL)", "weight": 90 },
|
|
58
|
+
{ "url": "$env(CANARY_BASE_URL)/v2", "weight": 10 }
|
|
59
|
+
],
|
|
60
|
+
"customOutputProperty": "trafficSplitting.basePath"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Logging the selection
|
|
65
|
+
|
|
66
|
+
Set `"logSelection": true` to log which base path was selected on each request.
|
|
67
|
+
This is off by default.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
The traffic splitting policy randomly distributes incoming requests across a set
|
|
2
|
+
of weighted base paths. It selects one base path per request and writes it to
|
|
3
|
+
the request custom context, where a URL Rewrite or URL Forward handler can use
|
|
4
|
+
it to route the request. This is useful for blue/green rollouts, canary
|
|
5
|
+
releases, or splitting traffic between backends.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft-07/schema",
|
|
3
|
+
"$id": "https://cdn.zuplo.com/policies/runtime/schemas/traffic-splitting-inbound.json",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"title": "Traffic Splitting",
|
|
6
|
+
"isDeprecated": false,
|
|
7
|
+
"isPaidAddOn": false,
|
|
8
|
+
"isEnterprise": false,
|
|
9
|
+
"isInternal": false,
|
|
10
|
+
"isBeta": false,
|
|
11
|
+
"isHidden": false,
|
|
12
|
+
"requiresAI": false,
|
|
13
|
+
"products": ["api-gateway"],
|
|
14
|
+
"description": "Splits traffic randomly across a set of weighted base paths. On each request one base path is selected (weighted by `weight`) and written to the request custom context at `customOutputProperty`. Reference it from a later URL Rewrite `rewritePattern` or URL Forward `baseUrl`, e.g. `${context.custom.trafficSplitting.basePath}`.",
|
|
15
|
+
"deprecatedMessage": "",
|
|
16
|
+
"required": ["handler"],
|
|
17
|
+
"properties": {
|
|
18
|
+
"handler": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"default": {},
|
|
21
|
+
"required": ["export", "module", "options"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"export": {
|
|
24
|
+
"const": "TrafficSplittingInboundPolicy",
|
|
25
|
+
"description": "The name of the exported type"
|
|
26
|
+
},
|
|
27
|
+
"module": {
|
|
28
|
+
"const": "$import(@zuplo/runtime)",
|
|
29
|
+
"description": "The module containing the policy"
|
|
30
|
+
},
|
|
31
|
+
"options": {
|
|
32
|
+
"title": "TrafficSplittingInboundPolicyOptions",
|
|
33
|
+
"type": "object",
|
|
34
|
+
"description": "The options for this policy.",
|
|
35
|
+
"additionalProperties": false,
|
|
36
|
+
"required": ["basePaths", "customOutputProperty"],
|
|
37
|
+
"properties": {
|
|
38
|
+
"basePaths": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"description": "The set of base paths (URLs) to split traffic across. One entry is selected at random per request, weighted by its `weight`.",
|
|
41
|
+
"items": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"additionalProperties": false,
|
|
44
|
+
"required": ["url", "weight"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"url": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"examples": ["https://api-v1.example.com"],
|
|
49
|
+
"description": "The base path (URL) to route to when this entry is selected. Supports environment variables, e.g. `$env(BASE_URL)/v2`."
|
|
50
|
+
},
|
|
51
|
+
"weight": {
|
|
52
|
+
"type": "number",
|
|
53
|
+
"minimum": 0,
|
|
54
|
+
"examples": [80],
|
|
55
|
+
"description": "The relative weight for this base path. Higher weights receive proportionally more traffic. Weights are relative and do not need to add up to 100."
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"customOutputProperty": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"pattern": "^[A-Za-z_$][A-Za-z0-9_$]*(\\.[A-Za-z_$][A-Za-z0-9_$]*)*$",
|
|
63
|
+
"examples": ["trafficSplitting.basePath"],
|
|
64
|
+
"description": "A simple dotted property path under the request custom context where the selected URL is written (e.g. `trafficSplitting.basePath`). Reference it later in a URL Rewrite `rewritePattern` or URL Forward `baseUrl` as `${context.custom.trafficSplitting.basePath}`. Only one value is in effect; if multiple Traffic Splitting policies write the same property, the last one to run wins. Array indexes and brackets are not allowed."
|
|
65
|
+
},
|
|
66
|
+
"logSelection": {
|
|
67
|
+
"type": "boolean",
|
|
68
|
+
"default": false,
|
|
69
|
+
"x-show-example": false,
|
|
70
|
+
"description": "When `true`, logs which base path was selected for each request. Defaults to `false`."
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"examples": [
|
|
74
|
+
{
|
|
75
|
+
"basePaths": [
|
|
76
|
+
{
|
|
77
|
+
"url": "https://api-v1.example.com",
|
|
78
|
+
"weight": 80
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"url": "https://api-v2.example.com",
|
|
82
|
+
"weight": 15
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"url": "$env(CANARY_BASE_URL)",
|
|
86
|
+
"weight": 5
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"customOutputProperty": "trafficSplitting.basePath",
|
|
90
|
+
"logSelection": true
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"examples": [
|
|
96
|
+
{
|
|
97
|
+
"export": "TrafficSplittingInboundPolicy",
|
|
98
|
+
"module": "$import(@zuplo/runtime)",
|
|
99
|
+
"options": {
|
|
100
|
+
"basePaths": [
|
|
101
|
+
{
|
|
102
|
+
"url": "https://api-v1.example.com",
|
|
103
|
+
"weight": 80
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"url": "https://api-v2.example.com",
|
|
107
|
+
"weight": 15
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"url": "$env(CANARY_BASE_URL)",
|
|
111
|
+
"weight": 5
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"customOutputProperty": "trafficSplitting.basePath",
|
|
115
|
+
"logSelection": true
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zuplo",
|
|
3
|
-
"version": "6.71.
|
|
3
|
+
"version": "6.71.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The programmable API Gateway",
|
|
6
6
|
"author": "Zuplo, Inc.",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"zuplo": "zuplo.js"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@zuplo/cli": "6.71.
|
|
23
|
-
"@zuplo/core": "6.71.
|
|
24
|
-
"@zuplo/runtime": "6.71.
|
|
22
|
+
"@zuplo/cli": "6.71.21",
|
|
23
|
+
"@zuplo/core": "6.71.21",
|
|
24
|
+
"@zuplo/runtime": "6.71.21",
|
|
25
25
|
"@zuplo/test": "1.4.0"
|
|
26
26
|
}
|
|
27
27
|
}
|