zuplo 6.72.13 → 6.72.15

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.
Files changed (58) hide show
  1. package/docs/articles/migrate-from-apigee.md +1 -1
  2. package/docs/articles/migrate-from-azure-apim.md +1 -1
  3. package/docs/articles/migrate-from-kong.md +4 -4
  4. package/docs/articles/waf-ddos-akamai.md +6 -6
  5. package/docs/articles/waf-ddos-aws-waf-shield.mdx +6 -6
  6. package/docs/articles/waf-ddos-fastly.mdx +6 -6
  7. package/docs/articles/waf-ddos.mdx +1 -1
  8. package/docs/concepts/authentication.mdx +2 -1
  9. package/docs/concepts/request-lifecycle.mdx +1 -1
  10. package/docs/policies/_index.md +1 -13
  11. package/docs/policies/ai-gateway-model-routing-v2-inbound/doc.md +162 -0
  12. package/docs/policies/ai-gateway-model-routing-v2-inbound/intro.md +19 -0
  13. package/docs/policies/ai-gateway-model-routing-v2-inbound/schema.json +263 -0
  14. package/docs/policies/graphql-cache-inbound/doc.md +1 -1
  15. package/package.json +4 -4
  16. package/docs/policies/ab-test-inbound/intro.md +0 -8
  17. package/docs/policies/ab-test-inbound/policy.ts +0 -14
  18. package/docs/policies/ab-test-inbound/schema.json +0 -27
  19. package/docs/policies/ab-test-outbound/intro.md +0 -8
  20. package/docs/policies/ab-test-outbound/policy.ts +0 -26
  21. package/docs/policies/ab-test-outbound/schema.json +0 -27
  22. package/docs/policies/acl-policy-inbound/intro.md +0 -5
  23. package/docs/policies/acl-policy-inbound/policy.ts +0 -32
  24. package/docs/policies/acl-policy-inbound/schema.json +0 -52
  25. package/docs/policies/archive-request-aws-s3-inbound/intro.md +0 -4
  26. package/docs/policies/archive-request-aws-s3-inbound/policy.ts +0 -58
  27. package/docs/policies/archive-request-aws-s3-inbound/schema.json +0 -68
  28. package/docs/policies/archive-request-azure-storage-inbound/doc.md +0 -31
  29. package/docs/policies/archive-request-azure-storage-inbound/intro.md +0 -4
  30. package/docs/policies/archive-request-azure-storage-inbound/policy.ts +0 -54
  31. package/docs/policies/archive-request-azure-storage-inbound/schema.json +0 -53
  32. package/docs/policies/archive-request-gcp-storage-inbound/doc.md +0 -63
  33. package/docs/policies/archive-request-gcp-storage-inbound/intro.md +0 -4
  34. package/docs/policies/archive-request-gcp-storage-inbound/policy.ts +0 -68
  35. package/docs/policies/archive-request-gcp-storage-inbound/schema.json +0 -47
  36. package/docs/policies/archive-response-aws-s3-outbound/intro.md +0 -2
  37. package/docs/policies/archive-response-aws-s3-outbound/policy.ts +0 -59
  38. package/docs/policies/archive-response-aws-s3-outbound/schema.json +0 -68
  39. package/docs/policies/archive-response-azure-storage-outbound/doc.md +0 -31
  40. package/docs/policies/archive-response-azure-storage-outbound/intro.md +0 -3
  41. package/docs/policies/archive-response-azure-storage-outbound/policy.ts +0 -54
  42. package/docs/policies/archive-response-azure-storage-outbound/schema.json +0 -53
  43. package/docs/policies/hmac-auth-inbound/doc.md +0 -30
  44. package/docs/policies/hmac-auth-inbound/intro.md +0 -10
  45. package/docs/policies/hmac-auth-inbound/policy.ts +0 -70
  46. package/docs/policies/hmac-auth-inbound/schema.json +0 -53
  47. package/docs/policies/ip-restriction-inbound/intro.md +0 -8
  48. package/docs/policies/ip-restriction-inbound/policy.ts +0 -40
  49. package/docs/policies/ip-restriction-inbound/schema.json +0 -58
  50. package/docs/policies/rbac-policy-inbound/intro.md +0 -3
  51. package/docs/policies/rbac-policy-inbound/policy.ts +0 -42
  52. package/docs/policies/rbac-policy-inbound/schema.json +0 -52
  53. package/docs/policies/transform-body-inbound/intro.md +0 -8
  54. package/docs/policies/transform-body-inbound/policy.ts +0 -16
  55. package/docs/policies/transform-body-inbound/schema.json +0 -27
  56. package/docs/policies/transform-body-outbound/intro.md +0 -8
  57. package/docs/policies/transform-body-outbound/policy.ts +0 -19
  58. package/docs/policies/transform-body-outbound/schema.json +0 -27
