@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sponson/adapters",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "The built-in resource adapters and secret sources for Sponson.",
5
5
  "keywords": [
6
6
  "sponson",
@@ -12,7 +12,8 @@
12
12
  "neon",
13
13
  "clerk",
14
14
  "adapters",
15
- "secrets"
15
+ "secrets",
16
+ "recipes"
16
17
  ],
17
18
  "license": "Apache-2.0",
18
19
  "repository": {
@@ -33,17 +34,23 @@
33
34
  }
34
35
  },
35
36
  "dependencies": {
36
- "@sponson/core": "0.4.0"
37
+ "yaml": "^2.8.1",
38
+ "@sponson/core": "0.5.0"
37
39
  },
38
40
  "devDependencies": {
39
- "@sponson/sim": "0.4.0"
41
+ "@sponson/sim": "0.5.0"
40
42
  },
41
43
  "files": [
42
44
  "dist",
43
45
  "!dist/.tsbuildinfo",
46
+ "recipes",
44
47
  "README.md",
45
48
  "LICENSE"
46
49
  ],
50
+ "publishConfig": {
51
+ "access": "public",
52
+ "provenance": true
53
+ },
47
54
  "homepage": "https://sponson.mintlify.site",
48
55
  "bugs": {
49
56
  "url": "https://github.com/MishaBear94/Sponson/issues"
@@ -0,0 +1,147 @@
1
+ # yaml-language-server: $schema=../../../schema/recipe.schema.json
2
+ # AWS Amplify Hosting API recipes. Format and checklist: docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
3
+ provider: amplify
4
+ title: AWS Amplify Hosting
5
+ category: deploy
6
+ verified_on: "2026-10-11"
7
+ docs:
8
+ - title: CreateBranch
9
+ url: https://docs.aws.amazon.com/amplify/latest/APIReference/API_CreateBranch.html
10
+ - title: GetBranch
11
+ url: https://docs.aws.amazon.com/amplify/latest/APIReference/API_GetBranch.html
12
+ - title: UpdateBranch
13
+ url: https://docs.aws.amazon.com/amplify/latest/APIReference/API_UpdateBranch.html
14
+ - title: DeleteBranch
15
+ url: https://docs.aws.amazon.com/amplify/latest/APIReference/API_DeleteBranch.html
16
+ - title: Amplify endpoints and quotas
17
+ url: https://docs.aws.amazon.com/general/latest/gr/amplify.html
18
+ - title: Create a signed AWS API request (SigV4)
19
+ url: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html
20
+ api:
21
+ base_url: https://amplify.us-east-1.amazonaws.com
22
+ base_url_env: AMPLIFY_API_URL
23
+ auth:
24
+ aws_sigv4: { region: us-east-1, service: amplify, access_key_id_env: AWS_ACCESS_KEY_ID, secret_access_key_env: AWS_SECRET_ACCESS_KEY }
25
+ detect:
26
+ files: [amplify.yml]
27
+ starter:
28
+ - op: branch_variable
29
+ values: { branch_name: "${ctx.git.branch}" }
30
+ where:
31
+ app_id: "Amplify console → your app → App settings → General → App ID (`d…`), or `aws amplify list-apps --query 'apps[].appId'`"
32
+ assumptions:
33
+ - id: AM1
34
+ verified: true
35
+ text: "The Amplify API is regional (`https://amplify.<region>.amazonaws.com`) and signed with SigV4 for the service `amplify`. The recipe defaults to `us-east-1`; an app in another region sets `base_url` and `auth` (with its `region`) in the provider block, and temporary credentials (a CI role) add `session_token_env: AWS_SESSION_TOKEN` there."
36
+ source: https://docs.aws.amazon.com/general/latest/gr/amplify.html
37
+ - id: AM2
38
+ verified: true
39
+ text: "`POST /apps/{appId}/branches` (CreateBranch) creates a branch from `branchName` (required) and optional `description`, `stage` (PRODUCTION, BETA, DEVELOPMENT, EXPERIMENTAL, PULL_REQUEST), `enableAutoBuild`, `environmentVariables`, …; it answers 200 with `{ branch }`."
40
+ source: https://docs.aws.amazon.com/amplify/latest/APIReference/API_CreateBranch.html
41
+ - id: AM3
42
+ verified: true
43
+ text: "`GET /apps/{appId}/branches/{branchName}` (GetBranch) answers `{ branch }` with `branchName`, `stage`, `description`, `enableAutoBuild` and `environmentVariables` (a map of string to string)."
44
+ source: https://docs.aws.amazon.com/amplify/latest/APIReference/API_GetBranch.html
45
+ - id: AM4
46
+ verified: true
47
+ text: "`POST /apps/{appId}/branches/{branchName}` (UpdateBranch) takes the same optional fields and answers `{ branch }`; `environmentVariables` is the branch's whole map of variables."
48
+ source: https://docs.aws.amazon.com/amplify/latest/APIReference/API_UpdateBranch.html
49
+ - id: AM5
50
+ verified: true
51
+ text: "`DELETE /apps/{appId}/branches/{branchName}` (DeleteBranch) deletes a branch; an unknown app or branch is 404 `NotFoundException`."
52
+ source: https://docs.aws.amazon.com/amplify/latest/APIReference/API_DeleteBranch.html
53
+ - id: AM6
54
+ verified: false
55
+ text: "UpdateBranch leaves the fields it is not sent as they are (so the branch op's update does not reset the variables, and the variable op's write does not reset the branch's settings), while an `environmentVariables` it is sent replaces the whole map, as the sim models it (assumption A4 of packages/sim/src/routes/aws.ts)."
56
+ - id: AM7
57
+ verified: false
58
+ text: "A build that ran before a variable was written does not see it: Sponson does not start a new job (StartJob), so order the variable lines before the branch's first build (`enable_auto_build: false` and a CI-started job, or the branch line, then the variables, then the push). The branches Amplify's own pull request previews make are not modelled; this recipe manages a branch the plan names."
59
+ ops:
60
+ branch:
61
+ kind: resource
62
+ title: Branch
63
+ summary: "An Amplify branch named by the plan (the git branch of the pull request, `${ctx.git.branch}`), created with CreateBranch and deleted on destroy. Its `stage`, `description` and auto-build setting are compared: a console edit is drift. Variables on it are `amplify.branch_variable` lines."
64
+ covers: [amplify-branch]
65
+ params:
66
+ app_id:
67
+ type: string
68
+ required: true
69
+ pattern: "^d[a-z0-9]+$"
70
+ description: The Amplify app's id.
71
+ example: d1demo
72
+ branch_name:
73
+ type: string
74
+ required: true
75
+ description: The branch's name, as the repository names it.
76
+ example: "${ctx.scope}"
77
+ stage:
78
+ type: string
79
+ enum: [PRODUCTION, BETA, DEVELOPMENT, EXPERIMENTAL, PULL_REQUEST]
80
+ description: The branch's stage.
81
+ example: PULL_REQUEST
82
+ description:
83
+ type: string
84
+ description: The branch's description.
85
+ example: "Preview of ${ctx.scope}"
86
+ enable_auto_build:
87
+ type: boolean
88
+ description: Build automatically on every push (false lets CI start the build after the variables are written; AM7).
89
+ http:
90
+ read: { path: "/apps/{app_id}/branches/{branch_name}" }
91
+ create:
92
+ path: "/apps/{app_id}/branches"
93
+ body: { branchName: { param: branch_name } }
94
+ update: { method: POST }
95
+ item_path: /branch
96
+ id_path: /branchName
97
+ fields:
98
+ stage: { param: stage }
99
+ description: { param: description }
100
+ enableAutoBuild: { param: enable_auto_build }
101
+ sim:
102
+ id_from: branchName
103
+ live:
104
+ params: { app_id: SPONSON_LIVE_AMPLIFY_APP_ID }
105
+ branch_variable:
106
+ kind: list_item
107
+ title: Branch environment variable
108
+ summary: "One entry of a branch's `environmentVariables`, by read-modify-write of the whole map (UpdateBranch replaces the map it is sent); other variables are left alone, and the branch is locked while Sponson writes it. A branch that is not there yet reads as having no variables, so a plan that also creates the branch shows a create. Builds started before the write do not see it (AM7)."
109
+ covers: [amplify-branch]
110
+ params:
111
+ app_id:
112
+ type: string
113
+ required: true
114
+ pattern: "^d[a-z0-9]+$"
115
+ description: The Amplify app's id.
116
+ example: d1demo
117
+ branch_name:
118
+ type: string
119
+ required: true
120
+ description: The branch's name (a `{ from }` of the `amplify.branch` line orders the two).
121
+ example: "${ctx.scope}"
122
+ name:
123
+ type: string
124
+ required: true
125
+ description: The variable's name.
126
+ example: API_URL
127
+ value:
128
+ type: string
129
+ required: true
130
+ description: The variable's value.
131
+ example: "https://api-${ctx.scope}.example.app"
132
+ http:
133
+ parent: { path: "/apps/{app_id}/branches/{branch_name}", method: POST, send: collection, item_path: /branch, if_missing: empty }
134
+ list_path: /environmentVariables
135
+ shape: map
136
+ item: { param: name }
137
+ value: { param: value }
138
+ sim:
139
+ provider: aws
140
+ base_path: /aws/amplify
141
+ seed: { amplify: { d1demo: { branches: { pr-42: { environmentVariables: { NODE_ENV: production } } } } } }
142
+ present: /amplify/d1demo/branches/pr-42/environmentVariables/API_URL
143
+ drift:
144
+ changed: { amplify.d1demo.pr-42.API_URL: "https://somewhere-else.example" }
145
+ missing: { amplify.d1demo.pr-42.API_URL: delete }
146
+ live:
147
+ params: { app_id: SPONSON_LIVE_AMPLIFY_APP_ID, branch_name: SPONSON_LIVE_AMPLIFY_BRANCH }
@@ -0,0 +1,178 @@
1
+ # yaml-language-server: $schema=../../../schema/recipe.schema.json
2
+ # Auth0 Management API recipes. Format and checklist: docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
3
+ provider: auth0
4
+ title: Auth0
5
+ category: auth
6
+ verified_on: "2026-10-11"
7
+ docs:
8
+ - title: Get Management API access tokens for production
9
+ url: https://auth0.com/docs/secure/tokens/access-tokens/management-api-access-tokens/get-management-api-access-tokens-for-production
10
+ - title: Management API v2, get a client
11
+ url: https://auth0.com/docs/api/management/v2/clients/get-clients-by-id
12
+ - title: Management API v2, update a client
13
+ url: https://auth0.com/docs/api/management/v2/clients/patch-clients-by-id
14
+ - title: Auth0 Terraform provider, configuration (conventional variable names)
15
+ url: https://raw.githubusercontent.com/auth0/terraform-provider-auth0/main/docs/index.md
16
+ api:
17
+ base_url_env: AUTH0_API_URL
18
+ auth:
19
+ oauth2_client_credentials:
20
+ token_url: /oauth/token
21
+ token_url_env: AUTH0_TOKEN_URL
22
+ client_id_env: AUTH0_CLIENT_ID
23
+ client_secret_env: AUTH0_CLIENT_SECRET
24
+ audience: /api/v2/
25
+ base_url_example: https://acme.eu.auth0.com/api/v2
26
+ detect:
27
+ deps: [auth0, "@auth0/"]
28
+ env: ["AUTH0_*"]
29
+ starter:
30
+ - op: callback_url
31
+ - op: logout_url
32
+ preview_url: url
33
+ where:
34
+ base_url: "`https://<tenant>.<region>.auth0.com/api/v2`: Auth0 Dashboard → Settings → General → Domain (the canonical domain, not a custom one)"
35
+ client_id: "Auth0 Dashboard → Applications → your application → Settings → Client ID"
36
+ url: "the exact callback URL the app sends as `redirect_uri` on a preview: its URL plus the callback path (a `{ from }` reference cannot carry a path)"
37
+ assumptions:
38
+ - id: AU1
39
+ verified: true
40
+ text: "A machine-to-machine application gets a Management API token from `POST https://<tenant>/oauth/token` (form-encoded `grant_type=client_credentials`, `client_id`, `client_secret`, `audience`); the audience is the Management API's identifier `https://<tenant>/api/v2/`. The answer has `access_token`, `expires_in` (86400 in the example) and `token_type: Bearer`. The recipe writes both as paths, so a plan's `base_url: https://<tenant>/api/v2` names the tenant once."
41
+ source: https://auth0.com/docs/secure/tokens/access-tokens/management-api-access-tokens/get-management-api-access-tokens-for-production
42
+ - id: AU2
43
+ verified: true
44
+ text: "`GET /api/v2/clients/{id}` answers the application with its `callbacks`, `allowed_logout_urls`, `web_origins` and `allowed_origins` arrays, which only a token with `read:clients` (or `read:client_keys`) receives. `fields` with `include_fields=true` limits the answer to the listed fields, so the recipe never reads the client secret."
45
+ source: https://auth0.com/docs/api/management/v2/clients/get-clients-by-id
46
+ - id: AU3
47
+ verified: true
48
+ text: "`PATCH /api/v2/clients/{id}` (scope `update:clients`) updates an application; `callbacks`, `allowed_logout_urls`, `web_origins` and `allowed_origins` are arrays of strings, and the body needs at least one property, so a write sends the one array alone."
49
+ source: https://auth0.com/docs/api/management/v2/clients/patch-clients-by-id
50
+ - id: AU4
51
+ verified: false
52
+ text: "An array sent in a PATCH replaces the stored array whole (it is not merged), so the recipe sends the full list read just before with one URL added or removed. The reference does not say so for these fields."
53
+ - id: AU5
54
+ verified: false
55
+ text: "Updates have no precondition (no ETag or version): the line locks the application (`lockOn`, one lock per tenant and client id, shared by the four ops) against other Sponson runs, and a console edit made between the read and the write can still be lost (the next apply then reports it as drift)."
56
+ - id: AU6
57
+ verified: false
58
+ text: "URLs are stored and read back exactly as written (no trailing slash added or case changed), so a URL identifies its entry."
59
+ - id: AU7
60
+ verified: true
61
+ text: "`AUTH0_CLIENT_ID` and `AUTH0_CLIENT_SECRET` are the variables the Auth0 Terraform provider reads for a machine-to-machine client."
62
+ source: https://raw.githubusercontent.com/auth0/terraform-provider-auth0/main/docs/index.md
63
+ - id: AU8
64
+ verified: false
65
+ text: "The audience stays the tenant's canonical domain when the tenant has a custom domain, so `base_url` names the canonical domain (`<tenant>.<region>.auth0.com`), not the custom one."
66
+ ops:
67
+ callback_url:
68
+ kind: list_item
69
+ title: Application callback URL
70
+ summary: "One URL in an Auth0 application's Allowed Callback URLs (`callbacks`), such as the preview's `/callback`; usually `{ from: <deploy line>.preview_url }` joined with the path in the app. Added by read-modify-write of the list under a lock on the application, removed on destroy; every other URL is left as it is. A URL removed in the Dashboard is drift (`missing`) that the next apply puts back."
71
+ covers: [auth0-callbacks]
72
+ params:
73
+ client_id:
74
+ type: string
75
+ required: true
76
+ description: The application's Client ID.
77
+ example: AbC123dEf456GhI789jKl012MnO345pQ
78
+ url:
79
+ type: string
80
+ required: true
81
+ pattern: "^https?://\\S+$"
82
+ description: "The callback URL, exactly as the application sends it as `redirect_uri`."
83
+ example: "https://${ctx.scope}.preview.example.app/callback"
84
+ http:
85
+ parent:
86
+ path: "/clients/{client_id}"
87
+ read_path: "/clients/{client_id}?fields=callbacks,allowed_logout_urls,web_origins,allowed_origins&include_fields=true"
88
+ list_path: /callbacks
89
+ item: { param: url }
90
+ sim:
91
+ objects:
92
+ "/clients/{client_id}": { callbacks: [https://app.example.com/callback], allowed_logout_urls: [https://app.example.com], web_origins: [https://app.example.com], allowed_origins: [] }
93
+ live:
94
+ params: { client_id: SPONSON_LIVE_AUTH0_APP_CLIENT_ID }
95
+ logout_url:
96
+ kind: list_item
97
+ title: Application allowed logout URL
98
+ summary: "One URL in an Auth0 application's Allowed Logout URLs (`allowed_logout_urls`), where `/v2/logout` may return the user, such as the preview's home page. Read-modify-write of the list under the application's lock; removed on destroy; every other URL is left as it is."
99
+ covers: [auth0-callbacks]
100
+ params:
101
+ client_id:
102
+ type: string
103
+ required: true
104
+ description: The application's Client ID.
105
+ example: AbC123dEf456GhI789jKl012MnO345pQ
106
+ url:
107
+ type: string
108
+ required: true
109
+ pattern: "^https?://\\S+$"
110
+ description: "The URL the application passes as `returnTo` on logout."
111
+ example: "https://${ctx.scope}.preview.example.app"
112
+ http:
113
+ parent:
114
+ path: "/clients/{client_id}"
115
+ read_path: "/clients/{client_id}?fields=callbacks,allowed_logout_urls,web_origins,allowed_origins&include_fields=true"
116
+ list_path: /allowed_logout_urls
117
+ item: { param: url }
118
+ sim:
119
+ objects:
120
+ "/clients/{client_id}": { callbacks: [https://app.example.com/callback], allowed_logout_urls: [https://app.example.com], web_origins: [https://app.example.com], allowed_origins: [] }
121
+ live:
122
+ params: { client_id: SPONSON_LIVE_AUTH0_APP_CLIENT_ID }
123
+ web_origin:
124
+ kind: list_item
125
+ title: Application allowed web origin
126
+ summary: "One origin in an Auth0 application's Allowed Web Origins (`web_origins`), which silent authentication and the SPA SDKs' token refresh need for the preview's origin. Read-modify-write of the list under the application's lock; removed on destroy; every other origin is left as it is."
127
+ covers: [auth0-callbacks]
128
+ params:
129
+ client_id:
130
+ type: string
131
+ required: true
132
+ description: The application's Client ID.
133
+ example: AbC123dEf456GhI789jKl012MnO345pQ
134
+ origin:
135
+ type: string
136
+ required: true
137
+ pattern: "^https?://[^/\\s]+$"
138
+ description: "The origin, scheme and host without a path (`https://pr-42.preview.example.app`)."
139
+ example: "https://${ctx.scope}.preview.example.app"
140
+ http:
141
+ parent:
142
+ path: "/clients/{client_id}"
143
+ read_path: "/clients/{client_id}?fields=callbacks,allowed_logout_urls,web_origins,allowed_origins&include_fields=true"
144
+ list_path: /web_origins
145
+ item: { param: origin }
146
+ sim:
147
+ objects:
148
+ "/clients/{client_id}": { callbacks: [https://app.example.com/callback], allowed_logout_urls: [https://app.example.com], web_origins: [https://app.example.com], allowed_origins: [] }
149
+ live:
150
+ params: { client_id: SPONSON_LIVE_AUTH0_APP_CLIENT_ID }
151
+ allowed_origin:
152
+ kind: list_item
153
+ title: Application allowed origin (CORS)
154
+ summary: "One origin in an Auth0 application's Allowed Origins (CORS, `allowed_origins`), for a preview that calls Auth0 from the browser across origins (embedded login, cross-origin authentication). Read-modify-write of the list under the application's lock; removed on destroy; every other origin is left as it is."
155
+ covers: [auth0-callbacks]
156
+ params:
157
+ client_id:
158
+ type: string
159
+ required: true
160
+ description: The application's Client ID.
161
+ example: AbC123dEf456GhI789jKl012MnO345pQ
162
+ origin:
163
+ type: string
164
+ required: true
165
+ pattern: "^https?://[^/\\s]+$"
166
+ description: "The origin, scheme and host without a path (`https://pr-42.preview.example.app`)."
167
+ example: "https://${ctx.scope}.preview.example.app"
168
+ http:
169
+ parent:
170
+ path: "/clients/{client_id}"
171
+ read_path: "/clients/{client_id}?fields=callbacks,allowed_logout_urls,web_origins,allowed_origins&include_fields=true"
172
+ list_path: /allowed_origins
173
+ item: { param: origin }
174
+ sim:
175
+ objects:
176
+ "/clients/{client_id}": { callbacks: [https://app.example.com/callback], allowed_logout_urls: [https://app.example.com], web_origins: [https://app.example.com], allowed_origins: [] }
177
+ live:
178
+ params: { client_id: SPONSON_LIVE_AUTH0_APP_CLIENT_ID }
@@ -0,0 +1,116 @@
1
+ # yaml-language-server: $schema=../../../schema/recipe.schema.json
2
+ # Azure Static Web Apps (Azure Resource Manager) recipes. Format and checklist: docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
3
+ provider: azure_swa
4
+ title: Azure Static Web Apps
5
+ category: deploy
6
+ verified_on: "2026-10-11"
7
+ docs:
8
+ - title: Static Sites - Create Or Update Static Site Build App Settings
9
+ url: https://learn.microsoft.com/en-us/rest/api/appservice/static-sites/create-or-update-static-site-build-app-settings?view=rest-appservice-2024-04-01
10
+ - title: Static Sites - List Static Site Build App Settings
11
+ url: https://learn.microsoft.com/en-us/rest/api/appservice/static-sites/list-static-site-build-app-settings?view=rest-appservice-2024-04-01
12
+ - title: Static Sites - Get Static Site Builds
13
+ url: https://learn.microsoft.com/en-us/rest/api/appservice/static-sites/get-static-site-builds?view=rest-appservice-2024-04-01
14
+ - title: Preview environments in Azure Static Web Apps
15
+ url: https://learn.microsoft.com/en-us/azure/static-web-apps/preview-environments
16
+ - title: Configure application settings for Azure Static Web Apps
17
+ url: https://learn.microsoft.com/en-us/azure/static-web-apps/application-settings
18
+ - title: az account get-access-token
19
+ url: https://learn.microsoft.com/en-us/cli/azure/account#az-account-get-access-token
20
+ api:
21
+ base_url: https://management.azure.com
22
+ base_url_env: AZURE_SWA_API_URL
23
+ auth: { command: [az, account, get-access-token, --query, accessToken, -o, tsv] }
24
+ detect:
25
+ files: [staticwebapp.config.json]
26
+ env: ["AZURE_STATIC_WEB_APPS_*"]
27
+ starter:
28
+ - op: build_app_setting
29
+ values: { environment: "${ctx.pr.number}" }
30
+ where:
31
+ subscription_id: "`az account show --query id -o tsv`"
32
+ resource_group: "`az staticwebapp show --name <site> --query resourceGroup -o tsv`"
33
+ site: "`az staticwebapp list --query '[].name'`"
34
+ assumptions:
35
+ - id: AZ1
36
+ verified: true
37
+ text: "`PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/staticSites/{name}/builds/{environmentName}/config/appsettings?api-version=2024-04-01` with `{ properties: { <name>: <value>, … } }` sets the app settings of one environment (build) and answers 200 with the same `properties`."
38
+ source: https://learn.microsoft.com/en-us/rest/api/appservice/static-sites/create-or-update-static-site-build-app-settings?view=rest-appservice-2024-04-01
39
+ - id: AZ2
40
+ verified: true
41
+ text: "The settings are read with `POST …/builds/{environmentName}/listAppSettings?api-version=2024-04-01` (no body), which answers a StringDictionary `{ id, properties }`; there is no GET, so the recipe reads with `parent.read_method: POST`."
42
+ source: https://learn.microsoft.com/en-us/rest/api/appservice/static-sites/list-static-site-build-app-settings?view=rest-appservice-2024-04-01
43
+ - id: AZ3
44
+ verified: true
45
+ text: "Each environment is a `builds/{environmentName}` resource: production is `default`, a pull request's preview environment is named by the pull request's number (`builds/12`)."
46
+ source: https://learn.microsoft.com/en-us/rest/api/appservice/static-sites/get-static-site-builds?view=rest-appservice-2024-04-01
47
+ - id: AZ4
48
+ verified: true
49
+ text: "A preview environment exists from the pull request's first deployment and is deleted, with its settings, when the pull request is closed; app settings reach the app's managed API (Functions), not the front-end build."
50
+ source: https://learn.microsoft.com/en-us/azure/static-web-apps/preview-environments
51
+ - id: AZ5
52
+ verified: true
53
+ text: "`az account get-access-token --query accessToken -o tsv` prints an Azure Resource Manager access token for the signed-in account (the default resource is `https://management.azure.com/`), sent as a bearer token."
54
+ source: https://learn.microsoft.com/en-us/cli/azure/account#az-account-get-access-token
55
+ - id: AZ6
56
+ verified: false
57
+ text: "The PUT replaces the whole settings map (a setting it is not sent is removed), so the recipe sends the map as read with the one entry changed (`send: collection`); there is no ETag on this resource, so only Sponson's own writers are serialised (the parent lock), and a setting added in the portal between the read and the write is lost."
58
+ - id: AZ7
59
+ verified: false
60
+ text: "Listing the settings of an environment that does not exist (not deployed yet, or deleted with its pull request) answers 404, which the recipe reads as no settings (`if_missing: empty`): plan shows a create before the first deploy, and destroy after the pull request closed is a no-op. A write before the first deploy fails with that 404; order the line after the deploy."
61
+ ops:
62
+ build_app_setting:
63
+ kind: list_item
64
+ title: App setting of a preview environment
65
+ summary: "One app setting of a Static Web App environment (a pull request's preview environment is named by its number), by read-modify-write of the environment's settings: read with `listAppSettings`, written whole with a PUT. Other settings are left alone and the environment is locked while Sponson writes it. Settings reach the app's managed API, not the front-end build (AZ4); the environment exists only after the PR's first deploy (AZ7)."
66
+ covers: [azure-swa-settings]
67
+ params:
68
+ subscription_id:
69
+ type: string
70
+ required: true
71
+ description: The Azure subscription id.
72
+ example: 00000000-0000-0000-0000-000000000000
73
+ resource_group:
74
+ type: string
75
+ required: true
76
+ description: The resource group of the static web app.
77
+ example: rg-web
78
+ site:
79
+ type: string
80
+ required: true
81
+ description: The static web app's name.
82
+ example: web
83
+ environment:
84
+ type: string
85
+ required: true
86
+ pattern: "^[a-zA-Z0-9]+$"
87
+ description: The environment's name (the pull request's number for its preview environment; `default` is production).
88
+ example: "42"
89
+ name:
90
+ type: string
91
+ required: true
92
+ description: The setting's name.
93
+ example: API_URL
94
+ value:
95
+ type: string
96
+ required: true
97
+ description: The setting's value.
98
+ example: "https://api-${ctx.scope}.example.app"
99
+ http:
100
+ parent:
101
+ path: "/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Web/staticSites/{site}/builds/{environment}/config/appsettings?api-version=2024-04-01"
102
+ read_path: "/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Web/staticSites/{site}/builds/{environment}/listAppSettings?api-version=2024-04-01"
103
+ read_method: POST
104
+ method: PUT
105
+ send: collection
106
+ if_missing: empty
107
+ list_path: /properties
108
+ shape: map
109
+ item: { param: name }
110
+ value: { param: value }
111
+ sim:
112
+ objects:
113
+ "/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Web/staticSites/{site}/builds/{environment}/config/appsettings":
114
+ properties: { SHARED_SETTING: from-the-portal }
115
+ live:
116
+ params: { subscription_id: SPONSON_LIVE_AZURE_SUBSCRIPTION_ID, resource_group: SPONSON_LIVE_AZURE_RESOURCE_GROUP, site: SPONSON_LIVE_AZURE_SWA_SITE, environment: SPONSON_LIVE_AZURE_SWA_ENVIRONMENT }
@@ -0,0 +1,97 @@
1
+ # yaml-language-server: $schema=../../../schema/recipe.schema.json
2
+ # Google Cloud Run Admin API v2 recipes. Format and checklist: docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
3
+ provider: cloud_run
4
+ title: Google Cloud Run
5
+ category: deploy
6
+ verified_on: "2026-10-11"
7
+ docs:
8
+ - title: "REST Resource: projects.locations.services (Service, TrafficTarget)"
9
+ url: https://docs.cloud.google.com/run/docs/reference/rest/v2/projects.locations.services
10
+ - title: "Method: projects.locations.services.patch"
11
+ url: https://docs.cloud.google.com/run/docs/reference/rest/v2/projects.locations.services/patch
12
+ - title: "Method: projects.locations.services.get"
13
+ url: https://docs.cloud.google.com/run/docs/reference/rest/v2/projects.locations.services/get
14
+ - title: Rollbacks, gradual rollouts, and traffic migration (tags)
15
+ url: https://cloud.google.com/run/docs/rollouts-rollbacks-traffic-migration
16
+ - title: gcloud auth print-access-token
17
+ url: https://cloud.google.com/sdk/gcloud/reference/auth/print-access-token
18
+ api:
19
+ base_url: https://run.googleapis.com/v2
20
+ base_url_env: CLOUD_RUN_API_URL
21
+ auth: { command: [gcloud, auth, print-access-token] }
22
+ assumptions:
23
+ - id: CR1
24
+ verified: true
25
+ text: "`GET https://run.googleapis.com/v2/projects/{project}/locations/{location}/services/{service}` answers the Service with its `traffic` list and an `etag`, 'a system-generated fingerprint for this version of the resource' that 'may be used to detect modification conflict during updates'."
26
+ source: https://docs.cloud.google.com/run/docs/reference/rest/v2/projects.locations.services
27
+ - id: CR2
28
+ verified: true
29
+ text: "`PATCH https://run.googleapis.com/v2/{service.name}` takes a Service and an optional `updateMask` (fields to update), answers a long-running Operation, and needs the `cloud-platform` scope; the recipe sends `?updateMask=traffic` with `{ traffic, etag }` only, so the revision template is never written."
30
+ source: https://docs.cloud.google.com/run/docs/reference/rest/v2/projects.locations.services/patch
31
+ - id: CR3
32
+ verified: true
33
+ text: "A TrafficTarget is `{ type, revision, percent, tag }`; `type: TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION` sends traffic to the named `revision`, `percent` defaults to zero, and `tag` is 'a string to be part of the URI to exclusively reference this target', which is the per-PR URL."
34
+ source: https://docs.cloud.google.com/run/docs/reference/rest/v2/projects.locations.services
35
+ - id: CR4
36
+ verified: true
37
+ text: "`gcloud auth print-access-token` prints an OAuth access token for the active account, sent as a bearer token."
38
+ source: https://cloud.google.com/sdk/gcloud/reference/auth/print-access-token
39
+ - id: CR5
40
+ verified: false
41
+ text: "A patch whose `etag` no longer matches (a deploy changed the service after the read) is refused (409 ABORTED or 412) rather than applied: the line fails and the next apply reads again, so a concurrent `gcloud run deploy` is never overwritten. Sponson's own writers are serialised by the parent lock."
42
+ - id: CR6
43
+ verified: false
44
+ text: "The Service answered right after the patch's Operation is accepted already shows the new `traffic` (the desired state), so the re-read that confirms the write sees the tag; `percent` 0 is left out of the answer and `type` and `revision` are answered as sent."
45
+ - id: CR7
46
+ verified: false
47
+ text: "The revision a tag points to exists before the line applies: the PR's deploy creates it (`gcloud run deploy --no-traffic --revision-suffix <scope>` gives `<service>-<scope>`). Its environment variables are part of that revision, set by the deploy, not by this recipe; a deploy that tags (`--tag`) itself conflicts with this line's tag."
48
+ ops:
49
+ traffic_tag:
50
+ kind: list_item
51
+ title: Traffic tag of a revision
52
+ summary: "A tag (`pr-42`) in a service's `traffic` list pointing at the PR's revision with no traffic share, which gives the revision its own URL (`https://pr-42---<service>-<hash>.a.run.app`). Read-modify-write of `traffic` only (`updateMask=traffic`), sent with the service's `etag` so a concurrent deploy makes the write fail instead of being overwritten (CR5); other tags and the traffic split are left alone, and destroy removes only this tag. The revision itself, and its environment variables, are the deploy's (CR7)."
53
+ covers: []
54
+ params:
55
+ project:
56
+ type: string
57
+ required: true
58
+ description: The Google Cloud project id.
59
+ example: demo-project
60
+ region:
61
+ type: string
62
+ required: true
63
+ description: The service's region.
64
+ example: us-central1
65
+ service:
66
+ type: string
67
+ required: true
68
+ description: The Cloud Run service's name.
69
+ example: web
70
+ tag:
71
+ type: string
72
+ required: true
73
+ pattern: "^[a-z][a-z0-9-]*$"
74
+ description: The tag, the prefix of the revision's own URL.
75
+ example: "${ctx.scope}"
76
+ revision:
77
+ type: string
78
+ required: true
79
+ description: The revision the tag points to (made by the PR's deploy).
80
+ example: "web-${ctx.scope}"
81
+ http:
82
+ parent:
83
+ path: "/projects/{project}/locations/{region}/services/{service}?updateMask=traffic"
84
+ read_path: "/projects/{project}/locations/{region}/services/{service}"
85
+ method: PATCH
86
+ send: [etag]
87
+ list_path: /traffic
88
+ key_field: tag
89
+ item: { tag: { param: tag }, revision: { param: revision }, type: TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION }
90
+ sim:
91
+ objects:
92
+ "/projects/{project}/locations/{region}/services/{service}":
93
+ name: projects/demo-project/locations/us-central1/services/web
94
+ etag: '"sim-etag-1"'
95
+ traffic: [{ type: TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST, percent: 100 }]
96
+ live:
97
+ params: { project: SPONSON_LIVE_GCP_PROJECT, region: SPONSON_LIVE_CLOUD_RUN_REGION, service: SPONSON_LIVE_CLOUD_RUN_SERVICE, revision: SPONSON_LIVE_CLOUD_RUN_REVISION }