-
Notifications
You must be signed in to change notification settings - Fork 0
feat(fork): build with official T3 Connect public config #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0ee39d2
04c72b5
19d7c57
db0466d
d8d2c8c
7eedbbb
8d9e55a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # fork-owned — see .fork/customizations.yaml#t3-connect-official-config | ||
| # | ||
| # Official T3 Connect public configuration, identical to what upstream bakes | ||
| # into every released artifact (read from the published npm CLI, t3@0.0.30). | ||
| # These are public identifiers, not secrets — see docs/cloud/t3-connect-clerk.md. | ||
| # Tracked on purpose (force-added past .gitignore's .env* rule) so every clone | ||
| # and worktree of this fork builds at T3 Connect parity with official releases. | ||
| # | ||
| # Personal overrides belong in .env.local, which stays gitignored and wins — | ||
| # by REPLACING a value, not blanking it: the loader treats empty as unset and | ||
| # falls through to this file. To build with T3 Connect off, temporarily delete | ||
| # this file in your checkout (do not commit the deletion). | ||
| # Never add server-side secrets (CLERK_SECRET_KEY, API tokens) to this file. | ||
| T3CODE_CLERK_PUBLISHABLE_KEY=pk_live_Y2xlcmsudDMuY29kZXMk | ||
| T3CODE_CLERK_JWT_TEMPLATE=t3-relay | ||
| T3CODE_CLERK_CLI_OAUTH_CLIENT_ID=hzxSgY2cH10sDU2r | ||
| T3CODE_RELAY_URL=https://relay.t3.codes | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -929,22 +929,36 @@ | |
| the app is ready. Fast machines win that race; CI runners lose it | ||
| deterministically, and a cold local boot is the same dice roll (the | ||
| v0.1.2 launch isolation gate caught it: the app exited before its server | ||
| ever started). Fork builds bake no Clerk publishable key, so the bridge | ||
| is guaranteed dead weight — DesktopClerk skips it outright when | ||
| desktopClerkFrontendApiHostname is undefined, logging a warning, and | ||
| main.ts registers both schemes' privileges synchronously at module load | ||
| (guaranteed to precede "ready"; the sole registrar on the skip path; | ||
| observed against the bundled Electron 41 that pre-ready re-registration | ||
| by a keyed build's bridge replaces the list harmlessly). Keyed builds | ||
| keep upstream's behavior exactly: bridge created, initialization and | ||
| cleanup failures both loud — the cleanup path's Effect.orDie is | ||
| deliberately untouched, because a real Clerk defect in a keyed build | ||
| must not hide behind a warning. The singleton-lock behavior in | ||
| DesktopClerk.configure is bridge-independent and preserved on both | ||
| paths. | ||
| ever started). A build with no baked Clerk publishable key has a bridge | ||
| that is guaranteed dead weight — historically every fork build; since | ||
| t3-connect-official-config, only a checkout without the tracked .env or | ||
| one that blanks the key via .env.local. DesktopClerk skips it outright | ||
| when desktopClerkFrontendApiHostname is undefined, logging a warning, | ||
| and main.ts registers both schemes' privileges synchronously at module | ||
| load (guaranteed to precede "ready") and is the sole registrar on every | ||
| path: createDesktopClerkBridge no-ops the registrar for the duration of | ||
| the createClerkBridge call and restores it after, because the bridge | ||
| would re-register the identical privilege set and that call throws | ||
| post-"ready". The suppression is load-bearing, not hygiene — packaged | ||
| fork builds are keyed since t3-connect-official-config, and the v0.1.7 | ||
| dry run's launch isolation gate caught the keyed build losing the ready | ||
| race and dying on the bridge's own registration (an earlier observation | ||
| that pre-ready re-registration is harmless was true but answered the | ||
| wrong case). Keyed builds otherwise keep upstream's behavior: bridge | ||
| created, initialization and cleanup failures both loud — the cleanup | ||
| path's Effect.orDie is deliberately untouched, because a real Clerk | ||
| defect in a keyed build must not hide behind a warning. Keyed bridge | ||
| behavior stays unit-covered by upstream's DesktopClerk.test.ts, whose | ||
| fenced hunk bakes a key in before import; the registrar suppression by | ||
| DesktopClerkForkRegistrarSuppression.test.ts; the keyless skip by | ||
| DesktopClerkForkSkip.test.ts; and the packaged boot itself by | ||
| fork-release.yml's launch isolation gate on every build, dry runs | ||
| included. The singleton-lock behavior in DesktopClerk.configure is | ||
| bridge-independent and preserved on both paths. | ||
| tier: 4 | ||
| files: | ||
| - apps/desktop/src/app/DesktopClerkForkSkip.test.ts | ||
| - apps/desktop/src/app/DesktopClerkForkRegistrarSuppression.test.ts | ||
| shadows: [] | ||
| watch: | ||
| - apps/desktop/src/main.ts | ||
|
|
@@ -1216,3 +1230,61 @@ | |
| - apps/web/src/components/ComposerPromptEditor.tsx | ||
| verify: | ||
| - apps/web/src/__fork_guards__/forkComposerShell.test.ts | ||
|
|
||
| - id: t3-connect-official-config | ||
| intent: > | ||
| Fork builds carry the same T3 Connect public configuration as official | ||
| releases, so the cloud UI, the `t3 connect` CLI group, and the managed | ||
| tunnel all work against upstream's hosted relay out of the box. Upstream | ||
| injects four public values at release time from CI variables this fork | ||
| does not have (release.yml's relay_public_config job); the fork instead | ||
| tracks them in a repository-root .env, which scripts/lib/public-config.ts | ||
| already reads for every dev run and build — with the right precedence | ||
| built in, since process env and .env.local both outrank it, so a personal | ||
| or self-hosted-relay override stays possible and stays gitignored. An | ||
| override REPLACES a value; it cannot blank one — the loader resolves | ||
| through firstNonEmpty, which treats empty as unset and falls through to | ||
| the tracked file. Building with T3 Connect off means temporarily | ||
| deleting the tracked .env in that checkout, never committing it. The | ||
| file is force-added past .gitignore's .env* rule on purpose: tracked | ||
| files are exempt from ignore rules, and upstream never ships a .env, so | ||
| a sync can never conflict with it. The values are public identifiers, | ||
| not secrets (docs/cloud/t3-connect-clerk.md) — the same ones baked into | ||
| every official artifact; they were read from the published npm CLI | ||
| (t3@0.0.30). The .env must never grow server-side secrets or tokens; the | ||
| guard pins its key set to exactly these four so secret creep fails CI. | ||
| Two neighbouring customizations make keyed fork builds safe rather than | ||
| accidental: fork-clerk-launch-resilience's keyless skip only engages | ||
| when no publishable key is baked and keyed builds keep upstream's Clerk | ||
| bridge behavior exactly, and fork-app-identity deliberately keeps the | ||
| shared t3code:// scheme, which is the desktop OAuth callback Clerk's | ||
| redirect allowlist expects. Relay access itself remains gated by the | ||
| user's own Clerk account, which is what authorizes use of the hosted | ||
| service. | ||
| tier: 1 | ||
| files: | ||
| - .env | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. important: |
||
| shadows: [] | ||
| watch: | ||
| # Upstream's loader: the one place the repo-root .env is read and | ||
| # projected into VITE_*/EXPO_PUBLIC_* aliases. If upstream renames the | ||
| # canonical variables or stops reading .env, this customization dies | ||
| # silently — the guard exercises the loader against the real repo root | ||
| # so that failure turns CI red instead. | ||
| - scripts/lib/public-config.ts | ||
| # Carries a fenced note telling developers NOT to `cp .env.example .env` | ||
| # in this fork — that documented upstream onboarding move would clobber | ||
| # the tracked file. An upstream rewrite of the example must re-seat it. | ||
| - .env.example | ||
| # Two fenced stubs blank the baked CLI OAuth client id: upstream models | ||
| # "unconfigured clone" by not stubbing the variable, which stopped being | ||
| # the ambient default once the tracked .env keyed every build. | ||
| - apps/web/src/cloud/connectCliAuth.test.ts | ||
| # reconcileRootEnv writes relay public config — OTLP tracing tokens | ||
| # included — into the repo-root .env, which this customization made | ||
| # committable. Unfenced (the fork never runs relay deploys), but any | ||
| # upstream rework of where that write lands must be re-checked against | ||
| # the tracked file. See the decisions note. | ||
| - infra/relay/scripts/deploy.ts | ||
| verify: | ||
| - apps/web/src/__fork_guards__/t3ConnectOfficialConfig.test.ts | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -185,3 +185,104 @@ Related deep-dives that predate this file and stay where they are: | |
| editor stays unclamped with `overflow-y: hidden` so Geist ink cannot inflate a scroll | ||
| container. The guard's `not.toContain("data-composer-prompt-scrollable")` is a regression fence | ||
| against bringing the toggle back, not an unexplained ban. | ||
|
|
||
| ## t3-connect-official-config | ||
|
|
||
| - The goal was stated as "parity with official releases on top of the fork's changes", which ruled | ||
| out the two heavier options up front: self-hosting the relay (`infra/relay` — own Clerk app, | ||
| Cloudflare, PlanetScale; a second production system to operate for zero parity gain) and asking | ||
| every clone to hand-author an untracked `.env` (works once, silently absent in the next worktree | ||
| or clone, and this fork's contributions largely come from fresh agent worktrees). | ||
| - The four values were extracted from the published npm CLI tarball (`t3@0.0.30`), where upstream's | ||
| release build inlines them (`VITE_CLERK_CLI_OAUTH_CLIENT_ID` etc. in the bundled web assets). | ||
| `app.t3.codes` would have shown the same values but is unreachable from the agent environment's | ||
| network policy. If upstream ever rotates them, the fix is re-extracting from the current release | ||
| and updating `.env` and the guard's `OFFICIAL_VALUES` together. | ||
| - Committing a file that `.gitignore` matches is deliberate, not an oversight: ignore rules bind | ||
| only untracked files, so one `git add -f` makes it a normal tracked file forever, upstream can | ||
| never conflict with a path it has never shipped, and `.env.local` (still ignored, higher | ||
| precedence in `scripts/lib/public-config.ts`) remains the escape hatch for anyone pointing a | ||
| checkout at a staging or self-hosted relay. The alternative — carrying the values as code-level | ||
| fallbacks — would have meant a Tier-4 fence in an upstream loader that syncs would fight over. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This decision frames force-adding |
||
| - No client code changes were needed, by construction: `fork-clerk-launch-resilience` only skips | ||
| the desktop Clerk bridge when the build is keyless, and `fork-app-identity` explicitly kept the | ||
| shared `t3code://` scheme, which is the redirect Clerk's desktop OAuth allowlist expects. The | ||
| packaged fork app signing in shares upstream's scheme contention caveat already recorded there. | ||
| - What this does not grant: relay access is authorized by the signed-in user's Clerk account | ||
| (waitlist/allowlist on upstream's instance), not by the baked values. A fork build with these | ||
| values but no approved account gets exactly what an official build gets — the sign-in flow. | ||
| - Review follow-ups (PR #35). Accepted residual risk, named rather than implied: tracking `.env` | ||
| removes the structural impossibility of committing it, and `.env` is the file most likely to | ||
| receive a `CLERK_SECRET_KEY` by habit. The guard's exact-key-set assertion is the in-repo fence, | ||
| but it is CI-only and post-push; GitHub push protection / secret scanning on the fork is the | ||
| control actually positioned to catch it pre-push, and should be confirmed enabled in repository | ||
| settings (not verifiable from a checkout). Second recorded gap: the guard's value assertion | ||
| compares the tracked `.env` against a constant maintained in the same commits, so it catches | ||
| copy-drift and secret creep, not upstream rotating the values — if rotation happens, both copies | ||
| agree, CI stays green, and the failure surfaces as a dead relay handshake at runtime. A live | ||
| probe was considered and declined; guards do not do network. | ||
| - Identity consequences of parity, stated out loud: dev runs (`vp run dev`, throwaway `test-t3-app` | ||
| worktrees) are now keyed against upstream's production Clerk instance and relay by default, where | ||
| T3 Connect was previously compiled out; and with `T3CODE_HOSTED_APP_URL` unset the `t3 connect` | ||
| CLI flow round-trips through upstream's hosted app, so the consent screen names upstream's | ||
| application. Both are exactly what "parity with official releases" means, and both are | ||
| overridable per-checkout via `.env.local` — with a real limit the second review caught: | ||
| `.env.local` can replace a value, never blank one. `firstNonEmpty` in the loader treats an empty | ||
| string as absent and falls through to the tracked `.env`, and the resolved projection is spread | ||
| last, so `T3CODE_CLERK_PUBLISHABLE_KEY=` in `.env.local` (or the process env) leaves the build | ||
| keyed. Turning T3 Connect off in a checkout means temporarily deleting the tracked `.env` — the | ||
| guard suite will complain locally until it is restored, which is the visible reminder not to | ||
| commit the deletion. A fenced loader opt-out was considered and declined: it would put a fork | ||
| hunk in upstream's build bootstrap to serve a local-experiment case that deletion already covers. | ||
| - Keyed desktop launch path: baking a key moves packaged fork builds off | ||
| fork-clerk-launch-resilience's skip path and onto upstream's bridge path — deliberately, since | ||
| that is the path every official desktop release ships. This entry originally argued a keyed | ||
| fork build was "no worse-positioned in the ready race than an official build" because main.ts's | ||
| pre-ready registration was strictly earlier than the bridge's own. True, and useless: the | ||
| bridge's own post-ready call still throws regardless of what was registered first, official | ||
| builds ship that dice roll to end users, and upstream runs no launch gate in CI to see it. The | ||
| fork's first keyed dry-run gate saw it immediately and failed the build; the incident and fix | ||
| live under `## fork-clerk-launch-resilience` below. Unit coverage of the keyed bridge already | ||
| existed in upstream's DesktopClerk.test.ts, whose fenced hunk bakes a key in before import; the | ||
| launch race itself is only observable in a packaged boot, which fork-release.yml's launch | ||
| isolation gate exercises — run it with dry_run=true to prove a keyed build before tagging a | ||
| release. | ||
| - Second review's sharpest catch: `infra/relay/scripts/deploy.ts`'s `reconcileRootEnv` writes | ||
| relay public config — including `T3CODE_MOBILE_OTLP_TRACES_TOKEN` and | ||
| `T3CODE_RELAY_CLIENT_OTLP_TRACES_TOKEN`, the latter `::add-mask::`-ed in upstream's own release | ||
| workflow — into the repo-root `.env`, which this customization made committable. In-repo | ||
| automation of the exact failure the key-set guard fences. Accepted un-fenced because this fork | ||
| never runs relay deploys (self-hosting was rejected above) and a fenced redirect to `.env.local` | ||
| would also have to carry fenced edits to upstream's `deploy.test.ts`, which asserts the `.env` | ||
| target. If the fork ever self-hosts, redirecting that write is the first change to make. The | ||
| guard's failure message now names both legitimate writers (deploy output, optional OTLP values) | ||
| and points them at `.env.local`, so tripping it reads as "wrong file", not "you leaked a secret". | ||
| - The `.env.example` fork note is now asserted by the guard suite (`toContain` on the fence | ||
| marker), closing the fourth finding: `watch:` reports drift after a sync merges, but only a | ||
| failing test stops `cp .env.example .env` from shipping upstream's placeholders over the live | ||
| values via a routine `git commit -a`. | ||
|
|
||
| ## fork-clerk-launch-resilience | ||
|
|
||
| - The keyed-build story failed the moment it was actually tested. After t3-connect-official-config | ||
| keyed every fork build, the manifest was rewritten to say keyed builds keep upstream's bridge | ||
| behavior exactly, leaning on "pre-ready re-registration observed harmless on Electron 41". The | ||
| first dry-run launch gate on a keyed build (PR #35, run 30508846869) exited before the server | ||
| started: the macOS runner's layer construction trailed "ready", `createClerkBridge` called | ||
| `registerSchemesAsPrivileged` post-ready, and `DesktopClerkBridgeInitializationError` was | ||
| fatally loud — the v0.1.2 failure reproduced on the keyed path. "Observed harmless" had only | ||
| ever described boots that won the race; CI was the population of boots that lose it. | ||
| - The fix (7eedbbb6) makes main.ts the sole registrar on every path: `createDesktopClerkBridge` | ||
| no-ops `protocol.registerSchemesAsPrivileged` for exactly the duration of `createClerkBridge` | ||
| and restores it in a `finally`. Chosen over gating on `app.isReady()` — an isReady gate keeps | ||
| fast and slow boots on different code paths, and the losing path is the one CI never exercises — | ||
| and over catching the initialization error, which would swallow unknown causes along with the | ||
| one known one. Safe only because main.ts registers the identical privilege set the bridge would | ||
| have; the launch-resilience guard pins that set item by item, and a future @clerk/electron that | ||
| registers a different set surfaces as a failing renderer in the launch gate, not silently. | ||
| Covered by DesktopClerkForkRegistrarSuppression.test.ts (registration lands on the no-op, the | ||
| registrar is restored after). | ||
| - Two sessions independently authored this same fix within the hour, differing only in fence | ||
| placement and test naming — the shipped one is 7eedbbb6; the duplicate was dropped unpushed. | ||
| Recorded because the convergence is itself evidence the no-op-around-bridge-creation shape is | ||
| the minimal fix, not one agent's taste. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blocker: tracking repo-root
.envfights upstream’s contract for this path..gitignoreignores it on purpose, docs treat it as optional local config, andinfra/relay/scripts/deploy.ts(reconcileRootEnvPublicConfig) mutates it — rewritingT3CODE_RELAY_URLand appendingT3CODE_MOBILE_OTLP_*/T3CODE_RELAY_CLIENT_OTLP_*keys (including ingest tokens). A force-tracked “exactly four keys” pin means a normal relay deploy dirties git, fails the guard, and risks committing stage URLs/tokens.code judo: put these four values in a fork-owned file (e.g.
.fork/t3-connect.public.env) and add a small fenced lowest-precedence read inscripts/lib/public-config.ts. Keep.env/.env.localas the override/scratchpad layer deploy already owns. Avoiding a Tier-4 loader hunk is not worth co-opting the mutable scratchpad.