@@ -120,7 +120,7 @@ The following table maps common Apigee policies to Zuplo equivalents:
120
120
  | `ExtractVariables` | [Custom Code Policy](../policies/custom-code-inbound.md) |
121
121
  | `XMLToJSON` / `JSONToXML` | [XML to JSON](../policies/xml-to-json-outbound.md) or custom code |
122
122
  | `RaiseFault` | Custom code returning an error [Response](../programmable-api/http-problems.md) |
123
- | `AccessControl` | [IP Restriction](../policies/ip-restriction-inbound.md) |
123
+ | `AccessControl` | [Custom Code](../policies/custom-code-inbound.md) |
124
124
  | `CORS` | Built-in [CORS configuration](../programmable-api/custom-cors-policy.md) |
125
125
  | `JavaScript` callout | [Custom Code Policy](../policies/custom-code-inbound.md) (TypeScript) |
126
126
  | `ServiceCallout` | [Custom Code Policy](../policies/custom-code-inbound.md) using `fetch()` |
@@ -97,7 +97,7 @@ The following table maps common Azure APIM policies to Zuplo equivalents:
97
97
  | `quota` / `quota-by-key` | [Quota](../policies/quota-inbound.md) |
98
98
  | `validate-jwt` | [Open ID JWT Authentication](../policies/open-id-jwt-auth-inbound.md) |
99
99
  | `authentication-basic` | [Basic Authentication](../policies/basic-auth-inbound.md) |
100
- | `ip-filter` | [IP Restriction](../policies/ip-restriction-inbound.md) |
100
+ | `ip-filter` | [Custom Code](../policies/custom-code-inbound.md) |
101
101
  | `cors` | Built-in [CORS configuration](../programmable-api/custom-cors-policy.md) |
102
102
  | `json-to-xml` / `xml-to-json` | [XML to JSON](../policies/xml-to-json-outbound.md) or custom code |
103
103
  | `find-and-replace` | [Replace String](../policies/replace-string-outbound.md) |
@@ -145,13 +145,13 @@ The following table maps common Kong plugins to their Zuplo policy equivalents:
145
145
  | `basic-auth` | [Basic Authentication](../policies/basic-auth-inbound.md) |
146
146
  | `rate-limiting` | [Rate Limiting](../policies/rate-limit-inbound.md) |
147
147
  | `rate-limiting-advanced` | [Complex Rate Limiting](../policies/complex-rate-limit-inbound.md) |
148
- | `request-transformer` | [Transform Body](../policies/transform-body-inbound.md) |
149
- | `response-transformer` | [Transform Body Outbound](../policies/transform-body-outbound.md) |
148
+ | `request-transformer` | [Custom Code](../policies/custom-code-inbound.md) |
149
+ | `response-transformer` | [Custom Code](../policies/custom-code-outbound.md) |
150
150
  | `cors` | Built-in [CORS configuration](../programmable-api/custom-cors-policy.md) |
151
- | `ip-restriction` | [IP Restriction](../policies/ip-restriction-inbound.md) |
151
+ | `ip-restriction` | [Custom Code](../policies/custom-code-inbound.md) |
152
152
  | `request-size-limiting` | [Request Size Limit](../policies/request-size-limit-inbound.md) |
