@sponson/adapters 0.9.2 → 0.10.0
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/dist/contentful.d.ts +8 -0
- package/dist/contentful.js +308 -0
- package/dist/contentful.js.map +1 -0
- package/dist/http-adapter-auth.d.ts +5 -2
- package/dist/http-adapter-auth.js +24 -6
- package/dist/http-adapter-auth.js.map +1 -1
- package/dist/http-adapter-client.js +7 -1
- package/dist/http-adapter-client.js.map +1 -1
- package/dist/http-adapter-resource.js +16 -2
- package/dist/http-adapter-resource.js.map +1 -1
- package/dist/http-adapter-spec.d.ts +5 -0
- package/dist/http-adapter-spec.js +12 -1
- package/dist/http-adapter-spec.js.map +1 -1
- package/dist/http.d.ts +5 -2
- package/dist/http.js +5 -4
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/neon.js +4 -2
- package/dist/neon.js.map +1 -1
- package/dist/recipes.d.ts +7 -0
- package/dist/recipes.js +1 -1
- package/dist/recipes.js.map +1 -1
- package/package.json +3 -3
- package/recipes/ably.yaml +124 -0
- package/recipes/bugsnag.yaml +112 -0
- package/recipes/convex.yaml +144 -0
- package/recipes/firebase_hosting.yaml +107 -0
- package/recipes/mailgun.yaml +186 -0
- package/recipes/newrelic.yaml +108 -0
- package/recipes/rollbar.yaml +94 -0
- package/recipes/sanity.yaml +163 -0
- package/recipes/twilio.yaml +141 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# Mailgun API recipes: an account webhook and an inbound route per preview. Format and checklist:
|
|
3
|
+
# docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
|
|
4
|
+
provider: mailgun
|
|
5
|
+
title: Mailgun
|
|
6
|
+
category: email
|
|
7
|
+
verified_on: "2026-10-12"
|
|
8
|
+
docs:
|
|
9
|
+
- title: Mailgun API OpenAPI document (every operation and schema below)
|
|
10
|
+
url: https://documentation.mailgun.com/_bundle/docs/mailgun/api-reference/send/mailgun.yaml
|
|
11
|
+
- title: Authentication (HTTP Basic, user `api`)
|
|
12
|
+
url: https://documentation.mailgun.com/docs/mailgun/api-reference/authentication/
|
|
13
|
+
- title: Account Webhooks
|
|
14
|
+
url: https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/account-webhooks
|
|
15
|
+
- title: Create an account-level webhook
|
|
16
|
+
url: https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/account-webhooks/post-v1-webhooks
|
|
17
|
+
- title: Get account-level webhook by ID
|
|
18
|
+
url: https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/account-webhooks/get-v1-webhooks--webhook-id-
|
|
19
|
+
- title: Update an account-level webhook
|
|
20
|
+
url: https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/account-webhooks/put-v1-webhooks--webhook-id-
|
|
21
|
+
- title: Domain Webhooks (the v3 and v4 per-domain alternatives)
|
|
22
|
+
url: https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/domain-webhooks
|
|
23
|
+
- title: Routes
|
|
24
|
+
url: https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/routes
|
|
25
|
+
- title: Route actions
|
|
26
|
+
url: https://documentation.mailgun.com/docs/mailgun/user-manual/receive-forward-store/route-actions
|
|
27
|
+
api:
|
|
28
|
+
base_url: https://api.mailgun.net
|
|
29
|
+
base_url_env: MAILGUN_API_URL
|
|
30
|
+
auth: { basic: { user: api, password_env: MAILGUN_API_KEY } }
|
|
31
|
+
encoding: form
|
|
32
|
+
# Lists go as the key repeated (`action=…&action=…`, `event_types=…&event_types=…`): MG4.
|
|
33
|
+
form_arrays: repeat
|
|
34
|
+
credential:
|
|
35
|
+
url: "https://documentation.mailgun.com/docs/mailgun/api-reference/authentication/"
|
|
36
|
+
scope: "An account API key (Account Settings > API Keys): Domain Sending Keys 'only allow sending messages' and cannot manage webhooks or routes."
|
|
37
|
+
source: "https://documentation.mailgun.com/docs/mailgun/api-reference/authentication/"
|
|
38
|
+
verify: "GET /v1/webhooks"
|
|
39
|
+
detect:
|
|
40
|
+
deps: [mailgun.js, mailgun-js]
|
|
41
|
+
env: ["MAILGUN_*"]
|
|
42
|
+
starter:
|
|
43
|
+
- op: webhook
|
|
44
|
+
preview_url: url
|
|
45
|
+
values: { name: "sponson-${ctx.env}-${ctx.scope}" }
|
|
46
|
+
check: [path]
|
|
47
|
+
assumptions:
|
|
48
|
+
- id: MG1
|
|
49
|
+
verified: true
|
|
50
|
+
text: "Requests authenticate with HTTP Basic, the user name `api` and an API key as the password; the US API is `https://api.mailgun.net`, the EU one `https://api.eu.mailgun.net` (an EU account sets `base_url` in the provider block)."
|
|
51
|
+
source: https://documentation.mailgun.com/_bundle/docs/mailgun/api-reference/send/mailgun.yaml
|
|
52
|
+
- id: MG2
|
|
53
|
+
verified: true
|
|
54
|
+
text: "`POST /v1/webhooks` creates an account-level webhook from `url` (required), `event_types` (required, one of accepted, clicked, opened, unsubscribed, delivered, permanent_fail, temporary_fail, complained; repeated for several) and `description`, and answers `{ webhook_id }` only; it receives the events of every domain of the account. At most three URLs per event type (a fourth answers 409 'unable to add more than 3 urls for event type …'), so at most three previews (fewer when the account has its own webhooks) can each have one at a time."
|
|
55
|
+
source: https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/account-webhooks/post-v1-webhooks
|
|
56
|
+
- id: MG3
|
|
57
|
+
verified: true
|
|
58
|
+
text: "`GET /v1/webhooks` answers `{ webhooks: [...] }` and `GET /v1/webhooks/{webhook_id}` one webhook, each with `webhook_id`, `description`, `url`, `event_types` (a list) and `created_at`; `PUT /v1/webhooks/{webhook_id}` replaces url, description and event types whole (204), `DELETE` on the same path removes it (204), and an unknown id answers 404."
|
|
59
|
+
source: https://documentation.mailgun.com/_bundle/docs/mailgun/api-reference/send/mailgun.yaml
|
|
60
|
+
- id: MG4
|
|
61
|
+
verified: true
|
|
62
|
+
text: "Lists in request bodies are the key repeated: the OpenAPI document declares `action` with `style: form, explode: true` and says to use `event_types` 'multiple times to specify multiple event types', hence `form_arrays: repeat`."
|
|
63
|
+
source: https://documentation.mailgun.com/_bundle/docs/mailgun/api-reference/send/mailgun.yaml
|
|
64
|
+
- id: MG5
|
|
65
|
+
verified: false
|
|
66
|
+
text: "The account-webhook operations, documented as `multipart/form-data`, accept the same fields `application/x-www-form-urlencoded`, as Mailgun's v3 operations (documented so) do."
|
|
67
|
+
- id: MG6
|
|
68
|
+
verified: true
|
|
69
|
+
text: "Webhook changes 'can take up to 10 minutes to become effective due to caching': a new preview may miss its first events."
|
|
70
|
+
source: https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/account-webhooks
|
|
71
|
+
- id: MG7
|
|
72
|
+
verified: true
|
|
73
|
+
text: "Routes are account-wide ('defined globally, per account, not per domain'). `POST /v3/routes` takes `priority` (default 0, lower first), `description`, `expression` (required) and `action` (repeated), and answers `{ message, route }`; `GET /v3/routes/{id}` answers `{ route }` (404 when unknown); `GET /v3/routes` answers `{ total_count, items }`, `limit` up to 1000; `PUT /v3/routes/{id}` updates only the fields sent and answers `{ message, route }`; `DELETE /v3/routes/{id}` removes it. A route object carries `id`, `priority`, `description`, `expression`, `actions` (a list) and `created_at`."
|
|
74
|
+
source: https://documentation.mailgun.com/_bundle/docs/mailgun/api-reference/send/mailgun.yaml
|
|
75
|
+
- id: MG8
|
|
76
|
+
verified: true
|
|
77
|
+
text: "`forward(\"https://…\")` posts a matching message to the URL; every route is evaluated unless a higher-priority one runs `stop()`; `match_recipient('regex')` filters on the recipient. The receiving domain needs its MX records pointing at Mailgun."
|
|
78
|
+
source: https://documentation.mailgun.com/docs/mailgun/user-manual/receive-forward-store/route-actions
|
|
79
|
+
- id: MG9
|
|
80
|
+
verified: false
|
|
81
|
+
text: "The API answers `description`, `url`, `event_types`, `expression` and `actions` as they were written, so an unchanged webhook or route hashes the same on every plan, and a route's description (not required to be unique by Mailgun) or a webhook's identifies what this recipe made: two equal ones make `find` refuse with PARAM_INVALID."
|
|
82
|
+
- id: MG10
|
|
83
|
+
verified: false
|
|
84
|
+
text: "A per-domain webhook (v3 `…/domains/{domain}/webhooks/{event}`, a list of up to three URLs per event; v4 `…/webhooks?url=`, answered as a map of event to URLs) is not an object of its own that a later run can read back by an id, so this recipe uses account webhooks; the preview's handler must ignore events of mail it did not send (every webhook gets every domain's events)."
|
|
85
|
+
ops:
|
|
86
|
+
webhook:
|
|
87
|
+
kind: resource
|
|
88
|
+
title: Account webhook
|
|
89
|
+
summary: "An account-level webhook that posts the chosen email events to the preview's own URL, `url` + `path` (usually `{ from: web.preview_url }`). Identified by its description (`name`), so a new preview URL updates it in place. It receives every domain's events (MG10), and Mailgun takes at most three URLs per event type (MG2): at most three previews at a time. A console edit of its URL or events is drift."
|
|
90
|
+
covers: [mailgun-webhook-route]
|
|
91
|
+
params:
|
|
92
|
+
name:
|
|
93
|
+
type: string
|
|
94
|
+
required: true
|
|
95
|
+
pattern: "^[A-Za-z0-9_.:/ -]{1,200}$"
|
|
96
|
+
description: "The webhook's identity, kept as its description: unique per preview, such as `sponson-${ctx.env}-${ctx.scope}`."
|
|
97
|
+
example: "sponson-${ctx.env}-${ctx.scope}"
|
|
98
|
+
url:
|
|
99
|
+
type: string
|
|
100
|
+
required: true
|
|
101
|
+
pattern: "^https://\\S*[^/]$"
|
|
102
|
+
description: "The preview's base URL, without a trailing slash: usually `{ from: <deploy line>.preview_url }`."
|
|
103
|
+
example: https://pr-42.preview.example.com
|
|
104
|
+
path:
|
|
105
|
+
type: string
|
|
106
|
+
default: /api/webhooks/mailgun
|
|
107
|
+
pattern: "^/\\S*$"
|
|
108
|
+
description: "Where the app handles Mailgun's events, appended to `url`."
|
|
109
|
+
event_types:
|
|
110
|
+
type: list
|
|
111
|
+
default: [delivered, permanent_fail, complained]
|
|
112
|
+
description: "The events posted: accepted, clicked, opened, unsubscribed, delivered, permanent_fail, temporary_fail, complained (MG2)."
|
|
113
|
+
http:
|
|
114
|
+
find:
|
|
115
|
+
path: /v1/webhooks
|
|
116
|
+
list_path: /webhooks
|
|
117
|
+
match: { description: { param: name } }
|
|
118
|
+
read: { path: "/v1/webhooks/{id}" }
|
|
119
|
+
create: { path: /v1/webhooks, locate: true }
|
|
120
|
+
update: { method: PUT, path: "/v1/webhooks/{id}" }
|
|
121
|
+
id_path: /webhook_id
|
|
122
|
+
fields:
|
|
123
|
+
url: { join: [{ param: url }, { param: path }] }
|
|
124
|
+
event_types: { param: event_types }
|
|
125
|
+
route:
|
|
126
|
+
kind: resource
|
|
127
|
+
title: Inbound route
|
|
128
|
+
summary: "An inbound route per preview that forwards mail matching `expression` (such as `match_recipient('pr-42@inbound.example.com')`) to the preview's own URL, `url` + `path`. Identified by its description (`name`); a console edit of its priority, expression or action is drift. The receiving domain is long-lived and shared (MX records at Mailgun, MG8); each preview gets its own address on it."
|
|
129
|
+
covers: [mailgun-webhook-route]
|
|
130
|
+
params:
|
|
131
|
+
name:
|
|
132
|
+
type: string
|
|
133
|
+
required: true
|
|
134
|
+
pattern: "^[A-Za-z0-9_.:/ -]{1,200}$"
|
|
135
|
+
description: "The route's identity, kept as its description: unique per preview, such as `sponson-${ctx.env}-${ctx.scope}`."
|
|
136
|
+
example: "sponson-${ctx.env}-${ctx.scope}"
|
|
137
|
+
expression:
|
|
138
|
+
type: string
|
|
139
|
+
required: true
|
|
140
|
+
description: "The filter (MG8), such as `match_recipient('${ctx.scope}@inbound.example.com')`."
|
|
141
|
+
example: "match_recipient('${ctx.scope}@inbound.example.com')"
|
|
142
|
+
url:
|
|
143
|
+
type: string
|
|
144
|
+
required: true
|
|
145
|
+
pattern: "^https://\\S*[^/\"]$"
|
|
146
|
+
description: "The preview's base URL, without a trailing slash: usually `{ from: <deploy line>.preview_url }`."
|
|
147
|
+
example: https://pr-42.preview.example.com
|
|
148
|
+
path:
|
|
149
|
+
type: string
|
|
150
|
+
default: /api/inbound/mailgun
|
|
151
|
+
pattern: "^/[^\\s\"]*$"
|
|
152
|
+
description: "Where the app receives forwarded mail, appended to `url`."
|
|
153
|
+
priority:
|
|
154
|
+
type: integer
|
|
155
|
+
default: 0
|
|
156
|
+
description: "Lower runs first (MG7)."
|
|
157
|
+
http:
|
|
158
|
+
find:
|
|
159
|
+
path: "/v3/routes?limit=1000"
|
|
160
|
+
list_path: /items
|
|
161
|
+
match: { description: { param: name } }
|
|
162
|
+
read: { path: "/v3/routes/{id}" }
|
|
163
|
+
create:
|
|
164
|
+
path: /v3/routes
|
|
165
|
+
send_fields: false
|
|
166
|
+
body:
|
|
167
|
+
priority: { param: priority }
|
|
168
|
+
description: { param: name }
|
|
169
|
+
expression: { param: expression }
|
|
170
|
+
action: [{ join: ["forward(\"", { param: url }, { param: path }, "\")"] }]
|
|
171
|
+
update:
|
|
172
|
+
method: PUT
|
|
173
|
+
path: "/v3/routes/{id}"
|
|
174
|
+
send_fields: false
|
|
175
|
+
body:
|
|
176
|
+
priority: { param: priority }
|
|
177
|
+
description: { param: name }
|
|
178
|
+
expression: { param: expression }
|
|
179
|
+
action: [{ join: ["forward(\"", { param: url }, { param: path }, "\")"] }]
|
|
180
|
+
item_path: /route
|
|
181
|
+
fields:
|
|
182
|
+
priority: { param: priority }
|
|
183
|
+
expression: { param: expression }
|
|
184
|
+
actions: [{ join: ["forward(\"", { param: url }, { param: path }, "\")"] }]
|
|
185
|
+
sim:
|
|
186
|
+
write_fields: { action: actions }
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# New Relic NerdGraph recipes: a change-tracking deployment marker per release. Format and checklist:
|
|
3
|
+
# docs/adr/0020-recipes.md, docs/adr/0022-one-off-actions.md, CONTRIBUTING.md "Adding a recipe".
|
|
4
|
+
provider: newrelic
|
|
5
|
+
title: New Relic
|
|
6
|
+
category: observability
|
|
7
|
+
verified_on: "2026-10-12"
|
|
8
|
+
docs:
|
|
9
|
+
- title: Track changes with NerdGraph (changeTrackingCreateDeployment, changeTrackingCreateEvent)
|
|
10
|
+
url: https://docs.newrelic.com/docs/change-tracking/change-tracking-graphql/
|
|
11
|
+
- title: Introduction to NerdGraph (endpoints, the API-Key header)
|
|
12
|
+
url: https://docs.newrelic.com/docs/apis/nerdgraph/get-started/introduction-new-relic-nerdgraph/
|
|
13
|
+
- title: New Relic's Go client, the mutation as its CLI and Terraform provider send it (ChangeTrackingDeploymentInput)
|
|
14
|
+
url: https://github.com/newrelic/newrelic-client-go/blob/main/pkg/changetracking/changetracking_api.go
|
|
15
|
+
- title: User keys
|
|
16
|
+
url: https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/
|
|
17
|
+
api:
|
|
18
|
+
base_url: https://api.newrelic.com/graphql
|
|
19
|
+
base_url_env: NEW_RELIC_API_URL
|
|
20
|
+
auth: { header: API-Key, value_env: NEW_RELIC_API_KEY }
|
|
21
|
+
credential:
|
|
22
|
+
url: "https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/"
|
|
23
|
+
scope: "A user key (`NRAK-…`, API keys > Create a key > User) of a user who can create change tracking events for the entity's account."
|
|
24
|
+
source: "https://docs.newrelic.com/docs/apis/nerdgraph/get-started/introduction-new-relic-nerdgraph/"
|
|
25
|
+
detect:
|
|
26
|
+
deps: [newrelic, "@newrelic/"]
|
|
27
|
+
env: ["NEW_RELIC_*"]
|
|
28
|
+
starter:
|
|
29
|
+
- op: deployment
|
|
30
|
+
values: { version: "${ctx.git.sha}", description: "${ctx.env} ${ctx.scope}" }
|
|
31
|
+
where:
|
|
32
|
+
entity_guid: "the GUID of the APM (or browser) entity the environment reports as: the entity's metadata in New Relic, or `newrelic entity search`"
|
|
33
|
+
assumptions:
|
|
34
|
+
- id: NR1
|
|
35
|
+
verified: true
|
|
36
|
+
text: "NerdGraph is one GraphQL endpoint, `https://api.newrelic.com/graphql` (EU accounts: `https://api.eu.newrelic.com/graphql`, set `base_url` in the provider block), taking a user key in the `API-Key` header and a JSON body `{ query, variables }`."
|
|
37
|
+
source: https://docs.newrelic.com/docs/apis/nerdgraph/get-started/introduction-new-relic-nerdgraph/
|
|
38
|
+
- id: NR2
|
|
39
|
+
verified: true
|
|
40
|
+
text: "`changeTrackingCreateDeployment(deployment: ChangeTrackingDeploymentInput!)` records a deployment marker on an entity from `version` and `entityGuid` (both required) and optionally `user`, `description`, `deploymentType` (`BASIC`, `BLUE_GREEN`, `CANARY`, `ROLLING`, `SHADOW`, `OTHER`), `deepLink`, `commit`, `changelog`, `groupId` and `timestamp` (within 24 hours of now), and answers `deploymentId` and `entityGuid`. New Relic recommends `changeTrackingCreateEvent` for new work but says this mutation 'isn't being retired and continues to work'."
|
|
41
|
+
source: https://docs.newrelic.com/docs/change-tracking/change-tracking-graphql/
|
|
42
|
+
- id: NR3
|
|
43
|
+
verified: true
|
|
44
|
+
text: "The input type's name is `ChangeTrackingDeploymentInput`, as New Relic's own Go client declares the mutation's variable."
|
|
45
|
+
source: https://github.com/newrelic/newrelic-client-go/blob/main/pkg/changetracking/changetracking_api.go
|
|
46
|
+
- id: NR4
|
|
47
|
+
verified: false
|
|
48
|
+
text: "NerdGraph has no mutation that deletes or edits a deployment marker (the REST v2 deployment endpoints, which could delete one, reach end of life on 2027-07-31), so destroy sends nothing and forgets the record: a marker is history."
|
|
49
|
+
- id: NR5
|
|
50
|
+
verified: false
|
|
51
|
+
text: "NerdGraph takes no idempotency key: a marker sent again after a crash before Sponson recorded it is a second marker for the same version (harmless, at least once)."
|
|
52
|
+
- id: NR6
|
|
53
|
+
verified: false
|
|
54
|
+
text: "A preview that reports to its own entity (an app name per environment, such as `web (preview)`) gets its markers there; a preview sharing production's entity would mark production's charts, so give previews their own entity or leave this line to production."
|
|
55
|
+
ops:
|
|
56
|
+
deployment:
|
|
57
|
+
kind: action
|
|
58
|
+
title: Deployment marker
|
|
59
|
+
summary: "A change-tracking deployment marker on the environment's entity (`entity_guid`) for a release, sent once per entity and version (usually the commit). Nothing to undo: markers are history and NerdGraph deletes none (NR4)."
|
|
60
|
+
covers: [newrelic-deployment]
|
|
61
|
+
params:
|
|
62
|
+
entity_guid:
|
|
63
|
+
type: string
|
|
64
|
+
required: true
|
|
65
|
+
description: The GUID of the entity the environment reports as (NR6).
|
|
66
|
+
example: MXxBUE18QVBQTElDQVRJT058MTIzNDU2Nzg
|
|
67
|
+
version:
|
|
68
|
+
type: string
|
|
69
|
+
required: true
|
|
70
|
+
description: "The release's version, usually the commit: `\"${ctx.git.sha}\"`. A new one sends a new marker."
|
|
71
|
+
example: "${ctx.git.sha}"
|
|
72
|
+
description:
|
|
73
|
+
type: string
|
|
74
|
+
description: "Text shown with the marker, such as `preview pr-42`."
|
|
75
|
+
example: "${ctx.env} ${ctx.scope}"
|
|
76
|
+
user:
|
|
77
|
+
type: string
|
|
78
|
+
default: sponson
|
|
79
|
+
description: Who deployed.
|
|
80
|
+
commit:
|
|
81
|
+
type: string
|
|
82
|
+
description: The commit deployed.
|
|
83
|
+
deep_link:
|
|
84
|
+
type: string
|
|
85
|
+
pattern: "^https?://\\S+$"
|
|
86
|
+
description: A link to the deployment (the preview URL, or the CI run).
|
|
87
|
+
deployment_type:
|
|
88
|
+
type: string
|
|
89
|
+
default: BASIC
|
|
90
|
+
enum: [BASIC, BLUE_GREEN, CANARY, ROLLING, SHADOW, OTHER]
|
|
91
|
+
description: The kind of deployment (NR2).
|
|
92
|
+
http:
|
|
93
|
+
trigger: { entity_guid: { param: entity_guid }, version: { param: version } }
|
|
94
|
+
request:
|
|
95
|
+
graphql:
|
|
96
|
+
query: "mutation ($deployment: ChangeTrackingDeploymentInput!) { changeTrackingCreateDeployment(deployment: $deployment) { deploymentId entityGuid } }"
|
|
97
|
+
variables:
|
|
98
|
+
deployment:
|
|
99
|
+
entityGuid: { param: entity_guid }
|
|
100
|
+
version: { param: version }
|
|
101
|
+
description: { param: description }
|
|
102
|
+
user: { param: user }
|
|
103
|
+
commit: { param: commit }
|
|
104
|
+
deepLink: { param: deep_link }
|
|
105
|
+
deploymentType: { param: deployment_type }
|
|
106
|
+
outputs: { deployment_id: /changeTrackingCreateDeployment/deploymentId }
|
|
107
|
+
live:
|
|
108
|
+
params: { entity_guid: SPONSON_LIVE_NEW_RELIC_ENTITY_GUID }
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# Rollbar API recipes: a deploy per release in the environment. Format and checklist: docs/adr/0020-recipes.md,
|
|
3
|
+
# docs/adr/0022-one-off-actions.md, CONTRIBUTING.md "Adding a recipe".
|
|
4
|
+
provider: rollbar
|
|
5
|
+
title: Rollbar
|
|
6
|
+
category: observability
|
|
7
|
+
verified_on: "2026-10-12"
|
|
8
|
+
docs:
|
|
9
|
+
- title: Report a deploy
|
|
10
|
+
url: https://docs.rollbar.com/reference/post-deploy
|
|
11
|
+
- title: Deploy tracking
|
|
12
|
+
url: https://docs.rollbar.com/docs/deploy-tracking
|
|
13
|
+
- title: Project access tokens and their scopes
|
|
14
|
+
url: https://docs.rollbar.com/docs/access-tokens
|
|
15
|
+
- title: API reference index (deploy endpoints)
|
|
16
|
+
url: https://docs.rollbar.com/llms.txt
|
|
17
|
+
api:
|
|
18
|
+
base_url: https://api.rollbar.com/api/1
|
|
19
|
+
base_url_env: ROLLBAR_API_URL
|
|
20
|
+
auth: { header: X-Rollbar-Access-Token, value_env: ROLLBAR_ACCESS_TOKEN }
|
|
21
|
+
credential:
|
|
22
|
+
url: "https://docs.rollbar.com/docs/access-tokens"
|
|
23
|
+
scope: "A project access token with the `post_server_item` scope ('Can perform all POST requests to /deploy/ and /item/')."
|
|
24
|
+
source: "https://docs.rollbar.com/reference/post-deploy"
|
|
25
|
+
detect:
|
|
26
|
+
deps: [rollbar, "@rollbar/"]
|
|
27
|
+
env: ["ROLLBAR_*"]
|
|
28
|
+
starter:
|
|
29
|
+
- op: deploy
|
|
30
|
+
values: { environment: "${ctx.env}", revision: "${ctx.git.sha}", comment: "${ctx.scope}" }
|
|
31
|
+
assumptions:
|
|
32
|
+
- id: RB1
|
|
33
|
+
verified: true
|
|
34
|
+
text: "`POST https://api.rollbar.com/api/1/deploy` records a deploy from `environment` and `revision` (required), `rollbar_username`, `local_username`, `comment` and `status` (`started`, `succeeded` by default, `failed`, `timed_out`), authenticated by a project access token with the `post_server_item` scope in `X-Rollbar-Access-Token`, and answers 200 with `data.deploy_id`, an integer."
|
|
35
|
+
source: https://docs.rollbar.com/reference/post-deploy
|
|
36
|
+
- id: RB2
|
|
37
|
+
verified: false
|
|
38
|
+
text: "The token in the header is enough: the reference also lists `access_token` as a body field, which this recipe does not send (a credential in a body would be part of what the request logs show)."
|
|
39
|
+
- id: RB3
|
|
40
|
+
verified: true
|
|
41
|
+
text: "The API reference has report, get, update and list operations for deploys and none that deletes one, so destroy sends nothing and forgets the record: a deploy is history."
|
|
42
|
+
source: https://docs.rollbar.com/llms.txt
|
|
43
|
+
- id: RB4
|
|
44
|
+
verified: false
|
|
45
|
+
text: "Rollbar takes no idempotency key for deploys: one sent again after a crash before Sponson recorded it is a second deploy of the same revision (harmless, at least once)."
|
|
46
|
+
- id: RB5
|
|
47
|
+
verified: false
|
|
48
|
+
text: "A deploy is attributed to errors of the environment of the same name that the SDK reports (`environment` in its configuration), so a preview's deploys stay apart from production's when the preview's SDK reports its own environment, such as `preview`."
|
|
49
|
+
ops:
|
|
50
|
+
deploy:
|
|
51
|
+
kind: action
|
|
52
|
+
title: Deploy
|
|
53
|
+
summary: "A deploy of the release's revision in the environment's Rollbar `environment` (such as `preview`), sent once per environment and revision, so errors are attributed to the deploy. Nothing to undo: Rollbar deletes no deploys (RB3)."
|
|
54
|
+
covers: [rollbar-deploy]
|
|
55
|
+
params:
|
|
56
|
+
environment:
|
|
57
|
+
type: string
|
|
58
|
+
required: true
|
|
59
|
+
description: "The Rollbar environment the deployment's SDK reports, such as `${ctx.env}` (RB5)."
|
|
60
|
+
example: "${ctx.env}"
|
|
61
|
+
revision:
|
|
62
|
+
type: string
|
|
63
|
+
required: true
|
|
64
|
+
description: "The revision deployed, usually the commit: `\"${ctx.git.sha}\"`. A new one sends a new deploy."
|
|
65
|
+
example: "${ctx.git.sha}"
|
|
66
|
+
comment:
|
|
67
|
+
type: string
|
|
68
|
+
description: "Text shown with the deploy, such as the scope."
|
|
69
|
+
example: "${ctx.scope}"
|
|
70
|
+
local_username:
|
|
71
|
+
type: string
|
|
72
|
+
default: sponson
|
|
73
|
+
description: Who deployed.
|
|
74
|
+
rollbar_username:
|
|
75
|
+
type: string
|
|
76
|
+
description: A Rollbar user to attribute the deploy to.
|
|
77
|
+
status:
|
|
78
|
+
type: string
|
|
79
|
+
default: succeeded
|
|
80
|
+
enum: [started, succeeded, failed, timed_out]
|
|
81
|
+
description: The deploy's status.
|
|
82
|
+
http:
|
|
83
|
+
trigger: { environment: { param: environment }, revision: { param: revision } }
|
|
84
|
+
request:
|
|
85
|
+
method: POST
|
|
86
|
+
path: /deploy
|
|
87
|
+
body:
|
|
88
|
+
environment: { param: environment }
|
|
89
|
+
revision: { param: revision }
|
|
90
|
+
comment: { param: comment }
|
|
91
|
+
local_username: { param: local_username }
|
|
92
|
+
rollbar_username: { param: rollbar_username }
|
|
93
|
+
status: { param: status }
|
|
94
|
+
outputs: { deploy_id: /data/deploy_id }
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# Sanity (Content Lake) Projects API recipes, authenticated by a robot token. Format and checklist:
|
|
3
|
+
# docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
|
|
4
|
+
provider: sanity
|
|
5
|
+
title: Sanity
|
|
6
|
+
category: cms
|
|
7
|
+
verified_on: "2026-10-12"
|
|
8
|
+
docs:
|
|
9
|
+
- title: Projects API reference (datasets, CORS origins)
|
|
10
|
+
url: https://www.sanity.io/docs/http-reference/projects-api
|
|
11
|
+
- title: Datasets (naming rules, plan limits, environments)
|
|
12
|
+
url: https://www.sanity.io/docs/content-lake/datasets
|
|
13
|
+
- title: CORS origins (preview deployments)
|
|
14
|
+
url: https://www.sanity.io/docs/content-lake/cors
|
|
15
|
+
- title: HTTP API authentication (robot tokens)
|
|
16
|
+
url: https://www.sanity.io/docs/content-lake/http-auth
|
|
17
|
+
- title: Cloud Clone (dataset copy)
|
|
18
|
+
url: https://www.sanity.io/docs/content-lake/how-to-use-cloud-clone-for-datasets
|
|
19
|
+
- title: CLI configuration (SANITY_AUTH_TOKEN)
|
|
20
|
+
url: https://www.sanity.io/docs/cli-reference/cli-config
|
|
21
|
+
- title: Pricing (datasets per plan)
|
|
22
|
+
url: https://www.sanity.io/pricing
|
|
23
|
+
api:
|
|
24
|
+
base_url: https://api.sanity.io/v2021-06-07
|
|
25
|
+
base_url_env: SANITY_API_URL
|
|
26
|
+
auth: { bearer_env: SANITY_AUTH_TOKEN }
|
|
27
|
+
credential:
|
|
28
|
+
url: "https://www.sanity.io/manage"
|
|
29
|
+
scope: "A robot token of the project (API → Tokens) with the Administrator role, or Developer on Growth and Enterprise: editors cannot create datasets, and CORS origins are project settings."
|
|
30
|
+
source: "https://www.sanity.io/docs/http-reference/projects-api"
|
|
31
|
+
detect:
|
|
32
|
+
deps: [sanity, "@sanity/client", next-sanity]
|
|
33
|
+
files: [sanity.config.ts, sanity.config.js, sanity.cli.ts, sanity.cli.js]
|
|
34
|
+
env: ["SANITY_*"]
|
|
35
|
+
starter:
|
|
36
|
+
- op: cors_origin
|
|
37
|
+
preview_url: origin
|
|
38
|
+
- op: dataset
|
|
39
|
+
values: { name: "preview-${ctx.scope}" }
|
|
40
|
+
where:
|
|
41
|
+
project_id: "`projectId` in sanity.config.ts or sanity.cli.ts (`SANITY_STUDIO_PROJECT_ID`), or sanity.io/manage"
|
|
42
|
+
assumptions:
|
|
43
|
+
- id: SN1
|
|
44
|
+
verified: true
|
|
45
|
+
text: "The Projects API is served at `https://api.sanity.io/<version>` (default `v2021-06-07`) and authenticates with a robot token as `Authorization: Bearer`; the Sanity CLI reads a token for unattended use from `SANITY_AUTH_TOKEN`."
|
|
46
|
+
source: https://www.sanity.io/docs/http-reference/projects-api
|
|
47
|
+
- id: SN2
|
|
48
|
+
verified: true
|
|
49
|
+
text: "Managing a project's datasets and settings needs the Administrator or Developer role (Developer only on Growth and Enterprise); editors can modify existing datasets but cannot create new ones."
|
|
50
|
+
source: https://www.sanity.io/docs/user-guides/roles
|
|
51
|
+
- id: SN3
|
|
52
|
+
verified: true
|
|
53
|
+
text: "`PUT /projects/{projectId}/datasets/{name}` with an optional `{ aclMode }` (`public`, the default, or `private`, a paid feature) creates an empty dataset and answers 200 with `{ datasetName, aclMode }`, not the dataset itself, so the recipe finds it by name afterwards (`create.locate`)."
|
|
54
|
+
source: https://www.sanity.io/docs/http-reference/projects-api
|
|
55
|
+
- id: SN4
|
|
56
|
+
verified: true
|
|
57
|
+
text: "`GET /projects/{projectId}/datasets` answers a bare list of `{ name, aclMode, … }`; dataset names are unique in a project."
|
|
58
|
+
source: https://www.sanity.io/docs/http-reference/projects-api
|
|
59
|
+
- id: SN5
|
|
60
|
+
verified: true
|
|
61
|
+
text: "`DELETE /projects/{projectId}/datasets/{name}` deletes the dataset and its documents and answers `{ deleted: true }`."
|
|
62
|
+
source: https://www.sanity.io/docs/http-reference/projects-api
|
|
63
|
+
- id: SN6
|
|
64
|
+
verified: true
|
|
65
|
+
text: "A dataset name is 1 to 64 characters of lowercase letters, digits, `-` and `_`, beginning and ending with a letter or digit."
|
|
66
|
+
source: https://www.sanity.io/docs/content-lake/datasets
|
|
67
|
+
- id: SN7
|
|
68
|
+
verified: true
|
|
69
|
+
text: "Free and Growth plans include 2 datasets (more on Growth cost $999 per dataset per month), and copying a dataset (Cloud Clone, an asynchronous job) is an Enterprise feature; so a dataset per preview is practical on Enterprise, or with one preview dataset at a time below it. This recipe makes an empty dataset; its content is the app's import or seed (application data, not Sponson's), and Cloud Clone copies are not covered."
|
|
70
|
+
source: https://www.sanity.io/pricing
|
|
71
|
+
- id: SN8
|
|
72
|
+
verified: true
|
|
73
|
+
text: "A browser querying the Content Lake (or a Studio, or the Presentation tool) from an origin must find that origin in the project's CORS origins; preview deployments get a new URL per branch, so the origin cannot be added ahead of time, and unused preview origins should be removed. `https://*.vercel.app` with credentials is unsafe."
|
|
74
|
+
source: https://www.sanity.io/docs/content-lake/cors
|
|
75
|
+
- id: SN9
|
|
76
|
+
verified: true
|
|
77
|
+
text: "`GET /projects/{projectId}/cors` answers a bare list of `{ id, origin, allowCredentials, createdAt }` with integer ids; `POST /projects/{projectId}/cors` with `{ origin, allowCredentials? }` creates one (201); `DELETE /projects/{projectId}/cors/{id}` deletes it."
|
|
78
|
+
source: https://www.sanity.io/docs/http-reference/projects-api
|
|
79
|
+
- id: SN10
|
|
80
|
+
verified: false
|
|
81
|
+
text: "No update of a CORS origin or of a dataset's `aclMode` is documented, so neither is compared for drift: `allowCredentials` and `aclMode` are sent when the line creates the object, and only its existence is checked after."
|
|
82
|
+
- id: SN11
|
|
83
|
+
verified: false
|
|
84
|
+
text: "A dataset being deleted (or a `PUT` of a name that exists) answers within the request; nothing waits, and a dataset is usable as soon as the `PUT` returns."
|
|
85
|
+
ops:
|
|
86
|
+
dataset:
|
|
87
|
+
kind: resource
|
|
88
|
+
title: Dataset per preview
|
|
89
|
+
summary: "An empty Sanity dataset per scope in a project, such as `preview-pr-42`, for the preview to import or seed its content into (SN7: copying production into it is Enterprise's Cloud Clone and is not covered). Located by name; only its existence is compared for drift; destroy deletes the dataset and its documents."
|
|
90
|
+
covers: [sanity-dataset]
|
|
91
|
+
params:
|
|
92
|
+
project_id:
|
|
93
|
+
type: string
|
|
94
|
+
required: true
|
|
95
|
+
pattern: "^[a-z0-9]+$"
|
|
96
|
+
description: The project id (`projectId` in sanity.config.ts).
|
|
97
|
+
example: abc123de
|
|
98
|
+
name:
|
|
99
|
+
type: string
|
|
100
|
+
required: true
|
|
101
|
+
pattern: "^(?!.*[-_]$)[a-z0-9][-_a-z0-9]{0,63}$"
|
|
102
|
+
description: The dataset's name; its identity in the project (SN6).
|
|
103
|
+
example: "preview-${ctx.scope}"
|
|
104
|
+
acl_mode:
|
|
105
|
+
type: string
|
|
106
|
+
default: public
|
|
107
|
+
enum: [public, private]
|
|
108
|
+
description: "Who may read it without a token: `public` (Sanity's default) or `private` (Growth and up). Sent on create only (SN10)."
|
|
109
|
+
http:
|
|
110
|
+
find:
|
|
111
|
+
path: "/projects/{project_id}/datasets"
|
|
112
|
+
match: { name: { param: name } }
|
|
113
|
+
create:
|
|
114
|
+
method: PUT
|
|
115
|
+
path: "/projects/{project_id}/datasets/{name}"
|
|
116
|
+
body: { aclMode: { param: acl_mode } }
|
|
117
|
+
send_fields: false
|
|
118
|
+
locate: true
|
|
119
|
+
delete: { path: "/projects/{project_id}/datasets/{id}" }
|
|
120
|
+
id_path: /name
|
|
121
|
+
outputs:
|
|
122
|
+
name: /name
|
|
123
|
+
sim:
|
|
124
|
+
collection: "/projects/{project_id}/datasets"
|
|
125
|
+
live:
|
|
126
|
+
params: { project_id: SPONSON_LIVE_SANITY_PROJECT_ID }
|
|
127
|
+
cors_origin:
|
|
128
|
+
kind: resource
|
|
129
|
+
title: CORS origin
|
|
130
|
+
summary: "The preview deployment's origin in the project's CORS origins (API → CORS origins), so the preview's browser code, an embedded Studio or the Presentation tool can query the Content Lake (SN8). Located by origin; removed on destroy; every other origin is left alone."
|
|
131
|
+
covers: [sanity-cors]
|
|
132
|
+
params:
|
|
133
|
+
project_id:
|
|
134
|
+
type: string
|
|
135
|
+
required: true
|
|
136
|
+
pattern: "^[a-z0-9]+$"
|
|
137
|
+
description: The project id (`projectId` in sanity.config.ts).
|
|
138
|
+
example: abc123de
|
|
139
|
+
origin:
|
|
140
|
+
type: string
|
|
141
|
+
required: true
|
|
142
|
+
pattern: "^https?://[^/\\s]+$"
|
|
143
|
+
description: "The origin, scheme and host without a path or trailing slash: usually `{ from: <deploy line>.preview_url }`."
|
|
144
|
+
example: "https://${ctx.scope}.preview.example.app"
|
|
145
|
+
allow_credentials:
|
|
146
|
+
type: boolean
|
|
147
|
+
default: false
|
|
148
|
+
description: "Allow requests with credentials (a token or a login), which a Studio needs; never for a wildcard origin (SN8). Sent on create only (SN10)."
|
|
149
|
+
http:
|
|
150
|
+
find:
|
|
151
|
+
path: "/projects/{project_id}/cors"
|
|
152
|
+
match: { origin: { param: origin } }
|
|
153
|
+
create:
|
|
154
|
+
path: "/projects/{project_id}/cors"
|
|
155
|
+
body: { allowCredentials: { param: allow_credentials } }
|
|
156
|
+
delete: { path: "/projects/{project_id}/cors/{id}" }
|
|
157
|
+
sim:
|
|
158
|
+
numeric_ids: true
|
|
159
|
+
console_url:
|
|
160
|
+
template: "https://www.sanity.io/manage/project/{project_id}/api"
|
|
161
|
+
source: https://github.com/sanity-io/client/blob/main/src/http/errors.ts
|
|
162
|
+
live:
|
|
163
|
+
params: { project_id: SPONSON_LIVE_SANITY_PROJECT_ID }
|