Skip to content

Commit 23ddb55

Browse files
authored
feat: support standard webhook delivery mode (#519)
* feat: destwebhookstandard * chore: destination webhook mode * fix: metadata.json * fix: destination type * test: verify delivery using official standard-webhooks sdk * feat: configurable webhook header prefix * docs: generate config * fix: prevent response body from being consumed twice in webhook error handling When webhook requests fail (status >= 400), the response body was being read twice - once with io.ReadAll() and again in parseResponse(). Since HTTP response bodies are streams, the second read would get an empty result, causing delivery.Response to have an empty body instead of the actual error message. This fix removes the duplicate read and lets parseResponse() handle all body reading. The parsed body is then extracted from delivery.Response for error metadata. Affects: - internal/destregistry/providers/destwebhook/destwebhook.go - internal/destregistry/providers/destwebhookstandard/destwebhookstandard.go Impact: Failed webhook deliveries will now correctly capture and display the actual error response body from endpoints, improving debuggability. Or a more concise version: fix: prevent double-read of webhook response body on error Response body was consumed twice in error path (status >= 400): first by io.ReadAll(), then by parseResponse(). This caused empty bodies in delivery responses, hiding actual error messages. Fixed by removing the first read and extracting the body from delivery.Response after parseResponse() completes. Fixes both destwebhook and destwebhookstandard providers. * chore: update metadata.json to be consistent with webhook destination
1 parent a62b2a7 commit 23ddb55

File tree

15 files changed

+2020
-51
lines changed

15 files changed

+2020
-51
lines changed

docs/pages/references/configuration.mdx

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,17 @@ Global configurations are provided through env variables or a YAML file. ConfigM
4747
| `DESTINATIONS_AWS_KINESIS_METADATA_IN_PAYLOAD` | If true, includes Outpost metadata (event ID, topic, etc.) within the Kinesis record payload. | `true` | No |
4848
| `DESTINATIONS_INCLUDE_MILLISECOND_TIMESTAMP` | If true, includes a 'timestamp-ms' field with millisecond precision in destination metadata. Useful for load testing and debugging. | `false` | No |
4949
| `DESTINATIONS_METADATA_PATH` | Path to the directory containing custom destination type definitions. This can be overridden by the root-level 'destination_metadata_path' if also set. | `config/outpost/destinations` | No |
50-
| `DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_EVENT_ID_HEADER` | If true, disables adding the default 'X-Outpost-Event-Id' header to webhook requests. | `false` | No |
51-
| `DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_SIGNATURE_HEADER` | If true, disables adding the default 'X-Outpost-Signature' header to webhook requests. | `false` | No |
52-
| `DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TIMESTAMP_HEADER` | If true, disables adding the default 'X-Outpost-Timestamp' header to webhook requests. | `false` | No |
53-
| `DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TOPIC_HEADER` | If true, disables adding the default 'X-Outpost-Topic' header to webhook requests. | `false` | No |
54-
| `DESTINATIONS_WEBHOOK_HEADER_PREFIX` | Prefix for custom headers added to webhook requests (e.g., 'X-MyOrg-'). | `x-outpost-` | No |
50+
| `DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_EVENT_ID_HEADER` | If true, disables adding the default 'X-Outpost-Event-Id' header to webhook requests. Only applies to 'default' mode. | `false` | No |
51+
| `DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_SIGNATURE_HEADER` | If true, disables adding the default 'X-Outpost-Signature' header to webhook requests. Only applies to 'default' mode. | `false` | No |
52+
| `DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TIMESTAMP_HEADER` | If true, disables adding the default 'X-Outpost-Timestamp' header to webhook requests. Only applies to 'default' mode. | `false` | No |
53+
| `DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TOPIC_HEADER` | If true, disables adding the default 'X-Outpost-Topic' header to webhook requests. Only applies to 'default' mode. | `false` | No |
54+
| `DESTINATIONS_WEBHOOK_HEADER_PREFIX` | Prefix for metadata headers added to webhook requests. Defaults to 'x-outpost-' in 'default' mode and 'webhook-' in 'standard' mode. | `x-outpost-` | No |
55+
| `DESTINATIONS_WEBHOOK_MODE` | Webhook mode: 'default' for customizable webhooks or 'standard' for Standard Webhooks specification compliance. Defaults to 'default'. | `nil` | No |
5556
| `DESTINATIONS_WEBHOOK_PROXY_URL` | Proxy URL for routing webhook requests through a proxy server. Supports HTTP and HTTPS proxies. When configured, all outgoing webhook traffic will be routed through the specified proxy. | `nil` | No |
56-
| `DESTINATIONS_WEBHOOK_SIGNATURE_ALGORITHM` | Algorithm used for signing webhook requests (e.g., 'hmac-sha256'). | `hmac-sha256` | No |
57-
| `DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE` | Go template for constructing the content to be signed for webhook requests. | `{{.Timestamp.Unix}}.{{.Body}}` | No |
58-
| `DESTINATIONS_WEBHOOK_SIGNATURE_ENCODING` | Encoding for the signature (e.g., 'hex', 'base64'). | `hex` | No |
59-
| `DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE` | Go template for the value of the signature header. | `t={{.Timestamp.Unix}},v0={{.Signatures \| join ","}}` | No |
57+
| `DESTINATIONS_WEBHOOK_SIGNATURE_ALGORITHM` | Algorithm used for signing webhook requests (e.g., 'hmac-sha256'). Only applies to 'default' mode. | `hmac-sha256` | No |
58+
| `DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE` | Go template for constructing the content to be signed for webhook requests. Only applies to 'default' mode. | `{{.Timestamp.Unix}}.{{.Body}}` | No |
59+
| `DESTINATIONS_WEBHOOK_SIGNATURE_ENCODING` | Encoding for the signature (e.g., 'hex', 'base64'). Only applies to 'default' mode. | `hex` | No |
60+
| `DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE` | Go template for the value of the signature header. Only applies to 'default' mode. | `t={{.Timestamp.Unix}},v0={{.Signatures \| join ","}}` | No |
6061
| `DESTINATION_METADATA_PATH` | Path to the directory containing custom destination type definitions. Overrides 'destinations.metadata_path' if set. | `nil` | No |
6162
| `DISABLE_TELEMETRY` | Global flag to disable all telemetry (anonymous usage statistics to Hookdeck and error reporting to Sentry). If true, overrides 'telemetry.disabled'. | `false` | No |
6263
| `GCP_PUBSUB_DELIVERY_SUBSCRIPTION` | Name of the GCP Pub/Sub subscription for delivery events. | `outpost-delivery-sub` | No |
@@ -186,34 +187,37 @@ destinations:
186187

187188
# Configuration specific to webhook destinations.
188189
webhook:
189-
# If true, disables adding the default 'X-Outpost-Event-Id' header to webhook requests.
190+
# If true, disables adding the default 'X-Outpost-Event-Id' header to webhook requests. Only applies to 'default' mode.
190191
disable_default_event_id_header: false
191192

192-
# If true, disables adding the default 'X-Outpost-Signature' header to webhook requests.
193+
# If true, disables adding the default 'X-Outpost-Signature' header to webhook requests. Only applies to 'default' mode.
193194
disable_default_signature_header: false
194195

195-
# If true, disables adding the default 'X-Outpost-Timestamp' header to webhook requests.
196+
# If true, disables adding the default 'X-Outpost-Timestamp' header to webhook requests. Only applies to 'default' mode.
196197
disable_default_timestamp_header: false
197198

198-
# If true, disables adding the default 'X-Outpost-Topic' header to webhook requests.
199+
# If true, disables adding the default 'X-Outpost-Topic' header to webhook requests. Only applies to 'default' mode.
199200
disable_default_topic_header: false
200201

201-
# Prefix for custom headers added to webhook requests (e.g., 'X-MyOrg-').
202+
# Prefix for metadata headers added to webhook requests. Defaults to 'x-outpost-' in 'default' mode and 'webhook-' in 'standard' mode.
202203
header_prefix: "x-outpost-"
203204

205+
# Webhook mode: 'default' for customizable webhooks or 'standard' for Standard Webhooks specification compliance. Defaults to 'default'.
206+
mode: ""
207+
204208
# Proxy URL for routing webhook requests through a proxy server. Supports HTTP and HTTPS proxies. When configured, all outgoing webhook traffic will be routed through the specified proxy.
205209
proxy_url: ""
206210

207-
# Algorithm used for signing webhook requests (e.g., 'hmac-sha256').
211+
# Algorithm used for signing webhook requests (e.g., 'hmac-sha256'). Only applies to 'default' mode.
208212
signature_algorithm: "hmac-sha256"
209213

210-
# Go template for constructing the content to be signed for webhook requests.
214+
# Go template for constructing the content to be signed for webhook requests. Only applies to 'default' mode.
211215
signature_content_template: "{{.Timestamp.Unix}}.{{.Body}}"
212216

213-
# Encoding for the signature (e.g., 'hex', 'base64').
217+
# Encoding for the signature (e.g., 'hex', 'base64'). Only applies to 'default' mode.
214218
signature_encoding: "hex"
215219

216-
# Go template for the value of the signature header.
220+
# Go template for the value of the signature header. Only applies to 'default' mode.
217221
signature_header_template: "t={{.Timestamp.Unix}},v0={{.Signatures | join \",\"}}"
218222

219223

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ require (
4242
github.com/redis/go-redis/v9 v9.6.1
4343
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
4444
github.com/spf13/viper v1.19.0
45+
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20250711233419-a173a6c0125c
4546
github.com/stretchr/testify v1.10.0
4647
github.com/testcontainers/testcontainers-go v0.36.0
4748
github.com/testcontainers/testcontainers-go/modules/clickhouse v0.33.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,6 +1249,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
12491249
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
12501250
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
12511251
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
1252+
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20250711233419-a173a6c0125c h1:Mm99t6GdFMtZOwyyvu3q8gXeZX0sqnjvimTC9QCJwQc=
1253+
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20250711233419-a173a6c0125c/go.mod h1:L1MQhA6x4dn9r007T033lsaZMv9EmBAdXyU/+EF40fo=
12521254
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
12531255
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
12541256
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=

internal/config/destinations.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,27 @@ type DestinationWebhookConfig struct {
3838
// ProxyURL may contain authentication credentials (e.g., http://user:pass@proxy:8080)
3939
// and should be treated as sensitive.
4040
// TODO: Implement sensitive value handling - https://github.com/hookdeck/outpost/issues/480
41+
Mode string `yaml:"mode" env:"DESTINATIONS_WEBHOOK_MODE" desc:"Webhook mode: 'default' for customizable webhooks or 'standard' for Standard Webhooks specification compliance. Defaults to 'default'." required:"N"`
4142
ProxyURL string `yaml:"proxy_url" env:"DESTINATIONS_WEBHOOK_PROXY_URL" desc:"Proxy URL for routing webhook requests through a proxy server. Supports HTTP and HTTPS proxies. When configured, all outgoing webhook traffic will be routed through the specified proxy." required:"N"`
42-
HeaderPrefix string `yaml:"header_prefix" env:"DESTINATIONS_WEBHOOK_HEADER_PREFIX" desc:"Prefix for custom headers added to webhook requests (e.g., 'X-MyOrg-')." required:"N"`
43-
DisableDefaultEventIDHeader bool `yaml:"disable_default_event_id_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_EVENT_ID_HEADER" desc:"If true, disables adding the default 'X-Outpost-Event-Id' header to webhook requests." required:"N"`
44-
DisableDefaultSignatureHeader bool `yaml:"disable_default_signature_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_SIGNATURE_HEADER" desc:"If true, disables adding the default 'X-Outpost-Signature' header to webhook requests." required:"N"`
45-
DisableDefaultTimestampHeader bool `yaml:"disable_default_timestamp_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TIMESTAMP_HEADER" desc:"If true, disables adding the default 'X-Outpost-Timestamp' header to webhook requests." required:"N"`
46-
DisableDefaultTopicHeader bool `yaml:"disable_default_topic_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TOPIC_HEADER" desc:"If true, disables adding the default 'X-Outpost-Topic' header to webhook requests." required:"N"`
47-
SignatureContentTemplate string `yaml:"signature_content_template" env:"DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE" desc:"Go template for constructing the content to be signed for webhook requests." required:"N"`
48-
SignatureHeaderTemplate string `yaml:"signature_header_template" env:"DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE" desc:"Go template for the value of the signature header." required:"N"`
49-
SignatureEncoding string `yaml:"signature_encoding" env:"DESTINATIONS_WEBHOOK_SIGNATURE_ENCODING" desc:"Encoding for the signature (e.g., 'hex', 'base64')." required:"N"`
50-
SignatureAlgorithm string `yaml:"signature_algorithm" env:"DESTINATIONS_WEBHOOK_SIGNATURE_ALGORITHM" desc:"Algorithm used for signing webhook requests (e.g., 'hmac-sha256')." required:"N"`
43+
HeaderPrefix string `yaml:"header_prefix" env:"DESTINATIONS_WEBHOOK_HEADER_PREFIX" desc:"Prefix for metadata headers added to webhook requests. Defaults to 'x-outpost-' in 'default' mode and 'webhook-' in 'standard' mode." required:"N"`
44+
DisableDefaultEventIDHeader bool `yaml:"disable_default_event_id_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_EVENT_ID_HEADER" desc:"If true, disables adding the default 'X-Outpost-Event-Id' header to webhook requests. Only applies to 'default' mode." required:"N"`
45+
DisableDefaultSignatureHeader bool `yaml:"disable_default_signature_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_SIGNATURE_HEADER" desc:"If true, disables adding the default 'X-Outpost-Signature' header to webhook requests. Only applies to 'default' mode." required:"N"`
46+
DisableDefaultTimestampHeader bool `yaml:"disable_default_timestamp_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TIMESTAMP_HEADER" desc:"If true, disables adding the default 'X-Outpost-Timestamp' header to webhook requests. Only applies to 'default' mode." required:"N"`
47+
DisableDefaultTopicHeader bool `yaml:"disable_default_topic_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TOPIC_HEADER" desc:"If true, disables adding the default 'X-Outpost-Topic' header to webhook requests. Only applies to 'default' mode." required:"N"`
48+
SignatureContentTemplate string `yaml:"signature_content_template" env:"DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE" desc:"Go template for constructing the content to be signed for webhook requests. Only applies to 'default' mode." required:"N"`
49+
SignatureHeaderTemplate string `yaml:"signature_header_template" env:"DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE" desc:"Go template for the value of the signature header. Only applies to 'default' mode." required:"N"`
50+
SignatureEncoding string `yaml:"signature_encoding" env:"DESTINATIONS_WEBHOOK_SIGNATURE_ENCODING" desc:"Encoding for the signature (e.g., 'hex', 'base64'). Only applies to 'default' mode." required:"N"`
51+
SignatureAlgorithm string `yaml:"signature_algorithm" env:"DESTINATIONS_WEBHOOK_SIGNATURE_ALGORITHM" desc:"Algorithm used for signing webhook requests (e.g., 'hmac-sha256'). Only applies to 'default' mode." required:"N"`
5152
}
5253

5354
// toConfig converts WebhookConfig to the provider config - private since it's only used internally
5455
func (c *DestinationWebhookConfig) toConfig() *destregistrydefault.DestWebhookConfig {
56+
mode := c.Mode
57+
if mode == "" {
58+
mode = "default"
59+
}
5560
return &destregistrydefault.DestWebhookConfig{
61+
Mode: mode,
5662
ProxyURL: c.ProxyURL,
5763
HeaderPrefix: c.HeaderPrefix,
5864
DisableDefaultEventIDHeader: c.DisableDefaultEventIDHeader,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Webhook Configuration Instructions
2+
3+
To receive events from the webhook destination, you need to set up a webhook endpoint.
4+
5+
A webhook endpoint is a URL that you provide to an HTTP server. When an event is sent to the webhook destination, an HTTP POST request is made to the webhook endpoint with a JSON payload. Information such as the event type will be sent in the HTTP headers.
6+
7+
## Verifying Webhook Signatures
8+
9+
Webhooks include a cryptographic signature for security. To verify:
10+
11+
1. Extract the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers
12+
2. Construct the signed content: `${webhook-id}.${webhook-timestamp}.${raw_body}`
13+
3. Decode your `whsec_` secret (remove prefix and base64 decode)
14+
4. Compute HMAC-SHA256 signature and compare
15+
16+
Verification libraries are available at: https://github.com/standard-webhooks
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"type": "webhook",
3+
"config_fields": [
4+
{
5+
"key": "url",
6+
"type": "text",
7+
"label": "Webhook URL",
8+
"description": "The URL to send webhook events to via HTTP POST (Standard Webhooks compliant)",
9+
"required": true,
10+
"pattern": "^https?:\\/\\/[\\w\\-]+(?:\\.[\\w\\-]+)*(?::\\d{1,5})?(?:\\/[\\w\\-\\/\\.~:?#\\[\\]@!$&'\\(\\)*+,;=]*)?$"
11+
}
12+
],
13+
"credential_fields": [],
14+
"label": "Webhook",
15+
"link": "https://hookdeck.com/webhooks/guides/what-are-webhooks-how-they-work",
16+
"description": "Send events as webhooks (HTTP POST).",
17+
"icon": "<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M4.79861 14.4C3.91361 14.4 3.15917 14.088 2.53528 13.464C1.9115 12.84 1.59961 12.0854 1.59961 11.2C1.59961 10.6222 1.7385 10.0861 2.01628 9.59169C2.29405 9.09725 2.68294 8.71114 3.18294 8.43336C3.38294 8.31114 3.58572 8.30836 3.79128 8.42502C3.99683 8.54169 4.09961 8.71747 4.09961 8.95236C4.09961 9.0698 4.06905 9.17653 4.00794 9.27253C3.94683 9.36864 3.86628 9.44447 3.76628 9.50002C3.46628 9.68891 3.23017 9.93025 3.05794 10.224C2.88572 10.5179 2.79961 10.8432 2.79961 11.2C2.79961 11.7556 2.99405 12.2278 3.38294 12.6167C3.77183 13.0056 4.24405 13.2 4.79961 13.2C5.35517 13.2 5.82739 13.0056 6.21628 12.6167C6.60517 12.2278 6.79961 11.7556 6.79961 11.2C6.79961 11.0334 6.86072 10.8917 6.98294 10.775C7.10517 10.6584 7.24961 10.6 7.41628 10.6H10.6663C10.7329 10.5334 10.8135 10.4834 10.9079 10.45C11.0024 10.4167 11.0996 10.4 11.1996 10.4C11.4218 10.4 11.6107 10.4778 11.7663 10.6334C11.9218 10.7889 11.9996 10.9778 11.9996 11.2C11.9996 11.4222 11.9218 11.6111 11.7663 11.7667C11.6107 11.9222 11.4218 12 11.1996 12C11.0996 12 11.0024 11.9861 10.9079 11.9584C10.8135 11.9306 10.7329 11.8778 10.6663 11.8H7.94961C7.82739 12.5667 7.46628 13.1917 6.86628 13.675C6.26628 14.1584 5.57705 14.4 4.79861 14.4ZM4.79961 12C4.57739 12 4.3885 11.9222 4.23294 11.7667C4.07739 11.6111 3.99961 11.4222 3.99961 11.2C3.99961 11.0189 4.04961 10.8625 4.14961 10.7309C4.24961 10.5992 4.37739 10.5056 4.53294 10.45L6.16628 7.92102C5.84405 7.62925 5.60239 7.2778 5.44128 6.86669C5.28017 6.45558 5.19961 6.03336 5.19961 5.60002C5.19961 4.71469 5.51161 3.96002 6.13561 3.33602C6.75961 2.71202 7.51428 2.40002 8.39961 2.40002C9.12183 2.40002 9.76628 2.61669 10.3329 3.05002C10.8996 3.48336 11.2774 4.05002 11.4663 4.75002C11.5218 4.94002 11.4897 5.11252 11.3699 5.26752C11.2502 5.42252 11.0934 5.50002 10.8996 5.50002C10.7552 5.50002 10.6285 5.45202 10.5196 5.35602C10.4108 5.26014 10.3375 5.14147 10.2996 5.00002C10.1774 4.5778 9.94128 4.23891 9.59128 3.98336C9.24128 3.7278 8.84405 3.60002 8.39961 3.60002C7.84405 3.60002 7.37183 3.79447 6.98294 4.18336C6.59405 4.57225 6.39961 5.04447 6.39961 5.60002C6.39961 5.95558 6.48572 6.29169 6.65794 6.60836C6.83017 6.92502 7.07183 7.17225 7.38294 7.35002C7.50517 7.4278 7.5885 7.5278 7.63294 7.65002C7.67739 7.77225 7.66628 7.89447 7.59961 8.01669L5.59961 11.1334C5.59961 11.3667 5.52183 11.5695 5.36628 11.7417C5.21072 11.9139 5.02183 12 4.79961 12ZM11.1989 14.4C10.9216 14.4 10.6524 14.3667 10.3913 14.3C10.1302 14.2334 9.88294 14.1334 9.64961 14C9.37183 13.8445 9.27183 13.6195 9.34961 13.325C9.42739 13.0306 9.61628 12.8834 9.91628 12.8834C10.0052 12.8834 10.0885 12.8945 10.1663 12.9167C10.2441 12.9389 10.3218 12.9722 10.3996 13.0167C10.5218 13.0722 10.649 13.1167 10.7811 13.15C10.9133 13.1834 11.0528 13.2 11.1996 13.2C11.7552 13.2 12.2274 13.0056 12.6163 12.6167C13.0052 12.2278 13.1996 11.7556 13.1996 11.2C13.1996 10.6445 13.0052 10.1722 12.6163 9.78336C12.2274 9.39447 11.7552 9.20002 11.1996 9.20002C11.0218 9.20002 10.8496 9.21669 10.6829 9.25002C10.5163 9.28336 10.3607 9.35002 10.2163 9.45002C10.0941 9.53891 9.96072 9.56114 9.81628 9.51669C9.67183 9.47225 9.56072 9.3778 9.48294 9.23336L8.04961 6.33336C7.90517 6.26669 7.79405 6.16669 7.71628 6.03336C7.6385 5.90002 7.59961 5.75558 7.59961 5.60002C7.59961 5.3778 7.67739 5.18891 7.83294 5.03336C7.9885 4.8778 8.17739 4.80002 8.39961 4.80002C8.62183 4.80002 8.81072 4.8778 8.96628 5.03336C9.12183 5.18891 9.19961 5.3778 9.19961 5.60002C9.19961 5.62225 9.19683 5.64725 9.19128 5.67502C9.18572 5.7028 9.18294 5.7278 9.18294 5.75002L10.3663 8.11669C10.5107 8.09447 10.6496 8.06947 10.7829 8.04169C10.9163 8.01391 11.0552 8.00002 11.1996 8.00002C12.0849 8.00002 12.8396 8.31241 13.4636 8.93719C14.0876 9.56186 14.3996 10.3174 14.3996 11.2039C14.3996 12.0902 14.0876 12.8445 13.4634 13.4667C12.8393 14.0889 12.0845 14.4 11.1989 14.4Z\" fill=\"#7A786E\"/></svg>"
18+
}

0 commit comments

Comments
 (0)