153
153
  | `request-validation` | [Request Validation](../policies/request-validation-inbound.md) |
154
- | `acl` | [ACL Policy](../policies/acl-policy-inbound.md) |
154
+ | `acl` | [Custom Code](../policies/custom-code-inbound.md) |
155
155
  | Custom Lua plugin | [Custom Code Policy](../policies/custom-code-inbound.md) (TypeScript) |
156
156
 
157
157
  ### Step 3: Translate plugin configuration
@@ -24,20 +24,20 @@ your API Gateway. This is a good way to ensure that only Akamai can access your
24
24
  API Gateway. However, as Akamai is a multi-tenant service, this method isn't
25
25
  sufficient to protect unauthorized traffic from hitting your API Gateway.
26
26
 
27
- In Zuplo, you can use the custom
28
- [IP Restriction policy](../policies/ip-restriction-inbound.mdx) to limit traffic
29
- to only the Akamai IP addresses. Copy the policy code from that page into a
30
- module in your project (for example, `modules/ip-restriction-inbound.ts`), then
27
+ In Zuplo, you can use a
28
+ [custom code policy](../policies/custom-code-inbound.mdx) to limit traffic to
29
+ only the Akamai IP addresses. Add a module in your project (for example,
30
+ `modules/ip-restriction.ts`) that allows only your permitted IP ranges, then
31
31
  configure the policy with the IP ranges that Akamai publishes for your account
32
32
  in Akamai Control Center.
33
33
 
34
34
  ```json
35
35
  {
36
36
  "name": "allow-akamai-only",
37
- "policyType": "ip-restriction-inbound",
37
+ "policyType": "custom-code-inbound",
38
38
  "handler": {
39
39
  "export": "default",
40
- "module": "$import(./modules/ip-restriction-inbound)",
40
+ "module": "$import(./modules/ip-restriction)",
41
41
  "options": {
42
42
  "allowedIpAddresses": ["23.32.0.0/11", "104.64.0.0/10"]
43
43
  }
@@ -26,20 +26,20 @@ way to ensure that only CloudFront can access your API Gateway. However, as
26
26
  CloudFront is available to any AWS customer, this method isn't sufficient to
27
27
  protect unauthorized traffic from hitting your API Gateway.
28
28
 
29
- In Zuplo, you can use the custom
30
- [IP Restriction policy](../policies/ip-restriction-inbound.mdx) to limit traffic
31
- to only the CloudFront IP addresses. Copy the policy code from that page into a
32
- module in your project (for example, `modules/ip-restriction-inbound.ts`), then
29
+ In Zuplo, you can use a
30
+ [custom code policy](../policies/custom-code-inbound.mdx) to limit traffic to
31
+ only the CloudFront IP addresses. Add a module in your project (for example,
32
+ `modules/ip-restriction.ts`) that allows only your permitted IP ranges, then
33
33
  configure the policy with the `CLOUDFRONT` ranges from the
34
34
  [AWS IP address ranges list](https://ip-ranges.amazonaws.com/ip-ranges.json).
35
35
 
36
36
  ```json
