@sponson/adapters 0.4.0 → 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.
Files changed (127) hide show
  1. package/README.md +1 -1
  2. package/dist/algolia.d.ts +6 -0
  3. package/dist/algolia.js +151 -0
  4. package/dist/algolia.js.map +1 -0
  5. package/dist/clerk.js +1 -1
  6. package/dist/clerk.js.map +1 -1
  7. package/dist/cloudflare.d.ts +25 -0
  8. package/dist/cloudflare.js +310 -0
  9. package/dist/cloudflare.js.map +1 -0
  10. package/dist/common.d.ts +2 -6
  11. package/dist/common.js.map +1 -1
  12. package/dist/digest.d.ts +46 -0
  13. package/dist/digest.js +129 -0
  14. package/dist/digest.js.map +1 -0
  15. package/dist/digitalocean.d.ts +5 -0
  16. package/dist/digitalocean.js +243 -0
  17. package/dist/digitalocean.js.map +1 -0
  18. package/dist/http-adapter-action.d.ts +63 -0
  19. package/dist/http-adapter-action.js +369 -0
  20. package/dist/http-adapter-action.js.map +1 -0
  21. package/dist/http-adapter-auth.d.ts +88 -0
  22. package/dist/http-adapter-auth.js +437 -0
  23. package/dist/http-adapter-auth.js.map +1 -0
  24. package/dist/http-adapter-client.d.ts +51 -0
  25. package/dist/http-adapter-client.js +156 -0
  26. package/dist/http-adapter-client.js.map +1 -0
  27. package/dist/http-adapter-graphql.d.ts +39 -0
  28. package/dist/http-adapter-graphql.js +157 -0
  29. package/dist/http-adapter-graphql.js.map +1 -0
  30. package/dist/http-adapter-list.d.ts +33 -0
  31. package/dist/http-adapter-list.js +421 -0
  32. package/dist/http-adapter-list.js.map +1 -0
  33. package/dist/http-adapter-resource.d.ts +29 -0
  34. package/dist/http-adapter-resource.js +462 -0
  35. package/dist/http-adapter-resource.js.map +1 -0
  36. package/dist/http-adapter-spec.d.ts +216 -0
  37. package/dist/http-adapter-spec.js +660 -0
  38. package/dist/http-adapter-spec.js.map +1 -0
  39. package/dist/http-adapter.d.ts +16 -0
  40. package/dist/http-adapter.js +28 -0
  41. package/dist/http-adapter.js.map +1 -0
  42. package/dist/http.d.ts +61 -2
  43. package/dist/http.js +79 -18
  44. package/dist/http.js.map +1 -1
  45. package/dist/index.d.ts +12 -0
  46. package/dist/index.js +24 -2
  47. package/dist/index.js.map +1 -1
  48. package/dist/launchdarkly.d.ts +15 -0
  49. package/dist/launchdarkly.js +337 -0
  50. package/dist/launchdarkly.js.map +1 -0
  51. package/dist/manual.d.ts +13 -0
  52. package/dist/manual.js +201 -0
  53. package/dist/manual.js.map +1 -0
  54. package/dist/neon.js +1 -1
  55. package/dist/neon.js.map +1 -1
  56. package/dist/netlify.d.ts +18 -0
  57. package/dist/netlify.js +436 -0
  58. package/dist/netlify.js.map +1 -0
  59. package/dist/planetscale.d.ts +10 -0
  60. package/dist/planetscale.js +311 -0
  61. package/dist/planetscale.js.map +1 -0
  62. package/dist/providers.d.ts +26 -0
  63. package/dist/providers.js +36 -0
  64. package/dist/providers.js.map +1 -0
  65. package/dist/recipes.d.ts +167 -0
  66. package/dist/recipes.js +246 -0
  67. package/dist/recipes.js.map +1 -0
  68. package/dist/secrets.d.ts +44 -0
  69. package/dist/secrets.js +279 -0
  70. package/dist/secrets.js.map +1 -1
  71. package/dist/sigv4.d.ts +56 -0
  72. package/dist/sigv4.js +118 -0
  73. package/dist/sigv4.js.map +1 -0
  74. package/dist/supabase.d.ts +9 -0
  75. package/dist/supabase.js +385 -0
  76. package/dist/supabase.js.map +1 -0
  77. package/dist/vercel.js +1 -1
  78. package/dist/vercel.js.map +1 -1
  79. package/dist/xata.d.ts +8 -0
  80. package/dist/xata.js +142 -0
  81. package/dist/xata.js.map +1 -0
  82. package/dist/xml.d.ts +25 -0
  83. package/dist/xml.js +211 -0
  84. package/dist/xml.js.map +1 -0
  85. package/package.json +11 -4
  86. package/recipes/amplify.yaml +147 -0
  87. package/recipes/auth0.yaml +178 -0
  88. package/recipes/azure_swa.yaml +116 -0
  89. package/recipes/cloud_run.yaml +97 -0
  90. package/recipes/cloudflare.yaml +108 -0
  91. package/recipes/cockroachdb.yaml +132 -0
  92. package/recipes/configcat.yaml +123 -0
  93. package/recipes/datadog.yaml +136 -0
  94. package/recipes/firebase.yaml +84 -0
  95. package/recipes/flagsmith.yaml +98 -0
  96. package/recipes/fly.yaml +97 -0
  97. package/recipes/fly_machines.yaml +67 -0
  98. package/recipes/gcs.yaml +102 -0
  99. package/recipes/github.yaml +123 -0
  100. package/recipes/growthbook.yaml +124 -0
  101. package/recipes/heroku.yaml +98 -0
  102. package/recipes/honeycomb.yaml +89 -0
  103. package/recipes/inngest.yaml +97 -0
  104. package/recipes/kinde.yaml +120 -0
  105. package/recipes/mongodb_atlas.yaml +119 -0
  106. package/recipes/okta.yaml +177 -0
  107. package/recipes/posthog.yaml +127 -0
  108. package/recipes/postmark.yaml +105 -0
  109. package/recipes/postmark_server.yaml +93 -0
  110. package/recipes/prisma.yaml +150 -0
  111. package/recipes/qstash.yaml +134 -0
  112. package/recipes/railway.yaml +130 -0
  113. package/recipes/render.yaml +103 -0
  114. package/recipes/resend.yaml +130 -0
  115. package/recipes/s3.yaml +108 -0
  116. package/recipes/sendgrid.yaml +165 -0
  117. package/recipes/sentry.yaml +158 -0
  118. package/recipes/split.yaml +121 -0
  119. package/recipes/statsig.yaml +124 -0
  120. package/recipes/stripe.yaml +310 -0
  121. package/recipes/stytch.yaml +113 -0
  122. package/recipes/svix.yaml +109 -0
  123. package/recipes/turso.yaml +98 -0
  124. package/recipes/unleash.yaml +149 -0
  125. package/recipes/upstash.yaml +130 -0
  126. package/recipes/vercel.yaml +116 -0
  127. package/recipes/workos.yaml +70 -0
