Skip to content

Commit fe47ac8

Browse files
Merge branch 'main' into fix/issue-33747
2 parents 48dfd10 + f31ce3e commit fe47ac8

864 files changed

Lines changed: 43548 additions & 6598 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/ci.yml‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,16 @@ jobs:
140140
- name: Start installing browser secret helper build libraries
141141
if: needs.changes.outputs.build != 'false'
142142
run: |
143-
sudo sed -i 's|http://|https://|g' /etc/apt/blacksmith-ubuntu-mirrors.txt /etc/apt/sources.list.d/ubuntu.sources
143+
# Fetch only the indexes these main and universe packages need. The full set is ~42 MB,
144+
# which a slow mirror can stretch past the wait below.
145+
sudo sed -i -e 's|http://|https://|g' -e 's/^Components: .*/Components: main universe/' \
146+
/etc/apt/blacksmith-ubuntu-mirrors.txt /etc/apt/sources.list.d/ubuntu.sources
144147
(
145148
set +e
146-
sudo apt-get update && sudo apt-get install -y libsecret-1-dev pkg-config xvfb
149+
sudo apt-get update -o Acquire::Languages=none \
150+
-o Acquire::IndexTargets::deb::DEP-11::DefaultEnabled=false \
151+
-o Acquire::IndexTargets::deb::CNF::DefaultEnabled=false &&
152+
sudo apt-get install -y libsecret-1-dev pkg-config xvfb
147153
echo "$?" > "$RUNNER_TEMP/apt-status"
148154
) > "$RUNNER_TEMP/apt.log" 2>&1 < /dev/null &
149155
@@ -287,10 +293,16 @@ jobs:
287293
# the background while Vite+ installs; the step before the tests waits for it.
288294
- name: Start installing browser secret helper build libraries
289295
run: |
290-
sudo sed -i 's|http://|https://|g' /etc/apt/blacksmith-ubuntu-mirrors.txt /etc/apt/sources.list.d/ubuntu.sources
296+
# Fetch only the indexes these main and universe packages need. The full set is ~42 MB,
297+
# which a slow mirror can stretch past the wait below.
298+
sudo sed -i -e 's|http://|https://|g' -e 's/^Components: .*/Components: main universe/' \
299+
/etc/apt/blacksmith-ubuntu-mirrors.txt /etc/apt/sources.list.d/ubuntu.sources
291300
(
292301
set +e
293-
sudo apt-get update && sudo apt-get install -y libsecret-1-dev pkg-config
302+
sudo apt-get update -o Acquire::Languages=none \
303+
-o Acquire::IndexTargets::deb::DEP-11::DefaultEnabled=false \
304+
-o Acquire::IndexTargets::deb::CNF::DefaultEnabled=false &&
305+
sudo apt-get install -y libsecret-1-dev pkg-config
294306
echo "$?" > "$RUNNER_TEMP/apt-status"
295307
) > "$RUNNER_TEMP/apt.log" 2>&1 < /dev/null &
296308

‎.github/workflows/mobile-showcase-screenshots.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ jobs:
8888
axe --version
8989
9090
- name: Install foldable simulator controls
91-
run: npm install --global [email protected].25
91+
run: npm install --global [email protected].36
9292

9393
- name: Capture iOS showcase
9494
run: pnpm screenshots:mobile --platform ios --appearance "${{ inputs.appearance }}" --theme "${{ inputs.theme }}"

