History

refactor(cloud): keep relay infra config unprefixed

Julius Marminge committed 5 months ago

Commit c48c5601 parent cc24a999 files · +78 −28Browse files

Unified · Split

9 files
  1. .github/workflows/deploy-relay.yml +3 −3
  2. .github/workflows/release.yml +6 −6
  3. docs/release.md +4 −4
  4. docs/t3-cloud-clerk.md +4 −4
  5. infra/relay/.env.example +3 −3
  6. infra/relay/README.md +5 −5
  7. infra/relay/src/worker.ts +1 −1
  8. infra/relay/src/zone.test.ts +50 −0
  9. infra/relay/src/zone.ts +2 −2
.github/workflows/deploy-relay.yml+3−3
@@ -29,9 +29,9 @@ jobs: · 28 unmodified lines
29 PLANETSCALE_ORGANIZATION: ${{ vars.PLANETSCALE_ORGANIZATION }}29 PLANETSCALE_ORGANIZATION: ${{ vars.PLANETSCALE_ORGANIZATION }}
30 AXIOM_TOKEN: ${{ secrets.AXIOM_TOKEN }}30 AXIOM_TOKEN: ${{ secrets.AXIOM_TOKEN }}
31 AXIOM_ORG_ID: ${{ vars.AXIOM_ORG_ID }}31 AXIOM_ORG_ID: ${{ vars.AXIOM_ORG_ID }}
32 T3CODE_RELAY_DOMAIN: ${{ vars.T3CODE_RELAY_DOMAIN }}32 RELAY_DOMAIN: ${{ vars.RELAY_DOMAIN }}
33 T3CODE_RELAY_ZONE_NAME: ${{ vars.T3CODE_RELAY_ZONE_NAME }}33 RELAY_ZONE_NAME: ${{ vars.RELAY_ZONE_NAME }}
34 T3CODE_CLERK_PUBLISHABLE_KEY: ${{ vars.T3CODE_CLERK_PUBLISHABLE_KEY }}34 CLERK_PUBLISHABLE_KEY: ${{ vars.CLERK_PUBLISHABLE_KEY }}
35 CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}35 CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
36 APNS_ENVIRONMENT: ${{ vars.APNS_ENVIRONMENT }}36 APNS_ENVIRONMENT: ${{ vars.APNS_ENVIRONMENT }}
37 APNS_TEAM_ID: ${{ vars.APNS_TEAM_ID }}37 APNS_TEAM_ID: ${{ vars.APNS_TEAM_ID }}
.github/workflows/release.yml+6−6
@@ -178,8 +178,8 @@ jobs: · 177 unmodified lines
178 clerk_publishable_key: ${{ steps.public_config.outputs.clerk_publishable_key }}178 clerk_publishable_key: ${{ steps.public_config.outputs.clerk_publishable_key }}
179 relay_url: ${{ steps.public_config.outputs.relay_url }}179 relay_url: ${{ steps.public_config.outputs.relay_url }}
180 env:180 env:
181 T3CODE_RELAY_DOMAIN: ${{ vars.T3CODE_RELAY_DOMAIN }}181 RELAY_DOMAIN: ${{ vars.RELAY_DOMAIN }}
182 T3CODE_CLERK_PUBLISHABLE_KEY: ${{ vars.T3CODE_CLERK_PUBLISHABLE_KEY }}182 CLERK_PUBLISHABLE_KEY: ${{ vars.CLERK_PUBLISHABLE_KEY }}
183 steps:183 steps:
184 - id: public_config184 - id: public_config
185 name: Resolve production relay public config185 name: Resolve production relay public config
@@ -188,8 +188,8 @@ jobs: · 2 unmodified lines
188 set -euo pipefail188 set -euo pipefail
189 189
190 required=(190 required=(
191 T3CODE_RELAY_DOMAIN191 RELAY_DOMAIN
192 T3CODE_CLERK_PUBLISHABLE_KEY192 CLERK_PUBLISHABLE_KEY
193 )193 )
194 missing=()194 missing=()
195 for name in "${required[@]}"; do195 for name in "${required[@]}"; do
@@ -202,8 +202,8 @@ jobs: · 6 unmodified lines
202 exit 1202 exit 1
203 fi203 fi
204 204
205 echo "clerk_publishable_key=$T3CODE_CLERK_PUBLISHABLE_KEY" >> "$GITHUB_OUTPUT"205 echo "clerk_publishable_key=$CLERK_PUBLISHABLE_KEY" >> "$GITHUB_OUTPUT"
206 echo "relay_url=https://$T3CODE_RELAY_DOMAIN" >> "$GITHUB_OUTPUT"206 echo "relay_url=https://$RELAY_DOMAIN" >> "$GITHUB_OUTPUT"
207 207
208 build:208 build:
209 name: Build ${{ matrix.label }}209 name: Build ${{ matrix.label }}
docs/release.md+4−4
@@ -56,10 +56,10 @@ Required repository secrets shared by relay deployments: · 55 unmodified lines
56 56
57Required `production` environment variables:57Required `production` environment variables:
58 58
59- `T3CODE_RELAY_DOMAIN`59- `RELAY_DOMAIN`
60- `T3CODE_RELAY_ZONE_NAME`60- `RELAY_ZONE_NAME`
61- `T3CODE_CLERK_PUBLISHABLE_KEY`61- `CLERK_PUBLISHABLE_KEY`
62- `T3CODE_CLERK_CLI_OAUTH_CLIENT_ID`62- `CLERK_CLI_OAUTH_CLIENT_ID`
63- `APNS_ENVIRONMENT`63- `APNS_ENVIRONMENT`
64- `APNS_TEAM_ID`64- `APNS_TEAM_ID`
65- `APNS_KEY_ID`65- `APNS_KEY_ID`
docs/t3-cloud-clerk.md+4−4
@@ -34,11 +34,11 @@ client-facing values in their EAS environment. · 33 unmodified lines
34When either public value is absent, cloud UI is omitted.34When either public value is absent, cloud UI is omitted.
35 35
36For a hosted relay deployment, copy `infra/relay/.env.example` to `infra/relay/.env`. The relay36For a hosted relay deployment, copy `infra/relay/.env.example` to `infra/relay/.env`. The relay
37deployment reads `T3CODE_RELAY_DOMAIN`, `T3CODE_RELAY_ZONE_NAME`, and37deployment reads `RELAY_DOMAIN`, `RELAY_ZONE_NAME`, and `CLERK_PUBLISHABLE_KEY` through Effect
38`T3CODE_CLERK_PUBLISHABLE_KEY` through Effect `Config`. There are no checked-in deployment defaults.38`Config`. There are no checked-in deployment defaults.
39`bun --cwd infra/relay run deploy` invokes Alchemy from the relay directory, so Alchemy loads39`bun --cwd infra/relay run deploy` invokes Alchemy from the relay directory, so Alchemy loads
40`infra/relay/.env`. After a successful deployment, the wrapper updates the repository-root `.env`40`infra/relay/.env`. After a successful deployment, the wrapper updates the repository-root `.env`
41with the HTTPS relay URL derived from `T3CODE_RELAY_DOMAIN`. The relay still requires41with the HTTPS relay URL derived from `RELAY_DOMAIN`. The relay still requires
42`CLERK_SECRET_KEY` as an Alchemy secret. Never put `CLERK_SECRET_KEY` in a client application42`CLERK_SECRET_KEY` as an Alchemy secret. Never put `CLERK_SECRET_KEY` in a client application
43environment or commit it to the repository.43environment or commit it to the repository.
44 44
@@ -56,7 +56,7 @@ In **Clerk Dashboard > JWT templates**, create a template with: · 11 unmodified lines
56| Claims | `{ "aud": "https://relay.example.com" }` |56| Claims | `{ "aud": "https://relay.example.com" }` |
57 57
58The `aud` value must be the deployed relay public URL, with no trailing slash. It must match the58The `aud` value must be the deployed relay public URL, with no trailing slash. It must match the
59client-facing `T3CODE_RELAY_URL` and the HTTPS URL derived from the deployment's `T3CODE_RELAY_DOMAIN`. If59client-facing `T3CODE_RELAY_URL` and the HTTPS URL derived from the deployment's `RELAY_DOMAIN`. If
60the relay domain changes, update both values and the JWT template.60the relay domain changes, update both values and the JWT template.
61 61
62## Desktop OAuth Redirect Allowlist62## Desktop OAuth Redirect Allowlist
infra/relay/.env.example+3−3
@@ -1,15 +1,15 @@
1# Required: Relay domain1# Required: Relay domain
2# Use the DNS zone managed in your Cloudflare account. Production deploys use2# Use the DNS zone managed in your Cloudflare account. Production deploys use
3# relay.<zone>; personal stages use relay-<stage>.<zone>.3# relay.<zone>; personal stages use relay-<stage>.<zone>.
4T3CODE_RELAY_ZONE_NAME=example.com4RELAY_ZONE_NAME=example.com
5 5
6# Optional: Relay domain override6# Optional: Relay domain override
7# Set this only when the derived relay hostname should not be used.7# Set this only when the derived relay hostname should not be used.
8# T3CODE_RELAY_DOMAIN=relay.example.com8# RELAY_DOMAIN=relay.example.com
9 9
10# Required: Clerk10# Required: Clerk
11# Get both values from the Clerk Dashboard under API keys.11# Get both values from the Clerk Dashboard under API keys.
12T3CODE_CLERK_PUBLISHABLE_KEY=pk_test_...12CLERK_PUBLISHABLE_KEY=pk_test_...
13CLERK_SECRET_KEY=sk_test_...13CLERK_SECRET_KEY=sk_test_...
14 14
15# Required: Apple Push Notification service15# Required: Apple Push Notification service
infra/relay/README.md+5−5
@@ -100,8 +100,8 @@ bun --cwd infra/relay run deploy -- --env-file .env.local · 99 unmodified lines
100 100
101Alchemy defaults personal deployments to the `dev_$USER` stage. Relay custom domains apply the same101Alchemy defaults personal deployments to the `dev_$USER` stage. Relay custom domains apply the same
102DNS-safe sanitization as Alchemy physical resource names, so `prod` uses102DNS-safe sanitization as Alchemy physical resource names, so `prod` uses
103`relay.<T3CODE_RELAY_ZONE_NAME>` and `dev_julius` uses `relay-dev-julius.<T3CODE_RELAY_ZONE_NAME>`.103`relay.<RELAY_ZONE_NAME>` and `dev_julius` uses `relay-dev-julius.<RELAY_ZONE_NAME>`.
104`T3CODE_RELAY_DOMAIN` remains available as an explicit override.104`RELAY_DOMAIN` remains available as an explicit override.
105 105
106After a successful deploy, the wrapper updates the repository-root `.env` file with the derived relay106After a successful deploy, the wrapper updates the repository-root `.env` file with the derived relay
107URL. That makes subsequent source builds point at the relay that was just deployed without copying107URL. That makes subsequent source builds point at the relay that was just deployed without copying
@@ -130,9 +130,9 @@ The repository must define these Actions secrets shared by relay deployments: · 22 unmodified lines
130 130
131The `production` GitHub environment must define these Actions variables:131The `production` GitHub environment must define these Actions variables:
132 132
133- `T3CODE_RELAY_ZONE_NAME`133- `RELAY_ZONE_NAME`
134- `T3CODE_RELAY_DOMAIN` if overriding the derived production relay domain134- `RELAY_DOMAIN` if overriding the derived production relay domain
135- `T3CODE_CLERK_PUBLISHABLE_KEY`135- `CLERK_PUBLISHABLE_KEY`
136- `APNS_ENVIRONMENT`136- `APNS_ENVIRONMENT`
137- `APNS_TEAM_ID`137- `APNS_TEAM_ID`
138- `APNS_KEY_ID`138- `APNS_KEY_ID`
infra/relay/src/worker.ts+1−1
@@ -129,7 +129,7 @@ export default class Api extends Cloudflare.Worker<Api>()( · 128 unmodified lines
129 const axiomTracesEndpoint = yield* observability.traces.otelTracesEndpoint;129 const axiomTracesEndpoint = yield* observability.traces.otelTracesEndpoint;
130 130
131 const clerkSecretKey = yield* Config.redacted("CLERK_SECRET_KEY");131 const clerkSecretKey = yield* Config.redacted("CLERK_SECRET_KEY");
132 const clerkPublishableKey = yield* Config.string("T3CODE_CLERK_PUBLISHABLE_KEY");132 const clerkPublishableKey = yield* Config.string("CLERK_PUBLISHABLE_KEY");
133 133
134 const cloudMintPrivateKey = yield* cloudMintKeyPair.privateKey;134 const cloudMintPrivateKey = yield* cloudMintKeyPair.privateKey;
135 const cloudMintPublicKey = yield* cloudMintKeyPair.publicKey;135 const cloudMintPublicKey = yield* cloudMintKeyPair.publicKey;
infra/relay/src/zone.test.ts+50−0
@@ -0,0 +1,50 @@
1import * as Alchemy from "alchemy";
2import * as ConfigProvider from "effect/ConfigProvider";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import { describe, expect, it } from "vitest";
6
7import { RelayDeploymentConfig } from "./zone.ts";
8
9function resolveRelayDeploymentConfig(env: Record<string, string>, stage = "prod") {
10 return Effect.runPromise(
11 RelayDeploymentConfig.pipe(
12 Effect.provide(
13 Layer.mergeAll(
14 Layer.succeed(Alchemy.Stage, stage),
15 ConfigProvider.layer(ConfigProvider.fromEnv({ env })),
16 ),
17 ),
18 ),
19 );
20}
21
22describe("RelayDeploymentConfig", () => {
23 it("derives the relay domain from the unprefixed zone name", async () => {
24 await expect(resolveRelayDeploymentConfig({ RELAY_ZONE_NAME: "example.com" })).resolves.toEqual(
25 {
26 stage: "prod",
27 relayPublicDomain: "relay.example.com",
28 relayPublicOrigin: "https://relay.example.com",
29 managedEndpointZoneName: "example.com",
30 },
31 );
32 });
33
34 it("uses the unprefixed relay domain override", async () => {
35 await expect(
36 resolveRelayDeploymentConfig(
37 {
38 RELAY_ZONE_NAME: "example.com",
39 RELAY_DOMAIN: "relay.custom.example",
40 },
41 "dev_julius",
42 ),
43 ).resolves.toEqual({
44 stage: "dev_julius",
45 relayPublicDomain: "relay.custom.example",
46 relayPublicOrigin: "https://relay.custom.example",
47 managedEndpointZoneName: "example.com",
48 });
49 });
50});
infra/relay/src/zone.ts+2−2
@@ -9,8 +9,8 @@ import { relayPublicDomainForStage } from "./deploymentConfig.ts"; · 8 unmodified lines
9 9
10export const RelayDeploymentConfig = Effect.gen(function* () {10export const RelayDeploymentConfig = Effect.gen(function* () {
11 const stage = yield* Alchemy.Stage;11 const stage = yield* Alchemy.Stage;
12 const managedEndpointZoneName = yield* Config.nonEmptyString("T3CODE_RELAY_ZONE_NAME");12 const managedEndpointZoneName = yield* Config.nonEmptyString("RELAY_ZONE_NAME");
13 const relayPublicDomainOverride = yield* Config.nonEmptyString("T3CODE_RELAY_DOMAIN").pipe(13 const relayPublicDomainOverride = yield* Config.nonEmptyString("RELAY_DOMAIN").pipe(
14 Config.option,14 Config.option,
15 );15 );
16 const relayPublicDomain = Option.getOrElse(relayPublicDomainOverride, () =>16 const relayPublicDomain = Option.getOrElse(relayPublicDomainOverride, () =>