@sponson/adapters 0.0.0-stage → 0.5.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/LICENSE +202 -0
- package/README.md +4 -2
- package/dist/algolia.d.ts +6 -0
- package/dist/algolia.js +151 -0
- package/dist/algolia.js.map +1 -0
- package/dist/clerk.d.ts +8 -0
- package/dist/clerk.js +107 -0
- package/dist/clerk.js.map +1 -0
- package/dist/cloudflare.d.ts +25 -0
- package/dist/cloudflare.js +310 -0
- package/dist/cloudflare.js.map +1 -0
- package/dist/common.d.ts +73 -0
- package/dist/common.js +140 -0
- package/dist/common.js.map +1 -0
- package/dist/digest.d.ts +46 -0
- package/dist/digest.js +129 -0
- package/dist/digest.js.map +1 -0
- package/dist/digitalocean.d.ts +5 -0
- package/dist/digitalocean.js +243 -0
- package/dist/digitalocean.js.map +1 -0
- package/dist/http-adapter-action.d.ts +63 -0
- package/dist/http-adapter-action.js +369 -0
- package/dist/http-adapter-action.js.map +1 -0
- package/dist/http-adapter-auth.d.ts +88 -0
- package/dist/http-adapter-auth.js +437 -0
- package/dist/http-adapter-auth.js.map +1 -0
- package/dist/http-adapter-client.d.ts +51 -0
- package/dist/http-adapter-client.js +156 -0
- package/dist/http-adapter-client.js.map +1 -0
- package/dist/http-adapter-graphql.d.ts +39 -0
- package/dist/http-adapter-graphql.js +157 -0
- package/dist/http-adapter-graphql.js.map +1 -0
- package/dist/http-adapter-list.d.ts +33 -0
- package/dist/http-adapter-list.js +421 -0
- package/dist/http-adapter-list.js.map +1 -0
- package/dist/http-adapter-resource.d.ts +29 -0
- package/dist/http-adapter-resource.js +462 -0
- package/dist/http-adapter-resource.js.map +1 -0
- package/dist/http-adapter-spec.d.ts +216 -0
- package/dist/http-adapter-spec.js +660 -0
- package/dist/http-adapter-spec.js.map +1 -0
- package/dist/http-adapter.d.ts +16 -0
- package/dist/http-adapter.js +28 -0
- package/dist/http-adapter.js.map +1 -0
- package/dist/http.d.ts +179 -0
- package/dist/http.js +352 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/launchdarkly.d.ts +15 -0
- package/dist/launchdarkly.js +337 -0
- package/dist/launchdarkly.js.map +1 -0
- package/dist/manual.d.ts +13 -0
- package/dist/manual.js +201 -0
- package/dist/manual.js.map +1 -0
- package/dist/neon.d.ts +8 -0
- package/dist/neon.js +167 -0
- package/dist/neon.js.map +1 -0
- package/dist/netlify.d.ts +18 -0
- package/dist/netlify.js +436 -0
- package/dist/netlify.js.map +1 -0
- package/dist/planetscale.d.ts +10 -0
- package/dist/planetscale.js +311 -0
- package/dist/planetscale.js.map +1 -0
- package/dist/providers.d.ts +26 -0
- package/dist/providers.js +36 -0
- package/dist/providers.js.map +1 -0
- package/dist/recipes.d.ts +167 -0
- package/dist/recipes.js +246 -0
- package/dist/recipes.js.map +1 -0
- package/dist/secrets.d.ts +72 -0
- package/dist/secrets.js +476 -0
- package/dist/secrets.js.map +1 -0
- package/dist/sigv4.d.ts +56 -0
- package/dist/sigv4.js +118 -0
- package/dist/sigv4.js.map +1 -0
- package/dist/supabase.d.ts +9 -0
- package/dist/supabase.js +385 -0
- package/dist/supabase.js.map +1 -0
- package/dist/vercel.d.ts +8 -0
- package/dist/vercel.js +475 -0
- package/dist/vercel.js.map +1 -0
- package/dist/xata.d.ts +8 -0
- package/dist/xata.js +142 -0
- package/dist/xata.js.map +1 -0
- package/dist/xml.d.ts +25 -0
- package/dist/xml.js +211 -0
- package/dist/xml.js.map +1 -0
- package/package.json +58 -3
- package/recipes/amplify.yaml +147 -0
- package/recipes/auth0.yaml +178 -0
- package/recipes/azure_swa.yaml +116 -0
- package/recipes/cloud_run.yaml +97 -0
- package/recipes/cloudflare.yaml +108 -0
- package/recipes/cockroachdb.yaml +132 -0
- package/recipes/configcat.yaml +123 -0
- package/recipes/datadog.yaml +136 -0
- package/recipes/firebase.yaml +84 -0
- package/recipes/flagsmith.yaml +98 -0
- package/recipes/fly.yaml +97 -0
- package/recipes/fly_machines.yaml +67 -0
- package/recipes/gcs.yaml +102 -0
- package/recipes/github.yaml +123 -0
- package/recipes/growthbook.yaml +124 -0
- package/recipes/heroku.yaml +98 -0
- package/recipes/honeycomb.yaml +89 -0
- package/recipes/inngest.yaml +97 -0
- package/recipes/kinde.yaml +120 -0
- package/recipes/mongodb_atlas.yaml +119 -0
- package/recipes/okta.yaml +177 -0
- package/recipes/posthog.yaml +127 -0
- package/recipes/postmark.yaml +105 -0
- package/recipes/postmark_server.yaml +93 -0
- package/recipes/prisma.yaml +150 -0
- package/recipes/qstash.yaml +134 -0
- package/recipes/railway.yaml +130 -0
- package/recipes/render.yaml +103 -0
- package/recipes/resend.yaml +130 -0
- package/recipes/s3.yaml +108 -0
- package/recipes/sendgrid.yaml +165 -0
- package/recipes/sentry.yaml +158 -0
- package/recipes/split.yaml +121 -0
- package/recipes/statsig.yaml +124 -0
- package/recipes/stripe.yaml +310 -0
- package/recipes/stytch.yaml +113 -0
- package/recipes/svix.yaml +109 -0
- package/recipes/turso.yaml +98 -0
- package/recipes/unleash.yaml +149 -0
- package/recipes/upstash.yaml +130 -0
- package/recipes/vercel.yaml +116 -0
- package/recipes/workos.yaml +70 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# ConfigCat Public Management API recipes. Format and checklist: docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
|
|
3
|
+
provider: configcat
|
|
4
|
+
title: ConfigCat
|
|
5
|
+
category: flags
|
|
6
|
+
verified_on: "2026-10-11"
|
|
7
|
+
docs:
|
|
8
|
+
- title: Public Management API
|
|
9
|
+
url: https://api.configcat.com/docs/
|
|
10
|
+
- title: OpenAPI spec (get value v2, replace value v2, targeting rule models)
|
|
11
|
+
url: https://api.configcat.com/docs/v1/swagger.json
|
|
12
|
+
- title: Terraform provider (credential variable names)
|
|
13
|
+
url: https://github.com/configcat/terraform-provider-configcat/blob/main/docs/index.md
|
|
14
|
+
api:
|
|
15
|
+
base_url: https://api.configcat.com
|
|
16
|
+
base_url_env: CONFIGCAT_API_URL
|
|
17
|
+
auth: { basic: { user_env: CONFIGCAT_BASIC_AUTH_USERNAME, password_env: CONFIGCAT_BASIC_AUTH_PASSWORD } }
|
|
18
|
+
detect:
|
|
19
|
+
deps: [configcat-js, configcat-js-ssr, configcat-js-full, configcat-node, configcat-react]
|
|
20
|
+
env: ["CONFIGCAT_*"]
|
|
21
|
+
starter:
|
|
22
|
+
- op: targeting_rule
|
|
23
|
+
values: { match: "${ctx.scope}" }
|
|
24
|
+
where:
|
|
25
|
+
environment_id: "ConfigCat Dashboard → your product → Environments → the preview environment's ID"
|
|
26
|
+
setting_id: "ConfigCat Public Management API `GET /v1/configs/{configId}/settings`: the flag's `settingId`"
|
|
27
|
+
assumptions:
|
|
28
|
+
- id: CC1
|
|
29
|
+
verified: true
|
|
30
|
+
text: "The API is at `https://api.configcat.com`, authenticated with Basic auth from Public API credentials (the Terraform provider's `CONFIGCAT_BASIC_AUTH_USERNAME` / `CONFIGCAT_BASIC_AUTH_PASSWORD`)."
|
|
31
|
+
source: https://api.configcat.com/docs/v1/swagger.json
|
|
32
|
+
- id: CC2
|
|
33
|
+
verified: true
|
|
34
|
+
text: "`GET /v2/environments/{environmentId}/settings/{settingId}/value` answers the setting's value in the environment bare: `defaultValue`, `targetingRules`, `percentageEvaluationAttribute` and read-only fields."
|
|
35
|
+
source: https://api.configcat.com/docs/v1/swagger.json
|
|
36
|
+
- id: CC3
|
|
37
|
+
verified: true
|
|
38
|
+
text: "`PUT` on the same path replaces the value: only `defaultValue`, `targetingRules` and `percentageEvaluationAttribute` can be set, and one not sent is reset. So those three are sent, as read, with the rule list changed (`parent.send`)."
|
|
39
|
+
source: https://api.configcat.com/docs/v1/swagger.json
|
|
40
|
+
- id: CC4
|
|
41
|
+
verified: true
|
|
42
|
+
text: "A targeting rule is `{ conditions: [{ userCondition: { comparisonAttribute, comparator, comparisonValue: { stringValue, doubleValue, listValue: [{ value, hint }] } } }], value | percentageOptions }`; rules have no id and are evaluated in order. `isOneOf` and `sensitiveIsOneOf` compare a user attribute with a list."
|
|
43
|
+
source: https://api.configcat.com/docs/v1/swagger.json
|
|
44
|
+
- id: CC5
|
|
45
|
+
verified: true
|
|
46
|
+
text: "Answers carry every member of a value (`boolValue`, `stringValue`, `intValue`, `doubleValue`, `predefinedVariationId`) and of a comparison value, the unused ones null; the rule is written with the same nulls so that it reads back equal."
|
|
47
|
+
source: https://api.configcat.com/docs/v1/swagger.json
|
|
48
|
+
- id: CC6
|
|
49
|
+
verified: false
|
|
50
|
+
text: "A condition is read back with `segmentCondition` and `prerequisiteFlagCondition` null and each list value's `hint` null, exactly as written; otherwise every plan shows the rule as changed."
|
|
51
|
+
- id: CC7
|
|
52
|
+
verified: false
|
|
53
|
+
text: "In a product with \"Config changes require a reason\" or approvals turned on, the PUT without `reason` / `bypassApproval` is refused (the query parameters are not sent); the apply then fails."
|
|
54
|
+
source: https://api.configcat.com/docs/v1/swagger.json
|
|
55
|
+
ops:
|
|
56
|
+
targeting_rule:
|
|
57
|
+
kind: list_item
|
|
58
|
+
title: Feature flag targeting rule
|
|
59
|
+
summary: "A targeting rule on a boolean feature flag in one environment that serves a value to the preview, such as `IF Preview IS ONE OF [pr-42] THEN true`. Added after the flag's other rules (evaluated in order: an earlier matching rule wins); the default value and the other rules are written back as read. Identified by the matched value; a console edit of its condition or served value is drift. Destroy removes the rule."
|
|
60
|
+
covers: [configcat-rule]
|
|
61
|
+
params:
|
|
62
|
+
environment_id:
|
|
63
|
+
type: string
|
|
64
|
+
required: true
|
|
65
|
+
description: The environment's id (a UUID).
|
|
66
|
+
example: 08d8becf-d4d9-4c66-8b48-6ac74cd95fba
|
|
67
|
+
setting_id:
|
|
68
|
+
type: string
|
|
69
|
+
required: true
|
|
70
|
+
pattern: "^[0-9]+$"
|
|
71
|
+
description: The feature flag's numeric setting id.
|
|
72
|
+
example: "12345"
|
|
73
|
+
attribute:
|
|
74
|
+
type: string
|
|
75
|
+
required: true
|
|
76
|
+
description: The user attribute the rule compares (a custom attribute such as `Preview`, or `Identifier`, `Email`).
|
|
77
|
+
example: Preview
|
|
78
|
+
comparator:
|
|
79
|
+
type: string
|
|
80
|
+
default: isOneOf
|
|
81
|
+
enum: [isOneOf, sensitiveIsOneOf]
|
|
82
|
+
description: "`isOneOf`, or `sensitiveIsOneOf` (hashed in the config JSON)."
|
|
83
|
+
match:
|
|
84
|
+
type: string
|
|
85
|
+
required: true
|
|
86
|
+
description: The attribute value that is the preview; it identifies the rule.
|
|
87
|
+
example: "${ctx.scope}"
|
|
88
|
+
serve:
|
|
89
|
+
type: boolean
|
|
90
|
+
default: true
|
|
91
|
+
description: The value the flag serves to the preview.
|
|
92
|
+
http:
|
|
93
|
+
parent:
|
|
94
|
+
path: "/v2/environments/{environment_id}/settings/{setting_id}/value"
|
|
95
|
+
method: PUT
|
|
96
|
+
send: [defaultValue, percentageEvaluationAttribute]
|
|
97
|
+
list_path: /targetingRules
|
|
98
|
+
key_field: /conditions/0/userCondition/comparisonValue/listValue/0/value
|
|
99
|
+
item:
|
|
100
|
+
conditions:
|
|
101
|
+
- userCondition:
|
|
102
|
+
comparisonAttribute: { param: attribute }
|
|
103
|
+
comparator: { param: comparator }
|
|
104
|
+
comparisonValue:
|
|
105
|
+
stringValue: null
|
|
106
|
+
doubleValue: null
|
|
107
|
+
listValue: [{ value: { param: match }, hint: null }]
|
|
108
|
+
segmentCondition: null
|
|
109
|
+
prerequisiteFlagCondition: null
|
|
110
|
+
value:
|
|
111
|
+
boolValue: { param: serve }
|
|
112
|
+
stringValue: null
|
|
113
|
+
intValue: null
|
|
114
|
+
doubleValue: null
|
|
115
|
+
predefinedVariationId: null
|
|
116
|
+
sim:
|
|
117
|
+
objects:
|
|
118
|
+
"/v2/environments/{environment_id}/settings/{setting_id}/value":
|
|
119
|
+
defaultValue: { boolValue: false, stringValue: null, intValue: null, doubleValue: null, predefinedVariationId: null }
|
|
120
|
+
targetingRules: []
|
|
121
|
+
percentageEvaluationAttribute: null
|
|
122
|
+
live:
|
|
123
|
+
params: { environment_id: SPONSON_LIVE_CONFIGCAT_ENVIRONMENT_ID, setting_id: SPONSON_LIVE_CONFIGCAT_SETTING_ID }
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# Datadog API recipes: every request carries the API key and the application key. Format and checklist:
|
|
3
|
+
# docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
|
|
4
|
+
provider: datadog
|
|
5
|
+
title: Datadog
|
|
6
|
+
category: observability
|
|
7
|
+
verified_on: "2026-10-11"
|
|
8
|
+
docs:
|
|
9
|
+
- title: Synthetics API reference
|
|
10
|
+
url: https://docs.datadoghq.com/api/latest/synthetics/
|
|
11
|
+
- title: API authentication (keys, sites)
|
|
12
|
+
url: https://docs.datadoghq.com/api/latest/authentication/
|
|
13
|
+
- title: Datadog API v1 OpenAPI document (datadog-api-client)
|
|
14
|
+
url: https://github.com/DataDog/datadog-api-client-typescript/blob/master/.generator/schemas/v1/openapi.yaml
|
|
15
|
+
api:
|
|
16
|
+
base_url: https://api.datadoghq.com/api/v1
|
|
17
|
+
base_url_env: DATADOG_API_URL
|
|
18
|
+
auth:
|
|
19
|
+
headers:
|
|
20
|
+
- { header: DD-API-KEY, value_env: DD_API_KEY }
|
|
21
|
+
- { header: DD-APPLICATION-KEY, value_env: DD_APP_KEY }
|
|
22
|
+
detect:
|
|
23
|
+
deps: [dd-trace, "@datadog/"]
|
|
24
|
+
env: ["DD_*", "DATADOG_*"]
|
|
25
|
+
starter:
|
|
26
|
+
- op: synthetic_api_test
|
|
27
|
+
preview_url: url
|
|
28
|
+
values: { name: "preview ${ctx.scope}", locations: ["aws:us-east-2"] }
|
|
29
|
+
assumptions:
|
|
30
|
+
- id: DD1
|
|
31
|
+
verified: true
|
|
32
|
+
text: "Requests carry the API key in `DD-API-KEY` and the application key in `DD-APPLICATION-KEY`; Datadog's clients read them from `DD_API_KEY` and `DD_APP_KEY`. Reading needs the application key too."
|
|
33
|
+
source: https://github.com/DataDog/datadog-api-client-typescript/blob/master/.generator/schemas/v1/openapi.yaml
|
|
34
|
+
- id: DD2
|
|
35
|
+
verified: true
|
|
36
|
+
text: "Each Datadog site has its own API host (`https://api.datadoghq.eu`, `https://api.us3.datadoghq.com`, …): outside US1, set `base_url` in the provider block."
|
|
37
|
+
source: https://docs.datadoghq.com/api/latest/authentication/
|
|
38
|
+
- id: DD3
|
|
39
|
+
verified: true
|
|
40
|
+
text: "`POST /synthetics/tests/api` creates an API test from `name`, `type` (`api`), `config` (`request` with `method` and `url`, `assertions`), `locations`, `options` and `message` (all required), with `subtype` (`http`), `status` (`live` or `paused`) and `tags`, answering it with its `public_id`."
|
|
41
|
+
source: https://github.com/DataDog/datadog-api-client-typescript/blob/master/.generator/schemas/v1/openapi.yaml
|
|
42
|
+
- id: DD4
|
|
43
|
+
verified: true
|
|
44
|
+
text: "`GET /synthetics/tests/api/{public_id}` answers one API test; `PUT` on the same path replaces its configuration with a whole test definition."
|
|
45
|
+
source: https://github.com/DataDog/datadog-api-client-typescript/blob/master/.generator/schemas/v1/openapi.yaml
|
|
46
|
+
- id: DD5
|
|
47
|
+
verified: true
|
|
48
|
+
text: "`GET /synthetics/tests` lists every test as `{ tests: [...] }` (`page_size` and `page_number` are optional); `POST /synthetics/tests/delete` with `{ public_ids: [...] }` deletes tests."
|
|
49
|
+
source: https://github.com/DataDog/datadog-api-client-typescript/blob/master/.generator/schemas/v1/openapi.yaml
|
|
50
|
+
- id: DD6
|
|
51
|
+
verified: false
|
|
52
|
+
text: "Without `page_size` the list answers every test of the organisation, and a test name identifies one test (two with one name make `find` refuse with PARAM_INVALID)."
|
|
53
|
+
- id: DD7
|
|
54
|
+
verified: false
|
|
55
|
+
text: "The fields compared (`config.request`, `config.assertions`, `locations`, `options.tick_every`, `message`, `status`, `tags`) are answered as they were sent, in order."
|
|
56
|
+
- id: DD8
|
|
57
|
+
verified: false
|
|
58
|
+
text: "Deleting a test that is already gone answers 404 (destroy treats it as done)."
|
|
59
|
+
- id: DD9
|
|
60
|
+
verified: false
|
|
61
|
+
text: "Deployment events (`datadog-ci deployment mark`, the DORA deployments API) are not a recipe: they are listed with a POST over a time window and cannot be deleted, so a later run could not find the one it made."
|
|
62
|
+
ops:
|
|
63
|
+
synthetic_api_test:
|
|
64
|
+
kind: resource
|
|
65
|
+
title: Synthetic API test against a preview
|
|
66
|
+
summary: "A Synthetic HTTP test per scope that checks the preview's URL from Datadog's locations, such as `preview pr-42` asserting status 200, with its own monitor. Located by its name; a console edit of its request, assertions, locations, frequency, message, status or tags is drift; destroy deletes the test (and its monitor)."
|
|
67
|
+
covers: [datadog-marker]
|
|
68
|
+
params:
|
|
69
|
+
name:
|
|
70
|
+
type: string
|
|
71
|
+
required: true
|
|
72
|
+
description: The test's name; its identity (DD6).
|
|
73
|
+
example: "preview ${ctx.scope}"
|
|
74
|
+
url:
|
|
75
|
+
type: string
|
|
76
|
+
required: true
|
|
77
|
+
pattern: "^https?://\\S+$"
|
|
78
|
+
description: The URL to request (the preview's URL, or a health path on it).
|
|
79
|
+
example: "https://${ctx.scope}.preview.example.app/api/health"
|
|
80
|
+
method:
|
|
81
|
+
type: string
|
|
82
|
+
default: GET
|
|
83
|
+
enum: [GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS]
|
|
84
|
+
description: The HTTP method.
|
|
85
|
+
assertions:
|
|
86
|
+
type: list
|
|
87
|
+
default: [{ type: statusCode, operator: is, target: 200 }]
|
|
88
|
+
description: "The assertions, each `{ type, operator, target }` (`statusCode`, `responseTime`, `body`, `header`)."
|
|
89
|
+
locations:
|
|
90
|
+
type: list
|
|
91
|
+
required: true
|
|
92
|
+
description: "The managed locations to run from, such as `aws:us-east-2` or `aws:eu-central-1`."
|
|
93
|
+
example: ["aws:us-east-2"]
|
|
94
|
+
tick_every:
|
|
95
|
+
type: integer
|
|
96
|
+
default: 300
|
|
97
|
+
description: How often the test runs, in seconds.
|
|
98
|
+
message:
|
|
99
|
+
type: string
|
|
100
|
+
default: Preview check managed by Sponson
|
|
101
|
+
description: The notification message of the test's monitor.
|
|
102
|
+
status:
|
|
103
|
+
type: string
|
|
104
|
+
default: live
|
|
105
|
+
enum: [live, paused]
|
|
106
|
+
description: "`paused` keeps the test without running it."
|
|
107
|
+
tags:
|
|
108
|
+
type: list
|
|
109
|
+
default: ["managed-by:sponson"]
|
|
110
|
+
description: The test's tags.
|
|
111
|
+
http:
|
|
112
|
+
find:
|
|
113
|
+
path: /synthetics/tests
|
|
114
|
+
list_path: /tests
|
|
115
|
+
match: { name: { param: name } }
|
|
116
|
+
read: { path: "/synthetics/tests/api/{id}" }
|
|
117
|
+
create:
|
|
118
|
+
path: /synthetics/tests/api
|
|
119
|
+
body: { type: api, subtype: http }
|
|
120
|
+
update:
|
|
121
|
+
method: PUT
|
|
122
|
+
body: { type: api, subtype: http }
|
|
123
|
+
delete:
|
|
124
|
+
method: POST
|
|
125
|
+
path: /synthetics/tests/delete
|
|
126
|
+
body: { public_ids: ["{id}"] }
|
|
127
|
+
id_path: /public_id
|
|
128
|
+
fields:
|
|
129
|
+
/config/request/method: { param: method }
|
|
130
|
+
/config/request/url: { param: url }
|
|
131
|
+
/config/assertions: { param: assertions }
|
|
132
|
+
locations: { param: locations }
|
|
133
|
+
/options/tick_every: { param: tick_every }
|
|
134
|
+
message: { param: message }
|
|
135
|
+
status: { param: status }
|
|
136
|
+
tags: { param: tags }
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# Firebase Authentication (Identity Toolkit admin API) recipes. Format and checklist: docs/adr/0020-recipes.md,
|
|
3
|
+
# CONTRIBUTING.md "Adding a recipe".
|
|
4
|
+
provider: firebase
|
|
5
|
+
title: Firebase Authentication
|
|
6
|
+
category: auth
|
|
7
|
+
verified_on: "2026-10-11"
|
|
8
|
+
docs:
|
|
9
|
+
- title: Identity Toolkit API v2, projects.getConfig
|
|
10
|
+
url: https://docs.cloud.google.com/identity-platform/docs/reference/rest/v2/projects/getConfig
|
|
11
|
+
- title: Identity Toolkit API v2, projects.updateConfig
|
|
12
|
+
url: https://docs.cloud.google.com/identity-platform/docs/reference/rest/v2/projects/updateConfig
|
|
13
|
+
- title: Identity Toolkit API v2, Config
|
|
14
|
+
url: https://docs.cloud.google.com/identity-platform/docs/reference/rest/v2/Config
|
|
15
|
+
- title: Authenticate for using REST
|
|
16
|
+
url: https://docs.cloud.google.com/docs/authentication/rest
|
|
17
|
+
api:
|
|
18
|
+
base_url: https://identitytoolkit.googleapis.com/admin/v2
|
|
19
|
+
base_url_env: FIREBASE_API_URL
|
|
20
|
+
auth: { command: [gcloud, auth, print-access-token] }
|
|
21
|
+
detect:
|
|
22
|
+
deps: [firebase, firebase-admin]
|
|
23
|
+
env: ["FIREBASE_*"]
|
|
24
|
+
files: [firebase.json, .firebaserc]
|
|
25
|
+
starter:
|
|
26
|
+
- op: authorized_domain
|
|
27
|
+
where:
|
|
28
|
+
project: "`projects.default` in .firebaserc, or `firebase projects:list`"
|
|
29
|
+
domain: "the preview's host name without `https://` (Firebase takes a domain, so a `{ from }` URL cannot be used)"
|
|
30
|
+
assumptions:
|
|
31
|
+
- id: FB1
|
|
32
|
+
verified: true
|
|
33
|
+
text: "`GET https://identitytoolkit.googleapis.com/admin/v2/projects/{project}/config` answers the project's Auth `Config`."
|
|
34
|
+
source: https://docs.cloud.google.com/identity-platform/docs/reference/rest/v2/projects/getConfig
|
|
35
|
+
- id: FB2
|
|
36
|
+
verified: true
|
|
37
|
+
text: "`PATCH …/admin/v2/projects/{project}/config?updateMask=authorizedDomains` updates the config with a `Config` body; fields set in the body but not named in `updateMask` are ignored, so the write changes the authorized domains only. It needs one of the `identitytoolkit`, `firebase` or `cloud-platform` OAuth scopes."
|
|
38
|
+
source: https://docs.cloud.google.com/identity-platform/docs/reference/rest/v2/projects/updateConfig
|
|
39
|
+
- id: FB3
|
|
40
|
+
verified: true
|
|
41
|
+
text: "`authorizedDomains` is a list of strings, the domains authorized for OAuth redirects; the masked field is replaced by the list sent, so the recipe sends the whole list read just before with one domain added or removed."
|
|
42
|
+
source: https://docs.cloud.google.com/identity-platform/docs/reference/rest/v2/Config
|
|
43
|
+
- id: FB4
|
|
44
|
+
verified: true
|
|
45
|
+
text: "`gcloud auth print-access-token` prints an access token for the signed-in credentials, used as `Authorization: Bearer`. With user credentials some APIs also need the quota project in `x-goog-user-project`: add `headers: { x-goog-user-project: <project> }` to the `providers.http.firebase` block (not needed with a service account; a block's headers are part of its identity)."
|
|
46
|
+
source: https://docs.cloud.google.com/docs/authentication/rest
|
|
47
|
+
- id: FB5
|
|
48
|
+
verified: false
|
|
49
|
+
text: "The config has no precondition the update honours (no etag in `Config`): the line locks the project's config (`lockOn`) against other Sponson runs; a console edit made between the read and the write can still be lost."
|
|
50
|
+
- id: FB6
|
|
51
|
+
verified: false
|
|
52
|
+
text: "An authorized domain is a host name without scheme, port or path, and is read back exactly as written."
|
|
53
|
+
- id: FB7
|
|
54
|
+
verified: false
|
|
55
|
+
text: "The same admin v2 config holds the authorized domains of a Firebase Authentication project with or without the Identity Platform upgrade."
|
|
56
|
+
ops:
|
|
57
|
+
authorized_domain:
|
|
58
|
+
kind: list_item
|
|
59
|
+
title: Authorized domain
|
|
60
|
+
summary: "One domain in Firebase Authentication's authorized domains (Authentication, Settings, Authorized domains), which OAuth sign-in redirects and email links require, such as the preview deployment's host. Read-modify-write of the list with `updateMask=authorizedDomains` under a lock on the project's config; removed on destroy; every other domain (localhost, the Firebase hosting domains) is left as it is."
|
|
61
|
+
covers: [firebase-auth-domains]
|
|
62
|
+
params:
|
|
63
|
+
project:
|
|
64
|
+
type: string
|
|
65
|
+
required: true
|
|
66
|
+
description: The Google Cloud / Firebase project id.
|
|
67
|
+
example: demo-project
|
|
68
|
+
domain:
|
|
69
|
+
type: string
|
|
70
|
+
required: true
|
|
71
|
+
pattern: "^[A-Za-z0-9.-]+$"
|
|
72
|
+
description: "The domain, a host name without scheme or path (`pr-42.preview.example.app`, `my-app-git-feat-x.vercel.app`)."
|
|
73
|
+
example: "${ctx.scope}.preview.example.app"
|
|
74
|
+
http:
|
|
75
|
+
parent:
|
|
76
|
+
path: "/projects/{project}/config?updateMask=authorizedDomains"
|
|
77
|
+
read_path: "/projects/{project}/config"
|
|
78
|
+
list_path: /authorizedDomains
|
|
79
|
+
item: { param: domain }
|
|
80
|
+
sim:
|
|
81
|
+
objects:
|
|
82
|
+
"/projects/{project}/config": { name: projects/demo-project/config, authorizedDomains: [localhost, demo-project.firebaseapp.com, demo-project.web.app] }
|
|
83
|
+
live:
|
|
84
|
+
params: { project: SPONSON_LIVE_FIREBASE_PROJECT }
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# Flagsmith Admin (management) API recipes, authenticated by an organisation API key. Format and checklist:
|
|
3
|
+
# docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
|
|
4
|
+
provider: flagsmith
|
|
5
|
+
title: Flagsmith
|
|
6
|
+
category: flags
|
|
7
|
+
verified_on: "2026-10-11"
|
|
8
|
+
docs:
|
|
9
|
+
- title: Admin API authentication
|
|
10
|
+
url: https://docs.flagsmith.com/integrating-with-flagsmith/flagsmith-api-overview/admin-api/authentication
|
|
11
|
+
- title: Admin API overview
|
|
12
|
+
url: https://docs.flagsmith.com/integrating-with-flagsmith/flagsmith-api-overview/admin-api
|
|
13
|
+
- title: Flagsmith API OpenAPI document
|
|
14
|
+
url: https://api.flagsmith.com/api/v1/swagger.json
|
|
15
|
+
api:
|
|
16
|
+
base_url: https://api.flagsmith.com/api/v1
|
|
17
|
+
base_url_env: FLAGSMITH_API_URL
|
|
18
|
+
auth: { header: Authorization, value_env: FLAGSMITH_MASTER_API_KEY, prefix: "Api-Key " }
|
|
19
|
+
detect:
|
|
20
|
+
deps: [flagsmith, flagsmith-nodejs, react-native-flagsmith]
|
|
21
|
+
env: ["FLAGSMITH_*"]
|
|
22
|
+
starter:
|
|
23
|
+
- op: environment
|
|
24
|
+
values: { name: "preview-${ctx.scope}" }
|
|
25
|
+
where:
|
|
26
|
+
project_id: "Flagsmith → your project: the number in its URL (`/project/<id>/…`)"
|
|
27
|
+
assumptions:
|
|
28
|
+
- id: FS1
|
|
29
|
+
verified: true
|
|
30
|
+
text: "The Admin API authenticates with an organisation API key as `Authorization: Api-Key <key>`; Bearer is only for short-lived OIDC-exchanged tokens."
|
|
31
|
+
source: https://docs.flagsmith.com/integrating-with-flagsmith/flagsmith-api-overview/admin-api/authentication
|
|
32
|
+
- id: FS2
|
|
33
|
+
verified: true
|
|
34
|
+
text: "`POST /environments/` creates an environment from `name` and `project` (both required) and optional `description`, answering it (201) with its integer `id` and its `api_key`, the client-side environment key SDKs use."
|
|
35
|
+
source: https://api.flagsmith.com/api/v1/swagger.json
|
|
36
|
+
- id: FS3
|
|
37
|
+
verified: true
|
|
38
|
+
text: "`GET /environments/?project=<id>` lists a project's environments as `{ count, next, previous, results: [...] }`."
|
|
39
|
+
source: https://api.flagsmith.com/api/v1/swagger.json
|
|
40
|
+
- id: FS4
|
|
41
|
+
verified: true
|
|
42
|
+
text: "`GET`, `PATCH` and `DELETE /environments/{api_key}/` read, update and delete one environment (DELETE answers 204)."
|
|
43
|
+
source: https://api.flagsmith.com/api/v1/swagger.json
|
|
44
|
+
- id: FS5
|
|
45
|
+
verified: false
|
|
46
|
+
text: "A project has fewer environments than one page of the list holds, so `find` sees them all (`next` is a URL, which the http adapter does not follow)."
|
|
47
|
+
- id: FS6
|
|
48
|
+
verified: false
|
|
49
|
+
text: "A new environment starts with every feature of the project at its default state, and environment names are unique in a project in practice (two with one name make `find` refuse with PARAM_INVALID)."
|
|
50
|
+
- id: FS7
|
|
51
|
+
verified: false
|
|
52
|
+
text: "`description` is answered as sent; `FLAGSMITH_MASTER_API_KEY` is the variable Flagsmith's Terraform provider reads the key from."
|
|
53
|
+
- id: FS8
|
|
54
|
+
verified: false
|
|
55
|
+
text: "Identity and segment overrides are not recipes: Edge projects (Flagsmith SaaS's default) address identities by UUID through `edge-identities`, and a segment override is two objects (a feature segment, then a feature state) created in order."
|
|
56
|
+
- id: FS9
|
|
57
|
+
verified: false
|
|
58
|
+
text: "The create takes the project id as a string of digits (`\"1234\"`) as well as a number, as Django REST Framework's primary-key fields do."
|
|
59
|
+
ops:
|
|
60
|
+
environment:
|
|
61
|
+
kind: resource
|
|
62
|
+
title: Environment per preview
|
|
63
|
+
summary: "A Flagsmith environment per scope in a project, such as `preview-pr-42`, starting from the project's default flag states; its client-side environment key is the output `api_key` for the preview's SDK configuration. Located by name in the project; a console edit of its description is drift; destroy deletes the environment with its flag states and identities."
|
|
64
|
+
covers: [flagsmith-override]
|
|
65
|
+
params:
|
|
66
|
+
project_id:
|
|
67
|
+
type: string
|
|
68
|
+
required: true
|
|
69
|
+
pattern: "^[0-9]+$"
|
|
70
|
+
description: The project's id, digits as a string (FS9).
|
|
71
|
+
example: "1234"
|
|
72
|
+
name:
|
|
73
|
+
type: string
|
|
74
|
+
required: true
|
|
75
|
+
description: The environment's name; its identity in the project (FS6).
|
|
76
|
+
example: "preview-${ctx.scope}"
|
|
77
|
+
description:
|
|
78
|
+
type: string
|
|
79
|
+
default: Preview environment managed by Sponson
|
|
80
|
+
description: The environment's description.
|
|
81
|
+
http:
|
|
82
|
+
find:
|
|
83
|
+
path: "/environments/?project={project_id}"
|
|
84
|
+
list_path: /results
|
|
85
|
+
match: { name: { param: name } }
|
|
86
|
+
read: { path: "/environments/{id}/" }
|
|
87
|
+
create:
|
|
88
|
+
path: /environments/
|
|
89
|
+
body: { project: { param: project_id } }
|
|
90
|
+
update: { method: PATCH }
|
|
91
|
+
id_path: /api_key
|
|
92
|
+
fields:
|
|
93
|
+
description: { param: description }
|
|
94
|
+
outputs:
|
|
95
|
+
api_key: /api_key
|
|
96
|
+
environment_id: /id
|
|
97
|
+
live:
|
|
98
|
+
params: { project_id: SPONSON_LIVE_FLAGSMITH_PROJECT_ID }
|
package/recipes/fly.yaml
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# Fly.io GraphQL API recipes (app secrets). Format and checklist: docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
|
|
3
|
+
# The per-PR app itself is in fly_machines.yaml (the Machines API has another base URL).
|
|
4
|
+
provider: fly
|
|
5
|
+
title: Fly.io
|
|
6
|
+
category: deploy
|
|
7
|
+
verified_on: "2026-10-11"
|
|
8
|
+
docs:
|
|
9
|
+
- title: Secrets and Fly Apps
|
|
10
|
+
url: https://docs.fly.io/apps/secrets
|
|
11
|
+
- title: superfly/fly-go resource_secrets.go (the GraphQL operations flyctl sends)
|
|
12
|
+
url: https://github.com/superfly/fly-go/blob/main/resource_secrets.go
|
|
13
|
+
- title: superfly/fly-go schema.graphql
|
|
14
|
+
url: https://github.com/superfly/fly-go/blob/main/schema.graphql
|
|
15
|
+
- title: Working with the Machines API (tokens)
|
|
16
|
+
url: https://docs.fly.io/machines/api/working-with-machines-api/
|
|
17
|
+
api:
|
|
18
|
+
base_url: https://api.fly.io/graphql
|
|
19
|
+
base_url_env: FLY_API_URL
|
|
20
|
+
auth: { bearer_env: FLY_API_TOKEN }
|
|
21
|
+
detect:
|
|
22
|
+
env: ["FLY_*"]
|
|
23
|
+
files: [fly.toml]
|
|
24
|
+
starter:
|
|
25
|
+
- op: secret
|
|
26
|
+
where:
|
|
27
|
+
app: "the preview's Fly app: `app` in fly.toml, or the app per pull request a `fly_machines.app` line creates"
|
|
28
|
+
assumptions:
|
|
29
|
+
- id: FS1
|
|
30
|
+
verified: true
|
|
31
|
+
text: "`query ($appName: String!) { app(name: $appName) { secrets { name digest createdAt } } }` lists an app's secrets; values are never returned (Fly does not allow reading plain-text secret values), so the recipe locates a secret by name and compares nothing else."
|
|
32
|
+
source: https://github.com/superfly/fly-go/blob/main/resource_secrets.go
|
|
33
|
+
- id: FS2
|
|
34
|
+
verified: true
|
|
35
|
+
text: "`mutation($input: SetSecretsInput!) { setSecrets(input: $input) { release { id version } } }` with `{ appId, secrets: [{ key, value }] }` sets secrets; `unsetSecrets(input: { appId, keys })` removes them."
|
|
36
|
+
source: https://github.com/superfly/fly-go/blob/main/resource_secrets.go
|
|
37
|
+
- id: FS3
|
|
38
|
+
verified: true
|
|
39
|
+
text: "Plain-text values cannot be read back (`fly secrets list` shows a name, a digest and a date), so a value changed in the console, or in the plan, is not detected: drift is the secret's presence only. To change a value, run `sponson apply --destroy` for the scope (or remove the line, apply, and add it back)."
|
|
40
|
+
source: https://docs.fly.io/apps/secrets
|
|
41
|
+
- id: FS4
|
|
42
|
+
verified: true
|
|
43
|
+
text: "Machines read secrets as environment variables at boot: a secret set without updating the Machines (as `fly secrets set --stage` does) reaches only Machines started or updated afterwards. Order the line before the PR's `fly deploy`; after a later change run `fly secrets deploy`."
|
|
44
|
+
source: https://docs.fly.io/apps/secrets
|
|
45
|
+
- id: FS5
|
|
46
|
+
verified: false
|
|
47
|
+
text: "A token from `fly tokens create` (`FlyV1 fm2_…`) or `fly auth token` is accepted as `Authorization: Bearer <token>` by the GraphQL API, as the Machines API documents for the same `FLY_API_TOKEN`. (fly-go itself sends a macaroon as `FlyV1 <token>`; a block that needs that sends it with `auth: { header: Authorization, value_env: FLY_API_TOKEN }`.)"
|
|
48
|
+
- id: FS6
|
|
49
|
+
verified: false
|
|
50
|
+
text: "Unsetting a secret of an app that no longer exists answers an error saying the app could not be found, which the adapter reads as already gone; unsetting an absent key of an existing app is not an error. setSecrets through GraphQL updates no Machines (FS4). Current flyctl sets secrets through the Machines API instead; the GraphQL mutations are not marked deprecated."
|
|
51
|
+
ops:
|
|
52
|
+
secret:
|
|
53
|
+
kind: resource
|
|
54
|
+
title: App secret
|
|
55
|
+
summary: "One secret of a Fly app (typically the app made for the pull request, `fly_machines.app`), set with `setSecrets` and removed with `unsetSecrets`. Fly never returns secret values, so only its presence is compared: a secret unset in the console is recreated, a changed value is not noticed (FS3). Machines see it once started or updated after the write: order it before the PR's deploy (FS4)."
|
|
56
|
+
covers: [fly-secrets]
|
|
57
|
+
params:
|
|
58
|
+
app:
|
|
59
|
+
type: string
|
|
60
|
+
required: true
|
|
61
|
+
description: The app's name.
|
|
62
|
+
example: "demo-${ctx.scope}"
|
|
63
|
+
name:
|
|
64
|
+
type: string
|
|
65
|
+
required: true
|
|
66
|
+
pattern: "^[A-Za-z_][A-Za-z0-9_]*$"
|
|
67
|
+
description: The secret's name (the environment variable the Machines see).
|
|
68
|
+
example: DATABASE_URL
|
|
69
|
+
value:
|
|
70
|
+
type: string
|
|
71
|
+
required: true
|
|
72
|
+
description: The secret's value, normally a `{ secret }` reference. It is sent, never stored or compared.
|
|
73
|
+
example: "postgres://app@db.internal:5432/${ctx.scope}"
|
|
74
|
+
http:
|
|
75
|
+
find:
|
|
76
|
+
graphql:
|
|
77
|
+
query: "query ($appName: String!) { app(name: $appName) { secrets { name digest createdAt } } }"
|
|
78
|
+
variables: { appName: { param: app } }
|
|
79
|
+
data_path: /app/secrets
|
|
80
|
+
match: { name: { param: name } }
|
|
81
|
+
create:
|
|
82
|
+
graphql:
|
|
83
|
+
query: "mutation($input: SetSecretsInput!) { setSecrets(input: $input) { release { id version } } }"
|
|
84
|
+
variables: { input: { appId: { param: app }, secrets: [{ key: { param: name }, value: { param: value } }] } }
|
|
85
|
+
idempotent: true
|
|
86
|
+
delete:
|
|
87
|
+
graphql:
|
|
88
|
+
query: "mutation($input: UnsetSecretsInput!) { unsetSecrets(input: $input) { release { id version } } }"
|
|
89
|
+
variables: { input: { appId: { param: app }, keys: [{ param: name }] } }
|
|
90
|
+
sim:
|
|
91
|
+
provider: fly
|
|
92
|
+
seed: { apps: { demo-pr-42: {} } }
|
|
93
|
+
present: /apps/demo-pr-42/secrets/DATABASE_URL
|
|
94
|
+
drift:
|
|
95
|
+
missing: { secrets.demo-pr-42.DATABASE_URL: delete }
|
|
96
|
+
live:
|
|
97
|
+
params: { app: SPONSON_LIVE_FLY_APP }
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../../../schema/recipe.schema.json
|
|
2
|
+
# Fly.io Machines API recipes (the per-PR app). Format and checklist: docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
|
|
3
|
+
# The app's secrets are in fly.yaml (the GraphQL API has another base URL).
|
|
4
|
+
provider: fly_machines
|
|
5
|
+
title: Fly.io Machines API
|
|
6
|
+
category: deploy
|
|
7
|
+
verified_on: "2026-10-11"
|
|
8
|
+
docs:
|
|
9
|
+
- title: Working with the Machines API
|
|
10
|
+
url: https://docs.fly.io/machines/api/working-with-machines-api/
|
|
11
|
+
- title: Apps resource
|
|
12
|
+
url: https://docs.fly.io/machines/api/apps-resource/
|
|
13
|
+
api:
|
|
14
|
+
base_url: https://api.machines.dev/v1
|
|
15
|
+
base_url_env: FLY_MACHINES_API_URL
|
|
16
|
+
auth: { bearer_env: FLY_API_TOKEN }
|
|
17
|
+
assumptions:
|
|
18
|
+
- id: FM1
|
|
19
|
+
verified: true
|
|
20
|
+
text: "The Machines API's public base URL is `https://api.machines.dev`, its paths start with `/v1`, and requests carry `Authorization: Bearer <fly_api_token>`."
|
|
21
|
+
source: https://docs.fly.io/machines/api/working-with-machines-api/
|
|
22
|
+
- id: FM2
|
|
23
|
+
verified: true
|
|
24
|
+
text: "`POST /v1/apps` with `app_name` (unique) and `org_slug` (both required) and optional `network` creates an app and answers 201 with `id` and `created_at`."
|
|
25
|
+
source: https://docs.fly.io/machines/api/apps-resource/
|
|
26
|
+
- id: FM3
|
|
27
|
+
verified: true
|
|
28
|
+
text: "`GET /v1/apps/{app_name}` answers the app (`id`, `name`, `status`, `organization { name, slug }`), so the name the plan chooses locates it."
|
|
29
|
+
source: https://docs.fly.io/machines/api/apps-resource/
|
|
30
|
+
- id: FM4
|
|
31
|
+
verified: true
|
|
32
|
+
text: "`DELETE /v1/apps/{app_name}` answers 202; Machines should be stopped first, and `?force=true` stops them and deletes the app at once, which is what the recipe's destroy sends (a PR app has the PR's Machines running)."
|
|
33
|
+
source: https://docs.fly.io/machines/api/apps-resource/
|
|
34
|
+
- id: FM5
|
|
35
|
+
verified: false
|
|
36
|
+
text: "Deleting the app deletes its secrets and its Machines with it; an app name another organization holds is refused with a conflict, which the adapter then fails to read (403/404) and reports."
|
|
37
|
+
ops:
|
|
38
|
+
app:
|
|
39
|
+
kind: resource
|
|
40
|
+
title: App
|
|
41
|
+
summary: "A Fly app per pull request, such as `demo-${ctx.scope}`, in an organization: created with `POST /v1/apps`, located by its name, deleted with its Machines on destroy (`?force=true`). Its secrets are `fly.secret` lines; the Machines are what the PR's `fly deploy` creates. Nothing about the app is compared besides its existence."
|
|
42
|
+
covers: [fly-secrets]
|
|
43
|
+
params:
|
|
44
|
+
app_name:
|
|
45
|
+
type: string
|
|
46
|
+
required: true
|
|
47
|
+
pattern: "^[a-z0-9][a-z0-9-]*$"
|
|
48
|
+
description: The app's name, unique across Fly.io.
|
|
49
|
+
example: "demo-${ctx.scope}"
|
|
50
|
+
org_slug:
|
|
51
|
+
type: string
|
|
52
|
+
required: true
|
|
53
|
+
description: The organization the app is created in.
|
|
54
|
+
example: acme
|
|
55
|
+
network:
|
|
56
|
+
type: string
|
|
57
|
+
description: A private network (6PN) to put the app on.
|
|
58
|
+
http:
|
|
59
|
+
read: { path: "/apps/{app_name}" }
|
|
60
|
+
create:
|
|
61
|
+
path: /apps
|
|
62
|
+
body: { app_name: { param: app_name }, org_slug: { param: org_slug }, network: { param: network } }
|
|
63
|
+
delete: { path: "/apps/{app_name}?force=true" }
|
|
64
|
+
sim:
|
|
65
|
+
id_from: app_name
|
|
66
|
+
live:
|
|
67
|
+
params: { org_slug: SPONSON_LIVE_FLY_ORG }
|