{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://raw.githubusercontent.com/Cedarflake/Cedarflake-Nami/main/packages/config/redirects.schema.json", "title": "Nami Redirect Slots Configuration", "description": "Schema for redirect and proxy rules consumed by the edge runtime.", "type": "object", "properties": { "Slots": { "$ref": "#/definitions/slots" }, "slots": { "$ref": "#/definitions/slots" }, "SLOT": { "$ref": "#/definitions/slots" } }, "additionalProperties": true, "oneOf": [ { "required": ["Slots"] }, { "required": ["slots"] }, { "required": ["SLOT"] } ], "definitions": { "slots": { "type": "object", "description": "Collection of redirect rules organised by path-based keys.", "patternProperties": { "^/.*$": { "$ref": "#/definitions/routeEntry" } }, "additionalProperties": { "$ref": "#/definitions/slots" } }, "routeEntry": { "description": "A route definition expressed as a string shortcut, object, or array of rules.", "oneOf": [ { "$ref": "#/definitions/routeString" }, { "$ref": "#/definitions/routeConfig" }, { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/routeItem" } } ] }, "routeItem": { "description": "Single route entry inside an array value.", "oneOf": [ { "$ref": "#/definitions/routeString" }, { "$ref": "#/definitions/routeConfig" } ] }, "routeString": { "type": "string", "minLength": 1, "description": "Shortcut form equivalent to a prefix redirect rule." }, "proxyHeaderOverrides": { "type": "object", "description": "Header overrides. String values set headers and null values remove them.", "maxProperties": 32, "propertyNames": { "pattern": "^[!#$%&'*+.^_`|~0-9A-Za-z-]+$" }, "additionalProperties": { "oneOf": [ { "type": "string", "maxLength": 8192, "pattern": "^[^\\u0000\\r\\n]*$" }, { "type": "null" } ] } }, "proxyOptions": { "type": "object", "description": "Optional overrides for the transparent single-upstream proxy.", "properties": { "timeoutSeconds": { "type": "integer", "minimum": 1, "maximum": 120, "description": "Maximum wait for the upstream redirect chain to return final response headers." }, "maxRequestBodyMegabytes": { "type": "number", "exclusiveMinimum": 0, "maximum": 100, "description": "Application-level request body limit in megabytes. Provider limits still apply." }, "requestHeaders": { "$ref": "#/definitions/proxyHeaderOverrides" }, "responseHeaders": { "$ref": "#/definitions/proxyHeaderOverrides" }, "redirects": { "type": "object", "properties": { "mode": { "type": "string", "enum": ["follow", "passthrough"] }, "maxHops": { "type": "integer", "minimum": 0, "maximum": 10 } }, "allOf": [ { "if": { "properties": { "mode": { "const": "passthrough" } }, "required": ["mode"] }, "then": { "not": { "required": ["maxHops"] } } } ], "additionalProperties": false }, "cookies": { "type": "object", "properties": { "mode": { "type": "string", "enum": ["rewrite-domain", "preserve", "strip"] } }, "additionalProperties": false } }, "additionalProperties": false }, "routeConfig": { "type": "object", "description": "Explicit redirect or proxy configuration.", "properties": { "analyticsId": { "type": "string", "format": "uuid", "description": "Stable identifier used to aggregate analytics across path or target edits." }, "description": { "type": "string", "maxLength": 500, "description": "Optional human-readable note shown by management interfaces. It does not affect routing." }, "proxyPolicy": { "type": "object", "deprecated": true, "description": "Retired field accepted temporarily for rollback compatibility. Runtime ignores it." }, "proxyOptions": { "$ref": "#/definitions/proxyOptions" }, "type": { "type": "string", "enum": ["prefix", "exact", "proxy"], "description": "Route matching mode." }, "target": { "type": "string", "minLength": 1, "description": "Destination URL that takes precedence over alias fields.", "format": "uri-reference" }, "to": { "type": "string", "minLength": 1, "description": "Alias for target.", "format": "uri-reference" }, "url": { "type": "string", "minLength": 1, "description": "Alias for target.", "format": "uri-reference" }, "appendPath": { "type": "boolean", "description": "Whether to append the unmatched suffix when using prefix or proxy routes." }, "status": { "description": "HTTP status code for non-proxy responses.", "oneOf": [ { "type": "integer", "minimum": 200, "maximum": 599 }, { "type": "string", "pattern": "^[2-5][0-9]{2}$" } ] }, "priority": { "description": "Lower numbers run first when multiple rules share a base path.", "oneOf": [ { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, { "type": "string", "pattern": "^-?[0-9]+$" } ] } }, "allOf": [ { "if": { "properties": { "type": { "const": "proxy" } }, "required": ["type"] }, "then": { "allOf": [ { "not": { "required": ["status"] } }, { "properties": { "target": { "pattern": "^[Hh][Tt][Tt][Pp][Ss]?://(?![^/?#]*@)" }, "to": { "pattern": "^[Hh][Tt][Tt][Pp][Ss]?://(?![^/?#]*@)" }, "url": { "pattern": "^[Hh][Tt][Tt][Pp][Ss]?://(?![^/?#]*@)" } } } ] } }, { "if": { "properties": { "type": { "const": "exact" } }, "required": ["type"] }, "then": { "not": { "required": ["appendPath"] } } }, { "if": { "not": { "properties": { "type": { "const": "proxy" } }, "required": ["type"] } }, "then": { "not": { "required": ["proxyOptions"] } } } ], "oneOf": [ { "required": ["target"], "not": { "anyOf": [ { "required": ["to"] }, { "required": ["url"] } ] } }, { "required": ["to"], "not": { "anyOf": [ { "required": ["target"] }, { "required": ["url"] } ] } }, { "required": ["url"], "not": { "anyOf": [ { "required": ["target"] }, { "required": ["to"] } ] } } ], "additionalProperties": false } } }