‎.github/workflows/release.yml‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1482,7 +1482,18 @@ jobs:
14821482
14831483
git add apps/server/package.json apps/desktop/package.json apps/web/package.json packages/contracts/package.json pnpm-lock.yaml
14841484
git commit --no-verify -m "chore(release): prepare $RELEASE_TAG"
1485-
git push origin HEAD:main
1485+
1486+
# main moves while this job runs, so a rejected push rebases and retries.
1487+
for attempt in 1 2 3 4 5; do
1488+
if git push origin HEAD:main; then
1489+
exit 0
1490+
fi
1491+
echo "Push rejected (attempt $attempt). Rebasing onto latest main."
1492+
git pull --rebase origin main
1493+
done
1494+
1495+
echo "Could not push the version bump after 5 attempts." >&2
1496+
exit 1
14861497
14871498
announce_discord:
14881499
name: Announce release on Discord

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ apps/mobile/.android-cache/
3838
artifacts/app-store/screenshots/
3939
artifacts/mobile-e2e/
4040
artifacts/mobile-behavior/
41+
scripts/.e2e/
4142
.github/pr-assets/
4243
native/**/target/
4344
node_modules/

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ An empty database is a bad test. Seed your worktree's `.t3` with a copy of real
108108
- [Testing](docs/internals/testing.md) carries these same test rules, plus review guidance, for review bots. Change both together.
109109
- **Do not run repo-wide checks.** No `vp check`, no `vp run -r test`, no `vp run -r typecheck` unless I ask. CI owns the full suite.
110110
- Backend behavior changes ship with focused tests for that behavior.
111-
- Proof for a bug fix depends on the bug. Logic, data, state, and protocol bugs get a failing test first (the fewest that fail on `main` for that reason, in an existing case of the module's test file where one fits), then the fix. Purely visual bugs (spacing, colour, alignment, a layout shift) get before/after captures as their proof and no test: do not add UI tests for nitpicks, and do not ask for one in review when a capture already shows it. A server-only fix with no visible surface ships the test plus a short runtime transcript.
111+
- Proof for a bug fix depends on the bug. Logic, data, state, and protocol bugs get a failing test first (the fewest that fail on `main` for that reason, in an existing case of the module's test file where one fits), then the fix. Purely visual bugs (spacing, colour, alignment, a layout shift) get before/after captures as their proof and no test: do not add UI tests for nitpicks, and do not ask for one in review when a capture already shows it. A server-only fix with no visible surface ships the test plus a short runtime transcript. For a bug a user can reproduce in the web client, `vp run scenarios:prove` shows it failing on base and passing on the fix in the real app; see [Scenarios](docs/operations/scenarios.md).
112112
- The server is event-sourced, and side effects run after the command commits. In tests, drain the effect worker (`OrchestrationEffectWorkerV2.drain`) or await the specific persisted event or `Deferred` that marks the milestone. Never wait on sleeps or polling. A test that needs a timeout to pass is wrong. Concretely:
113113
- `it.effect` runs on a `TestClock`; `Effect.sleep` only advances through `TestClock.adjust`. `it.live` is wall-clock and only for subprocess or network fixtures.
114114
- No `yieldNow` or `sleep` polling loops. Await the `Deferred`, take from the `Queue`, or drain the worker.

‎apps/desktop/package.json‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@t3tools/desktop",
3-
"version": "0.1.8",
3+
"version": "0.1.9",
44
"private": true,
55
"type": "module",
66
"main": "dist-electron/boot.cjs",
@@ -27,7 +27,7 @@
2727
"electron-updater": "^6.8.9",
2828
"electron-webauthn": "catalog:",
2929
"ffi-rs": "1.3.2",
30-
"playwright-core": "1.60.0",
30+
"playwright-core": "1.64.1",
3131
"react-grab": "^0.1.32",
3232
"tldts": "catalog:"
3333
},
@@ -37,6 +37,7 @@
3737
"acorn": "8.16.0",
3838
"cross-env": "^10.1.0",
3939
"electron-builder": "26.16.1",
40+
"jsdom": "^30.0.1",
4041
"tailwindcss": "^4.0.0",
4142
"vite-plus": "catalog:"
4243
},

‎apps/desktop/src/app/ClerkTokenStore.test.ts‎

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ import * as NodeFS from "node:fs";
33
import * as NodeOS from "node:os";
44
import * as NodePath from "node:path";
55
import { assert, describe, it } from "@effect/vitest";
6-
import { vi } from "vite-plus/test";
7-
8-
vi.mock("node:fs", { spy: true });
96

107
import { openClerkTokenStorage, type ClerkTokenStorage } from "./ClerkTokenStore.ts";
118

@@ -91,24 +88,6 @@ describePosix("ClerkTokenStore", () => {
9188
});
9289
});
9390