@@ -0,0 +1,108 @@
1
+ # yaml-language-server: $schema=../../../schema/recipe.schema.json
2
+ # Cloudflare API v4 recipes. Format and checklist: docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
3
+ provider: cloudflare
4
+ title: Cloudflare
5
+ category: dns
6
+ verified_on: "2026-10-11"
7
+ docs:
8
+ - title: Create DNS record
9
+ url: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/create/
10
+ - title: List DNS records
11
+ url: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/list/
12
+ - title: DNS record details
13
+ url: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/get/
14
+ - title: Update DNS record (PATCH)
15
+ url: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/edit/
16
+ - title: Delete DNS record
17
+ url: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/delete/
18
+ api:
19
+ base_url: https://api.cloudflare.com/client/v4
20
+ base_url_env: CLOUDFLARE_API_URL
21
+ auth: { bearer_env: CLOUDFLARE_API_TOKEN }
22
+ assumptions:
23
+ - id: CF1
24
+ verified: true
25
+ text: "Records are created with `POST /zones/{zone_id}/dns_records` (`type`, `name`, `content`, `ttl`, `proxied`, `comment`), authenticated with an API token as `Authorization: Bearer` that has DNS Write on the zone."
26
+ source: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/create/
27
+ - id: CF2
28
+ verified: true
29
+ text: "`GET /zones/{zone_id}/dns_records` answers `{ result: [...] }` and filters by `type` and `name.exact` (names compare case-insensitively)."
30
+ source: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/list/
31
+ - id: CF3
32
+ verified: true
33
+ text: "Single-record answers (create, details, update) carry the record under `result`, with its `id`."
34
+ source: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/get/
35
+ - id: CF4
36
+ verified: true
37
+ text: "`PATCH /zones/{zone_id}/dns_records/{id}` updates a record; `DELETE` on the same path removes it permanently."
38
+ source: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/delete/
39
+ - id: CF5
40
+ verified: false
41
+ text: "A PATCH needs `name` and `type` alongside the changed fields (the edit schema does not mark them optional), so every update sends both."
42
+ source: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/edit/
43
+ - id: CF6
44
+ verified: false
45
+ text: "The API returns `name` lower-cased as the full name and `content` as written, so `name` must be given lower-case and fully qualified, or every plan finds no record and tries to create one."
46
+ - id: CF7
47
+ verified: false
48
+ text: "A proxied record reports `ttl: 1` (automatic) whatever was sent, so `ttl` other than 1 with `proxied: true` shows as drift on every plan."
49
+ - id: CF8
50
+ verified: true
51
+ text: A CNAME cannot share its name with another record, so name and type identify it within the zone and a filtered list holds at most one, on its first page.
52
+ source: https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/create/
53
+ ops:
54
+ dns_cname:
55
+ kind: resource
56
+ title: DNS CNAME record
57
+ summary: A CNAME record in a zone, such as `pr-42.preview.example.com` pointing at the preview deployment's host. Located by name and type; a console edit of its target, proxying, TTL or comment is drift.
58
+ covers: [cloudflare-dns]
59
+ params:
60
+ zone_id:
61
+ type: string
62
+ required: true
63
+ pattern: "^[0-9a-f]{32}$"
64
+ description: The zone's id (32 hex characters, on the zone's Overview page).
65
+ example: 023e105f4ecef8ad9ca31a8372d0c353
66
+ name:
67
+ type: string
68
+ required: true
69
+ pattern: "^[a-z0-9*_.-]+$"
70
+ description: The record's full name, lower-case, zone included.
71
+ example: "${ctx.scope}.preview.example.com"
72
+ target:
73
+ type: string
74
+ required: true
75
+ description: The host the name points at (the record's `content`).
76
+ example: preview-host.example.net
77
+ proxied:
78
+ type: boolean
79
+ default: false
80
+ description: Whether Cloudflare proxies the traffic.
81
+ ttl:
82
+ type: integer
83
+ default: 1
84
+ description: TTL in seconds (60–86400), or 1 for automatic.
85
+ comment:
86
+ type: string
87
+ description: A note on the record; no effect on DNS.
88
+ example: Managed by Sponson
89
+ http:
90
+ find:
91
+ path: "/zones/{zone_id}/dns_records?type=CNAME&name.exact={name}"
92
+ list_path: /result
93
+ match: { type: CNAME, name: { param: name } }
94
+ create: { path: "/zones/{zone_id}/dns_records" }
95
+ update:
96
+ method: PATCH
97
+ path: "/zones/{zone_id}/dns_records/{id}"
98
+ body: { type: CNAME, name: { param: name } }
99
+ delete: { path: "/zones/{zone_id}/dns_records/{id}" }
100
+ item_path: /result
101
+ fields:
102
+ content: { param: target }
103
+ proxied: { param: proxied }
104
+ ttl: { param: ttl }
105
+ comment: { param: comment }
106
+ outputs: { hostname: /name }
107
+ live:
108
+ params: { zone_id: SPONSON_LIVE_CLOUDFLARE_ZONE_ID, name: SPONSON_LIVE_CLOUDFLARE_NAME }
@@ -0,0 +1,132 @@
1
+ # yaml-language-server: $schema=../../../schema/recipe.schema.json
2
+ # CockroachDB Cloud API recipes (service account API key, bearer). Format and checklist: docs/adr/0020-recipes.md,
3
+ # CONTRIBUTING.md "Adding a recipe".
4
+ provider: cockroachdb
5
+ title: CockroachDB Cloud
6
+ category: databases
7
+ verified_on: "2026-10-11"
8
+ docs:
9
+ - title: Cloud API OpenAPI document (version 2026-09-15)
10
+ url: https://cockroachlabs.cloud/assets/docs/api/latest/openapi.json
11
+ - title: Use the CockroachDB Cloud API
12
+ url: https://docs.cockroachlabs.com/docs/cockroachcloud/cloud-api
13
+ api:
14
+ base_url: https://cockroachlabs.cloud/api/v1
15
+ base_url_env: COCKROACH_API_URL
16
+ auth: { bearer_env: COCKROACH_API_KEY }
17
+ headers: { Cc-Version: "2024-09-16" }
18
+ detect:
19
+ env: ["COCKROACH_*"]
20
+ db_hosts: [.cockroachlabs.cloud]
21
+ starter:
22
+ - op: database
23
+ values: { name: "app_${ctx.scope}" }
24
+ where:
25
+ cluster_id: "CockroachDB Cloud Console → your cluster (the UUID in its URL), or `ccloud cluster list`"
26
+ assumptions:
27
+ - id: CR1
28
+ verified: true
29
+ text: "The Cloud API authenticates with a service account's secret key as `Authorization: Bearer`; the key has the service account's roles."
30
+ source: https://docs.cockroachlabs.com/docs/cockroachcloud/cloud-api
31
+ - id: CR2
32
+ verified: true
33
+ text: "`Cc-Version` pins the API version (`YYYY-MM-DD`); without it the latest version answers, which may change under a client. The guide documents `2024-09-16`."
34
+ source: https://docs.cockroachlabs.com/docs/cockroachcloud/cloud-api
35
+ - id: CR3
36
+ verified: true
37
+ text: "`POST /clusters/{cluster_id}/databases` with `{ name }` creates a database and answers `{ name, table_count }`; `GET` on the same path lists `{ databases: [{ name, table_count }], pagination: { next_page } }`, paged with `pagination.page`; `DELETE /clusters/{cluster_id}/databases/{name}` deletes one. There is no GET of a single database."
38
+ source: https://cockroachlabs.cloud/assets/docs/api/latest/openapi.json
39
+ - id: CR4
40
+ verified: true
41
+ text: "`POST /clusters/{cluster_id}/sql-users` with `{ name, password }` (both required) creates a SQL user; `GET` on the same path lists `{ users: [{ name }], pagination: { next_page } }`; `DELETE /clusters/{cluster_id}/sql-users/{name}` deletes one. The password cannot be read back; `PUT …/sql-users/{name}/password` changes it."
42
+ source: https://cockroachlabs.cloud/assets/docs/api/latest/openapi.json
43
+ - id: CR5
44
+ verified: true
45
+ text: "A SQL user created through the API gets the SQL `admin` role by default, which the guide advises against for anything but administration."
46
+ source: https://docs.cockroachlabs.com/docs/cockroachcloud/cloud-api
47
+ - id: CR6
48
+ verified: true
49
+ text: "Creating or deleting databases and SQL users needs a cluster-level role of the service account (Cluster Admin, Cluster Operator or Cluster Data Accessor for databases; Cluster Admin for SQL users)."
50
+ source: https://cockroachlabs.cloud/assets/docs/api/latest/openapi.json
51
+ - id: CR7
52
+ verified: false
53
+ text: "`COCKROACH_API_KEY` is the variable the CockroachDB Terraform provider and `ccloud` read the key from."
54
+ - id: CR8
55
+ verified: false
56
+ text: "A second create of an existing database or SQL user is refused with 409 (ALREADY_EXISTS), and deleting one that is gone answers 404."
57
+ - id: CR9
58
+ verified: false
59
+ text: "Deleting a database drops it with its tables (CASCADE); the API offers no way to refuse when it holds data."
60
+ - id: CR10
61
+ verified: false
62
+ text: "The API takes database and user names that need quoting in SQL (`app_pr-42`, from a scope with `-`) and quotes them itself."
63
+ ops:
64
+ database:
65
+ kind: resource
66
+ title: Database in a cluster
67
+ summary: "A database per scope in a shared CockroachDB Cloud cluster, such as `app_pr_42`, instead of a cluster per preview. Located by its name in the cluster's list; only its existence is compared (the API exposes nothing else to set); destroy drops it with its data (CR9)."
68
+ covers: [cockroachdb-database]
69
+ params:
70
+ cluster_id:
71
+ type: string
72
+ required: true
73
+ description: The cluster's id (a UUID, shown in the Cloud Console's URL).
74
+ example: 9e3f1a52-63d1-4a4c-9b8f-2c8b7a0e5d11
75
+ name:
76
+ type: string
77
+ required: true
78
+ pattern: "^[A-Za-z_][A-Za-z0-9_.-]{0,62}$"
79
+ description: "The database's name; its identity. A name with `-` (a scope such as `pr-42`) needs quoting in SQL (CR10)."
80
+ example: "app_${ctx.scope}"
81
+ http:
82
+ find:
83
+ path: "/clusters/{cluster_id}/databases"
84
+ list_path: /databases
85
+ match: { name: { param: name } }
86
+ next: /pagination/next_page
87
+ cursor_param: pagination.page
88
+ create: { path: "/clusters/{cluster_id}/databases" }
89
+ delete: { path: "/clusters/{cluster_id}/databases/{id}" }
90
+ id_path: /name
91
+ sim:
92
+ id_from: name
93
+ live:
94
+ params: { cluster_id: SPONSON_LIVE_COCKROACH_CLUSTER_ID }
95
+ sql_user:
96
+ kind: resource
97
+ title: SQL user in a cluster
98
+ summary: "A SQL user per scope in a shared CockroachDB Cloud cluster, such as `app_pr_42`, with its password as an input (`{ secret: … }`, or a sensitive output of another line), sent on create only and never compared. It gets the SQL `admin` role (CR5): grant narrower privileges in SQL if previews must not administer the cluster. Located by its name; destroy deletes the user."
99
+ covers: []
100
+ params:
101
+ cluster_id:
102
+ type: string
103
+ required: true
104
+ description: The cluster's id (a UUID, shown in the Cloud Console's URL).
105
+ example: 9e3f1a52-63d1-4a4c-9b8f-2c8b7a0e5d11
106
+ name:
107
+ type: string
108
+ required: true
109
+ pattern: "^[A-Za-z_][A-Za-z0-9_.-]{0,62}$"
110
+ description: The user's name; its identity.
111
+ example: "app_${ctx.scope}"
112
+ password:
113
+ type: string
114
+ required: true
115
+ description: "The user's password, as a reference (`{ secret: env://… }`, or `{ from: <line>.<output> }` of a sensitive output); sent on create only (CR4)."
116
+ example: { secret: "env://PREVIEW_DB_PASSWORD" }
117
+ http:
118
+ find:
119
+ path: "/clusters/{cluster_id}/sql-users"
120
+ list_path: /users
121
+ match: { name: { param: name } }
122
+ next: /pagination/next_page
123
+ cursor_param: pagination.page
124
+ create:
125
+ path: "/clusters/{cluster_id}/sql-users"
126
+ body: { password: { param: password } }
127
+ delete: { path: "/clusters/{cluster_id}/sql-users/{id}" }
128
+ id_path: /name
129
+ sim:
130
+ id_from: name
131
+ live:
132
+ params: { cluster_id: SPONSON_LIVE_COCKROACH_CLUSTER_ID }
@@ -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 }