authorgravatar for saiansh2525@gmail.comYash Singh <saiansh2525@gmail.com> 2026-10-11 02:02:11-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-11 02:02:11-05:00
logbb9b9aae57ce5614c9c26d540ca51c805cdbf09b
tree3da434ed3aca95184a558986afa8351849ec0fbf
parentcf821991863d5e374f698cb45bcef4759d3a0b7f
signature Signed by PGP key B5690EEEBB952194

fix(server): sync device tool license versions with installer pins (#18121)


7 files changed, 70 insertions(+), 13 deletions(-)

apps/server/src/device/DeviceToolchain.ts+3-2
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1import type { DeviceToolVersions } from "@t3tools/contracts";1import type { DeviceToolVersions } from "@t3tools/contracts";
2import { DEVICE_TOOL_VERSIONS } from "@t3tools/shared/deviceToolVersions";
2/**3/**
3 * Pinned installs of the two external tools device support is built on.4 * Pinned installs of the two external tools device support is built on.
4 *5 *
...@@ -26,9 +27,9 @@ import * as Semaphore from "effect/Semaphore";...@@ -26,9 +27,9 @@ import * as Semaphore from "effect/Semaphore";
26import * as ProcessRunner from "../processRunner.ts";27import * as ProcessRunner from "../processRunner.ts";
2728
28const DEVICE_HUB_PACKAGE = "expo-device-hub";29const DEVICE_HUB_PACKAGE = "expo-device-hub";
29export const DEVICE_HUB_VERSION = "0.15.3";30export const DEVICE_HUB_VERSION = DEVICE_TOOL_VERSIONS[DEVICE_HUB_PACKAGE];
30const AGENT_DEVICE_PACKAGE = "agent-device";31const AGENT_DEVICE_PACKAGE = "agent-device";
31export const AGENT_DEVICE_VERSION = "0.21.24";32export const AGENT_DEVICE_VERSION = DEVICE_TOOL_VERSIONS[AGENT_DEVICE_PACKAGE];
3233
33const INSTALL_TIMEOUT = Duration.minutes(10);34const INSTALL_TIMEOUT = Duration.minutes(10);
34const installLock = Semaphore.makeUnsafe(1);35const installLock = Semaphore.makeUnsafe(1);
docs/internals/open-source-licenses.md+4
...@@ -60,6 +60,10 @@ relative to the config file. `bundles` controls which generated manifests includ...@@ -60,6 +60,10 @@ relative to the config file. `bundles` controls which generated manifests includ
60supplies the label shown to users. Use `includeInBundles` when those differ, such as an optional60supplies the label shown to users. Use `includeInBundles` when those differ, such as an optional
61server tool that should appear in both client manifests but is not bundled into either client.61server tool that should appear in both client manifests but is not bundled into either client.
6262
63The `agent-device` and `expo-device-hub` custom notices take their versions from the
64[shared installer pins](../../packages/shared/src/deviceToolVersions.ts). Keep their package names
65in the config; their versions do not need manual updates.
66
63Use `packageOverrides` only when an installed npm archive omits its notice or has incorrect67Use `packageOverrides` only when an installed npm archive omits its notice or has incorrect
64metadata:68metadata:
6569
packages/shared/package.json+4
...@@ -359,6 +359,10 @@...@@ -359,6 +359,10 @@
359 "types": "./src/thirdPartyLicenses.ts",359 "types": "./src/thirdPartyLicenses.ts",
360 "import": "./src/thirdPartyLicenses.ts"360 "import": "./src/thirdPartyLicenses.ts"
361 },361 },
362 "./deviceToolVersions": {
363 "types": "./src/deviceToolVersions.ts",
364 "import": "./src/deviceToolVersions.ts"
365 },
362 "./claudeCompaction": {366 "./claudeCompaction": {
363 "types": "./src/claudeCompaction.ts",367 "types": "./src/claudeCompaction.ts",
364 "import": "./src/claudeCompaction.ts"368 "import": "./src/claudeCompaction.ts"
packages/shared/src/deviceToolVersions.ts created+5
...@@ -0,0 +1,5 @@
1// The installer and third-party notices share these pins for tools installed outside the workspace.
2export const DEVICE_TOOL_VERSIONS = {
3 "agent-device": "0.21.24",
4 "expo-device-hub": "0.15.3",
5} as const;
scripts/lib/third-party-licenses.test.ts+51
...@@ -5,6 +5,7 @@ import * as NodeOS from "node:os";...@@ -5,6 +5,7 @@ import * as NodeOS from "node:os";
5import * as NodePath from "node:path";5import * as NodePath from "node:path";
6import * as NodeURL from "node:url";6import * as NodeURL from "node:url";
77
8import { DEVICE_TOOL_VERSIONS } from "@t3tools/shared/deviceToolVersions";
8import { afterEach, describe, expect, it } from "vite-plus/test";9import { afterEach, describe, expect, it } from "vite-plus/test";
910
10import {11import {
...@@ -77,6 +78,56 @@ afterEach(async () => {...@@ -77,6 +78,56 @@ afterEach(async () => {
77});78});
7879
79describe("third-party license generation", () => {80describe("third-party license generation", () => {
81 it.each(["web", "mobile"])(
82 "uses installer pins for device tool notices in the %s manifest",
83 async (bundle) => {
84 const fixture = await createFixture();
85 await writeJson(fixture.configFile, {
86 customNotices: [
87 {
88 name: "agent-device",
89 license: "MIT",
90 noticeFile: "asset-notice.txt",
91 bundles: ["device-tools"],
92 includeInBundles: ["web", "mobile"],
93 },
94 {
95 name: "expo-device-hub",
96 license: "MIT",
97 noticeFile: "asset-notice.txt",
98 version: "0.0.0",
99 bundles: ["device-tools"],
100 includeInBundles: ["web", "mobile"],
101 },
102 {
103 name: "vendored-asset",
104 license: "MIT",
105 noticeFile: "asset-notice.txt",
106 version: "1.2.3",
107 bundles: ["web", "mobile"],
108 },
109 ],
110 });
111
112 const manifest = await generateThirdPartyLicenseManifest({
113 configFile: fixture.configFile,
114 packageManifests: [{ bundle, path: fixture.appManifest }],
115 });
116
117 expect(manifest.entries.find((entry) => entry.name === "agent-device")).toMatchObject({
118 version: DEVICE_TOOL_VERSIONS["agent-device"],
119 bundles: ["device-tools"],
120 });
121 expect(manifest.entries.find((entry) => entry.name === "expo-device-hub")).toMatchObject({
122 version: DEVICE_TOOL_VERSIONS["expo-device-hub"],
123 bundles: ["device-tools"],
124 });
125 expect(manifest.entries.find((entry) => entry.name === "vendored-asset")?.version).toBe(
126 "1.2.3",
127 );
128 },
129 );
130
80 it("keeps the GhosttyKit notice pinned to the vendored framework revision", async () => {131 it("keeps the GhosttyKit notice pinned to the vendored framework revision", async () => {
81 const [config, revision] = await Promise.all([132 const [config, revision] = await Promise.all([
82 NodeFSP.readFile(NodePath.join(REPOSITORY_ROOT, "third-party-licenses.config.json"), "utf8"),133 NodeFSP.readFile(NodePath.join(REPOSITORY_ROOT, "third-party-licenses.config.json"), "utf8"),
scripts/lib/third-party-licenses.ts+3-1
...@@ -5,12 +5,14 @@ import * as NodePath from "node:path";...@@ -5,12 +5,14 @@ import * as NodePath from "node:path";
5import * as NodeURL from "node:url";5import * as NodeURL from "node:url";
6import * as NodeModule from "node:module";6import * as NodeModule from "node:module";
77
8import { DEVICE_TOOL_VERSIONS } from "@t3tools/shared/deviceToolVersions";
8import type { Plugin } from "vite-plus";9import type { Plugin } from "vite-plus";
910
10export const THIRD_PARTY_LICENSES_FILE_NAME = "third-party-licenses.json";11export const THIRD_PARTY_LICENSES_FILE_NAME = "third-party-licenses.json";
11const SPDX_LICENSE_LIST_VERSION = "v3.28.0";12const SPDX_LICENSE_LIST_VERSION = "v3.28.0";
12const SPDX_LICENSE_LIST_REVISION = "c4a7237ec8f4654e867546f9f409749300f1bf4c";13const SPDX_LICENSE_LIST_REVISION = "c4a7237ec8f4654e867546f9f409749300f1bf4c";
13const GENERATED_NOTICE_CACHE_DIRECTORY = ".generated/third-party-licenses/spdx";14const GENERATED_NOTICE_CACHE_DIRECTORY = ".generated/third-party-licenses/spdx";
15const DEVICE_TOOL_NOTICE_VERSIONS = new Map(Object.entries(DEVICE_TOOL_VERSIONS));
1416
15export interface ThirdPartyLicenseEntry {17export interface ThirdPartyLicenseEntry {
16 readonly bundles: ReadonlyArray<string>;18 readonly bundles: ReadonlyArray<string>;
...@@ -868,7 +870,7 @@ async function customEntries(...@@ -868,7 +870,7 @@ async function customEntries(
868 name: notice.name,870 name: notice.name,
869 noticeText,871 noticeText,
870 sourceUrl: notice.sourceUrl ?? null,872 sourceUrl: notice.sourceUrl ?? null,
871 version: notice.version ?? null,873 version: DEVICE_TOOL_NOTICE_VERSIONS.get(notice.name) ?? notice.version ?? null,
872 };874 };
873 }),875 }),
874 );876 );
third-party-licenses.config.json-10
...@@ -62,7 +62,6 @@...@@ -62,7 +62,6 @@
62 "license": "MIT",62 "license": "MIT",
63 "name": "agent-device",63 "name": "agent-device",
64 "sourceUrl": "https://github.com/callstack/agent-device",64 "sourceUrl": "https://github.com/callstack/agent-device",
65 "version": "0.21.7",
66 "generatedNotices": [65 "generatedNotices": [
67 {66 {
68 "licenseId": "MIT",67 "licenseId": "MIT",
...@@ -76,7 +75,6 @@...@@ -76,7 +75,6 @@
76 "license": "MIT AND Apache-2.0 AND BSD-3-Clause",75 "license": "MIT AND Apache-2.0 AND BSD-3-Clause",
77 "name": "expo-device-hub",76 "name": "expo-device-hub",
78 "sourceUrl": "https://github.com/expo/expo-device-hub",77 "sourceUrl": "https://github.com/expo/expo-device-hub",
79 "version": "0.10.1",
80 "generatedNotices": [78 "generatedNotices": [
81 {79 {
82 "licenseId": "MIT",80 "licenseId": "MIT",
...@@ -174,14 +172,6 @@...@@ -174,14 +172,6 @@
174 "copyrights": ["Copyright 2021-2024 The Connect Authors"]172 "copyrights": ["Copyright 2021-2024 The Connect Authors"]
175 }173 }
176 },174 },
177 {
178 "name": "@connectrpc/connect-node",
179 "version": "1.7.0",
180 "generatedNotice": {
181 "licenseId": "Apache-2.0",
182 "copyrights": ["Copyright 2021-2024 The Connect Authors"]
183 }
184 },
185 {175 {
186 "name": "@connectrpc/connect-web",176 "name": "@connectrpc/connect-web",
187 "version": "1.7.0",177 "version": "1.7.0",