37
37
  {
38
38
  "name": "allow-cloudfront-only",
39
- "policyType": "ip-restriction-inbound",
39
+ "policyType": "custom-code-inbound",
40
40
  "handler": {
41
41
  "export": "default",
42
- "module": "$import(./modules/ip-restriction-inbound)",
42
+ "module": "$import(./modules/ip-restriction)",
43
43
  "options": {
44
44
  "allowedIpAddresses": ["13.32.0.0/15", "13.35.0.0/16"]
45
45
  }
@@ -27,20 +27,20 @@ your API Gateway. This is a good way to ensure that only Fastly can access your
27
27
  API Gateway. However, as Fastly is a multi-tenant service, this method isn't
28
28
  sufficient to protect unauthorized traffic from hitting your API Gateway.
29
29
 
30
- In Zuplo, you can use the custom
31
- [IP Restriction policy](../policies/ip-restriction-inbound.mdx) to limit traffic
32
- to only the Fastly IP addresses. Copy the policy code from that page into a
33
- module in your project (for example, `modules/ip-restriction-inbound.ts`), then
30
+ In Zuplo, you can use a
31
+ [custom code policy](../policies/custom-code-inbound.mdx) to limit traffic to
32
+ only the Fastly IP addresses. Add a module in your project (for example,
33
+ `modules/ip-restriction.ts`) that allows only your permitted IP ranges, then
34
34
  configure the policy with the address ranges from
35
35
  [Fastly's public IP list](https://api.fastly.com/public-ip-list).
36
36
 
37
37
  ```json
38
38
  {
39
39
  "name": "allow-fastly-only",
40
- "policyType": "ip-restriction-inbound",
40
+ "policyType": "custom-code-inbound",
41
41
  "handler": {
42
42
  "export": "default",
43
- "module": "$import(./modules/ip-restriction-inbound)",
43
+ "module": "$import(./modules/ip-restriction)",
44
44
  "options": {
45
45
  "allowedIpAddresses": ["151.101.0.0/16", "199.232.0.0/16"]
46
46
  }
@@ -31,7 +31,7 @@ Many common WAF functions can be implemented directly in Zuplo using policies,
31
31
  without the need for a separate WAF service:
32
32
 
33
33
  - **IP Restriction** - Block or allow requests from specific IP addresses using
34
- the [IP Restriction policy](../policies/ip-restriction-inbound.mdx)
34
+ a [custom code policy](../policies/custom-code-inbound.mdx)
35
35
  - **Geolocation Blocking** - Route or block requests based on country using
36
36
  [custom policies](../guides/geolocation-backend-routing.mdx)
37
37
  - **Rate Limiting** - Protect against abuse with built-in
@@ -79,7 +79,8 @@ users already authenticate with an identity provider.
79
79
  - [mTLS](../articles/securing-the-gateway-with-client-mtls.mdx) - Mutual TLS
80
80
  certificate authentication
81
81
  - [LDAP](../policies/ldap-auth-inbound.mdx) - LDAP directory authentication
82
- - [HMAC](../policies/hmac-auth-inbound.mdx) - Hash-based message authentication
82
+ - [HMAC](../policies/custom-code-inbound.mdx) - Hash-based message
83
+ authentication via a custom code policy
83
84
 
84
85
  ## Combining authentication methods
85
86
 
@@ -50,7 +50,7 @@ security headers, [logging](../articles/logging.mdx), analytics.
50
50
  | Validate request bodies | [Inbound policy](../policies/request-validation-inbound.mdx) |
51
51
  | Forward to a backend | [URL Forward Handler](../handlers/url-forward.mdx) |
52
52
  | Return custom responses | [Function Handler](../handlers/custom-handler.mdx) |
53
- | Transform response bodies | [Outbound policy](../policies/transform-body-outbound.mdx) |
53
+ | Transform response bodies | [Custom code policy](../policies/custom-code-outbound.mdx) |
54
54
  | Add headers to all responses | [Response hook](../programmable-api/hooks.mdx) |
55
55
  | Log every request | [Response final hook](../programmable-api/hooks.mdx) |
56
56
  | Normalize URLs before routing | [Pre-routing hook](../programmable-api/runtime-extensions.mdx) |
@@ -2,21 +2,14 @@
2
2
 
3
3
  | Policy ID | Name | Description | Products |
4
4
  | --- | --- | --- | --- |
5
- | ab-test-inbound | A/B Test Inbound | An A/B test policy is used to handle requests differently based on parameters such as user, ip, etc. | api-gateway |
6
- | ab-test-outbound | A/B Test Outbound | An A/B test policy is used to handle responses differently based on parameters such as user, ip, etc. | api-gateway |
7
- | acl-policy-inbound | Access Control List | The access control list inbound policy limits access to resources based on parameters on the authenticated user. | api-gateway |
8
5
  | set-query-params-inbound | Add or Set Query Parameters | Adds or sets query parameters on the incoming request. | api-gateway |
9
6
  | set-headers-inbound | Add or Set Request Headers | Adds or sets headers on the incoming request. | api-gateway |
7
+ | ai-gateway-model-routing-v2-inbound | AI Gateway Model Routing (v2) | Matches AI Gateway requests against curated allow lists or open block lists, then stores the winning `AIGatewayRouteTarget` for the route handler. | ai-gateway |
10
8
  | akamai-ai-firewall | Akamai AI Firewall | Akamai AI Firewall Inbound Policy | ai-gateway |
11
9
  | akamai-firewall-for-ai-outbound | Akamai Firewall for AI | Inspects each upstream response with Akamai's Firewall for AI detect API and replaces the response with a `403 Forbidden` if Akamai returns a `deny` rule. Useful behind AI-powered APIs to filter unsafe completions, sensitive data exposure, and toxic content before they reach the client. The body, headers, URL, and query string sent to Akamai are configurable; by default only the response body is captured. Bodies are read from a clone so the client still receives the original. | api-gateway |
12
10
  | akamai-firewall-for-ai-inbound | Akamai Firewall for AI | Inspects each incoming request with Akamai's Firewall for AI detect API and blocks the request if Akamai returns a `deny` rule. Useful in front of AI-powered APIs to filter prompt injection, jailbreaks, and other unsafe inputs before they reach the model. The body, headers, URL, and query string sent to Akamai are configurable; by default only the request body is captured. Bodies are read from a clone so the upstream handler still sees the original. | api-gateway |
13
11
  | amberflo-metering-inbound | Amberflo Metering / Billing | Amberflo is a usage metering and billing service. This policy allows you to send metering calls for each API to their meter ingest endpoint. | api-gateway |
14
12
  | api-key-inbound | API Key Authentication | Authenticates requests based on API Keys using Zuplo's built-in API key management. This policy validates API keys against Zuplo's key storage, caches results for performance, and automatically adds user information to authenticated requests. | api-gateway |
15
- | archive-request-aws-s3-inbound | Archive Request to AWS S3 | Archive the incoming request body to AWS S3 storage | api-gateway |
16
- | archive-request-azure-storage-inbound | Archive Request to Azure Storage | Archive the incoming request to Azure blob storage. | api-gateway |
17
- | archive-request-gcp-storage-inbound | Archive Request to GCP Storage | Archive the incoming request to Google Cloud Storage. | api-gateway |
18
- | archive-response-aws-s3-outbound | Archive Response to AWS S3 | Archive the outgoing response body to AWS S3 storage | api-gateway |
19
- | archive-response-azure-storage-outbound | Archive Response to Azure Storage | Archive the outgoing response to Azure blob storage. | api-gateway |
20
13
  | audit-log-inbound | Audit Logs | Capture detailed logs of requests for auditing purposes. The policy emits one structured CloudEvent per request, and user code can emit additional events via the static `log()` method. | api-gateway |
21
14
  | auth0-jwt-auth-inbound | Auth0 JWT Auth | Authenticate users using Auth0 issued JWT tokens. | api-gateway |
22
15
  | authzen-inbound | AuthZEN Authorization | Authorize requests using an AuthZEN compatible PDP | api-gateway |
@@ -48,9 +41,7 @@
48
41
  | graphql-complexity-limit-inbound | GraphQL Complexity Limit | Policy that limits the complexity and depth of GraphQL queries to prevent abuse. Protects your GraphQL API from expensive queries that could cause performance issues or denial of service attacks. | api-gateway |
49
42
  | graphql-disable-introspection-inbound | GraphQL Disable Introspection | Policy that disables GraphQL introspection queries in production. Introspection allows clients to discover the schema, which can be a security risk as it exposes your entire API structure. | api-gateway |
50
43
  | graphql-introspection-filter-outbound | GraphQL Introspection Filter | Filters GraphQL introspection responses to exclude specific types and fields. This policy intercepts GraphQL introspection query responses and removes configured types and fields from the schema. Useful for hiding internal types or sensitive fields from the public schema. | api-gateway |
51
- | hmac-auth-inbound | HMAC Auth | Authenticate requests using the HMAC-SHA256 authentication scheme. | api-gateway |
52
44
  | http-deprecation-outbound | HTTP Deprecation | Sets HTTP deprecation headers on the outgoing response following the IETF HTTP Deprecation Header standard. Supports the Deprecation, Sunset, and Link headers. | api-gateway |
53
- | ip-restriction-inbound | IP Restriction | Block or allow requests based on their IP address. | api-gateway |
54
45
  | validate-json-schema-inbound | JSON Body Validation (deprecated) | Validates the body of an incoming request based on a JSON schema. | api-gateway |
55
46
  | open-id-jwt-auth-inbound | JWT Auth | The Open ID JWT Authentication policy allows you to authenticate incoming requests using an Open ID compliant bearer token. | api-gateway |
56
47
  | jwt-scopes-inbound | JWT Scope Validation | Validates that the JWT token includes specific scopes | api-gateway |
@@ -82,7 +73,6 @@
82
73
  | query-param-to-header-inbound | Query Parameter to Header | Extracts a query parameter and sets it as a header in the request. | api-gateway |
83
74
  | quota-inbound | Quota | The Quota policy enables you to set monthly, weekly, daily or hourly quotas on your API. | api-gateway |
84
75
  | rate-limit-inbound | Rate Limiting | Rate limiting policy to control the number of requests to your API. Supports multiple identification strategies (by user, IP, header, etc.) and can operate in strict or async mode for different performance characteristics. | api-gateway |
85
- | rbac-policy-inbound | RBAC Authorization | The RBAC authorization inbound policy limits access to resources based on the roles of the authenticated user. | api-gateway |
86
76
  | readme-metrics-inbound | Readme Metrics | Readme is a developer documentation and API metrics company. This policy pushes logs to their API calls dashboard. | api-gateway |
87
77
  | remove-query-params-inbound | Remove Query Parameters | Remove query parameters from the incoming request | api-gateway |
88
78
  | remove-headers-inbound | Remove Request Headers | Remove headers from the incoming request. | api-gateway |
@@ -102,8 +92,6 @@
102
92
  | stripe-webhook-verification-inbound | Stripe Webhook Auth | The Stripe Webhook policy validates the authenticity of an incoming Stripe webhook. | api-gateway |
103
93
  | supabase-jwt-auth-inbound | Supabase JWT Auth | The Supabase JWT Authentication policy supports user JWT tokens created by Supabase. | api-gateway |
104
94
  | 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 |
105
- | transform-body-inbound | Transform Request Body | Transform the body of an incoming request. | api-gateway |
106
- | transform-body-outbound | Transform Response Body | Transform the body of an outgoing response. | api-gateway |
107
95
  | upstream-aws-federated-auth-inbound | Upstream AWS Federated Auth | Resolves AWS credentials with STS AssumeRoleWithWebIdentity using Zuplo's ambient OIDC identity — no AWS keys are stored anywhere. The role's trust policy must trust the Zuplo OIDC identity provider. Resolved credentials are registered on the request context for the AWS Lambda handler and custom code to sign upstream requests with `AwsClient.fromContext`. This policy does not itself sign or forward the request. | api-gateway |
108
96
  | upstream-aws-service-auth-inbound | Upstream AWS Service Auth | Resolves AWS credentials from static access keys (optionally exchanged for an IAM role's temporary credentials via STS AssumeRole) and registers them on the request context. The AWS Lambda handler and custom code read them with `AwsClient.fromContext` to sign upstream requests. This policy does not itself sign or forward the request. | api-gateway |
109
97
  | 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 |
@@ -0,0 +1,162 @@
1
+ # AI Gateway Model Routing (v2) Policy
2
+
3
+ The AI Gateway Model Routing (v2) policy applies declarative allow or block
4
+ rules to AI requests. Configured targets use `provider/model` form and split on
5
+ the first slash, so provider-specific model IDs can contain additional slashes.
6
+
7
+ ## Configuration
8
+
9
+ Set a non-empty `models` object containing `completions`, `embeddings`, or both.
10
+ Each capability uses exactly one mode:
11
+
12
+ - `allowList` is curated mode. Only listed `main` models are accepted, entry 0
13
+ is the default when the request omits `model`, and entries can include
14
+ `backup`, `fallbackTimeoutSeconds`, and `quotaFallback`.
15
+ - `blockList` is open-but-filtered mode. Any unblocked target can be requested,
16
+ but every request must include `model`; this mode has no defaults or
17
+ fallbacks.
18
+
19
+ Because Responses management operations such as `GET /v1/responses/{id}` and
20
+ `DELETE /v1/responses/{id}` have no request body, attach curated `allowList`
21
+ rules (or a custom routing policy that supplies an OpenAI selection) to those
22
+ operations. A `blockList` policy cannot select credentials for a bodyless
23
+ request because that mode intentionally has no default.
24
+
25
+ An allow-list entry can be a string shorthand or a full target object:
26
+
27
+ ```json
28
+ {
29
+ "name": "ai-gateway-model-routing-v2-inbound",
30
+ "policyType": "ai-gateway-model-routing-v2",
31
+ "handler": {
32
+ "export": "AIGatewayModelRoutingV2InboundPolicy",
33
+ "module": "$import(@zuplo/runtime)",
34
+ "options": {
35
+ "models": {
36
+ "completions": {
37
+ "allowList": [
38
+ "openai/gpt-5",
39
+ {
40
+ "main": "anthropic/claude-sonnet-4-6",
41
+ "backup": "openai/gpt-5-mini",
42
+ "fallbackTimeoutSeconds": 30,
43
+ "quotaFallback": "anthropic/claude-haiku-4-5"
44
+ }
45
+ ]
46
+ },
47
+ "embeddings": {
48
+ "blockList": ["openai/legacy-embedding-model"]
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ The first slash separates the provider from the model. Model IDs may contain
57
+ additional slashes, such as `my-fireworks/accounts/fireworks/models/llama-v3`.
58
+ Provider and model matching is case-insensitive. In curated mode the configured
59
+ casing is preserved when the request is sent upstream.
60
+
61
+ ## Request behavior
62
+
63
+ Clients can send a bare model name or `provider/model`. In curated mode, a bare
64
+ name selects the one allow-list `main` with that model name; an ambiguous name
65
+ receives a 400 response asking for `provider/model`. In block-list mode, bare
66
+ Chat Completions and Embeddings models use OpenAI, while native Messages and
67
+ Responses models use Anthropic and OpenAI respectively.
68
+
69
+ `/v1/embeddings` uses the `embeddings` rules; Chat Completions, Responses, and
70
+ Anthropic Messages use `completions` rules. A request containing `/` is treated
71
+ as `provider/model`, so model IDs containing slashes must include their
72
+ provider.
73
+
74
+ The pass-through routes are provider-native: `/v1/messages` accepts Anthropic
75
+ targets and `/v1/responses` accepts OpenAI targets. A request that explicitly
76
+ selects the wrong provider receives a 400 response. An incompatible entry-0
77
+ default is a policy configuration error.
78
+
79
+ ## Fallback behavior
80
+
81
+ When `backup` is configured, the gateway fails over after a retryable error or
82
+ after `fallbackTimeoutSeconds` (60 seconds by default). The timeout must be from
83
+ 1 through 300 seconds. `quotaFallback` independently selects another model after
84
+ a usage-limit-exceeded signal. Fallbacks do not chain through another allow-list
85
+ entry.
86
+
87
+ Retry and timeout backups apply to translated Chat Completions and Embeddings
88
+ requests. Native `/v1/messages` and `/v1/responses` requests are passed through
89
+ without retrying a `backup`; `AIGatewayModelRouting.set` still validates every
90
+ configured target and credential eagerly. A same-native-provider `quotaFallback`
91
+ can still serve those routes after a usage-limit-exceeded signal.
92
+
93
+ ## Write your own routing policy
94
+
95
+ Everything this policy does is built on two public primitives, so a custom
96
+ inbound policy can replace it entirely. The policy's job is to collapse its
97
+ allow list to one winning target and store it; custom code makes the same call
98
+ with whatever logic it wants:
99
+
100
+ - `AIGatewayModels.load(context)` returns the cached provider catalog, including
101
+ each model's capability, status, and per-token pricing.
102
+ - `AIGatewayModelRouting.set(context, routing)` validates the routing, resolves
103
+ provider credentials internally, and stores the selection that the AI Gateway
104
+ handler consumes.
105
+
106
+ A per-capability target is the same `AIGatewayRouteTarget` shape used by
107
+ `allowList` entries: a `"provider/model"` string, or an object with `main` and
108
+ optional `backup`, `fallbackTimeoutSeconds`, and `quotaFallback`.
109
+
110
+ ```typescript
111
+ import {
112
+ AIGatewayModelRouting,
113
+ AIGatewayModels,
114
+ type ZuploContext,
115
+ type ZuploRequest,
116
+ } from "@zuplo/runtime";
117
+
118
+ export default async function routeModel(
119
+ request: ZuploRequest,
120
+ context: ZuploContext
121
+ ) {
122
+ const providers = await AIGatewayModels.load(context);
123
+ const openAI = providers.find((provider) => provider.name === "openai");
124
+ const model = openAI?.models.find(
125
+ (candidate) =>
126
+ candidate.capability === "completions" && candidate.status === "active"
127
+ );
128
+ if (!model) {
129
+ throw new Error("No active OpenAI completions model is available");
130
+ }
131
+ await AIGatewayModelRouting.set(context, {
132
+ completions: {
133
+ main: `openai/${model.model}`,
134
+ backup: "anthropic/claude-sonnet-4-6",
135
+ fallbackTimeoutSeconds: 30,
136
+ },
137
+ });
138
+ return request;
139
+ }
140
+ ```
141
+
142
+ Attach the module as an ordinary inbound policy on the AI Gateway route instead
143
+ of (or before) the built-in model-routing policy:
144
+
145
+ ```json
146
+ {
147
+ "name": "my-model-routing-inbound",
148
+ "policyType": "custom-code-inbound",
149
+ "handler": {
150
+ "export": "default",
151
+ "module": "$import(./modules/my-model-routing)"
152
+ }
153
+ }
154
+ ```
155
+
156
+ `AIGatewayModelRouting.get(context)` returns the sanitized, normalized routing
157
+ set for the current request; it never returns credentials. The AI Gateway
158
+ handler consumes this selection even when the built-in model-routing policy is
159
+ not attached to the route. Prefer one routing policy per route. If you compose
160
+ policies intentionally, a custom policy before the built-in policy wins because
161
+ the built-in policy preserves an existing selection. A custom policy after it
162
+ can replace an allowed selection, while a built-in rejection stops the chain.
@@ -0,0 +1,19 @@
1
+ The AI Gateway Model Routing (v2) policy selects models with either a curated
2
+ `allowList` or an open-but-filtered `blockList`. Allow-list entries accept the
3
+ string shorthand `"provider/model"` or an object with `main`, `backup`,
4
+ `fallbackTimeoutSeconds`, and `quotaFallback`; entry zero is the default when a
5
+ curated request omits `model`, while block-list mode requires every request to
6
+ name a model.
7
+
8
+ Request model references split on the first slash, match provider and model
9
+ case-insensitively, and preserve configured casing upstream. Clients may send a
10
+ bare model name: curated rules resolve a unique allow-list match, while open
11
+ rules default to OpenAI except on Anthropic-native Messages routes. Bodyless
12
+ Responses management operations need curated or custom routing because
13
+ block-list mode has no default. Retry backups apply to translated Chat
14
+ Completions and Embeddings, not native pass-through routes; quota fallbacks
15
+ remain independent and fallbacks do not chain.
16
+
17
+ Custom inbound policies can inspect `AIGatewayModels.load(context)` and call
18
+ `AIGatewayModelRouting.set(context, routing)` to select the same target without
19
+ attaching the built-in policy. This policy is in beta.