94-
it("removes the legacy token file when the private copy already exists", async () => {
95-
await withStateDir((stateDir) => {
96-
const directory = NodePath.join(stateDir, "clerk");
97-
const legacyPath = NodePath.join(stateDir, "clerk-tokens.json");
98-
const tokenPath = NodePath.join(directory, "clerk-tokens.json");
99-
NodeFS.mkdirSync(directory, { mode: 0o755 });
100-
writeLoose(legacyPath, "stale-credential");
101-
writeLoose(tokenPath, "kept-credential");
102-
103-
openClerkTokenStorage(stateDir, () => idleStorage());
104-
105-
assert.equal(NodeFS.existsSync(legacyPath), false);
106-
assert.equal(modeOf(directory), 0o700);
107-
assert.equal(modeOf(tokenPath), 0o600);
108-
assert.equal(NodeFS.readFileSync(tokenPath, "utf8"), "kept-credential");
109-
});
110-
});
111-
11291
it("resolves a relative state directory before opening storage", async () => {
11392
await withStateDir(async (stateDir) => {
11493
const relativeStateDir = NodePath.relative(process.cwd(), stateDir);
@@ -150,23 +129,6 @@ describePosix("ClerkTokenStore", () => {
150129
});
151130
});
152131

153-
it("migrates tokens when the legacy directory is on another filesystem", async () => {
154-
await withStateDir((stateDir) => {
155-
const legacyPath = NodePath.join(stateDir, "clerk-tokens.json");
156-
writeLoose(legacyPath, "existing-session");
157-
using _rename = vi.spyOn(NodeFS, "renameSync").mockImplementation(() => {
158-
throw Object.assign(new Error("cross-device link"), { code: "EXDEV" });
159-
});
160-
161-
openClerkTokenStorage(stateDir, idleStorage);
162-
163-
const tokenPath = NodePath.join(stateDir, "clerk", "clerk-tokens.json");
164-
assert.equal(NodeFS.readFileSync(tokenPath, "utf8"), "existing-session");
165-
assert.equal(modeOf(tokenPath), 0o600);
166-
assert.equal(NodeFS.existsSync(legacyPath), false);
167-
});
168-
});
169-
170132
it("does not follow a symlinked clerk directory or token file", async () => {
171133
await withStateDir(async (stateDir) => {
172134
const outsideDirectory = NodePath.join(stateDir, "outside-dir");

‎apps/desktop/src/app/DesktopApp.test.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as Layer from "effect/Layer";
77
import * as FileSystem from "effect/FileSystem";
88
import * as Path from "effect/Path";
99
import * as HttpClient from "effect/http/HttpClient";
10+
import { ChildProcessSpawner } from "effect/process";
1011
import * as NetService from "@t3tools/shared/Net";
1112
import * as Fiber from "effect/Fiber";
1213
import * as Option from "effect/Option";
@@ -213,6 +214,7 @@ it.effect.each([false, true])(
213214
Effect.provide(
214215
Layer.mergeAll(
215216
Layer.mock(BrowserImport.BrowserImport, {}),
217+
Layer.mock(ChildProcessSpawner.ChildProcessSpawner, {}),
216218
Layer.mock(DesktopBackendConfiguration.DesktopBackendConfiguration, {}),
217219
Layer.mock(DesktopCliCommand.DesktopCliCommand, {}),
218220
Layer.mock(DesktopClientSettings.DesktopClientSettings, {}),

‎apps/desktop/src/app/DesktopClerk.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ export const make = Effect.gen(function* () {
116116
yield* electronApp.quit;
117117
return yield* Effect.interrupt;
118118
}
119+
// Chromium opens these caches at the first event-loop turn, before ready.
120+
yield* DesktopUserData.clearStaleGpuCaches({
121+
userDataPath,
122+
electronVersion: process.versions.electron,
123+
});
119124

120125
const pendingSecondInstances: Array<readonly string[]> = [];
121126
let handleSecondInstance = (argv: readonly string[]) => {

‎apps/desktop/src/app/DesktopPreReadyFileSystem.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ export const make = FileSystem.makeNoop({
4949
syncFs("makeDirectory", path, () => {
5050
NodeFS.mkdirSync(path, { recursive: options?.recursive ?? false });
5151
}),
52+
remove: (path, options) =>
53+
syncFs("remove", path, () =>
54+
NodeFS.rmSync(path, {
55+
recursive: options?.recursive ?? false,
56+
force: options?.force ?? false,
57+
}),
58+
),
5259
writeFileString: (path, data, options) =>
5360
syncFs("writeFileString", path, () =>
5461
NodeFS.writeFileSync(path, data, { flag: options?.flag ?? "w" }),

0 commit comments

Comments
 (0)