From 20254307084f1101ced00dfadeddc7804a7de45d Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Sun, 11 Oct 2026 02:31:06 -0500 Subject: [PATCH] fix(mobile): license generation works with filtered installs (#18127) --- apps/server/src/device/DeviceToolchain.ts | 2 +- .../server/src/device/deviceToolVersions.json | 4 + docs/internals/open-source-licenses.md | 2 +- packages/shared/package.json | 4 - packages/shared/src/deviceToolVersions.ts | 5 -- scripts/lib/third-party-licenses.test.ts | 79 ++++++++++++++++++- scripts/lib/third-party-licenses.ts | 14 +++- 7 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 apps/server/src/device/deviceToolVersions.json delete mode 100644 packages/shared/src/deviceToolVersions.ts diff --git a/apps/server/src/device/DeviceToolchain.ts b/apps/server/src/device/DeviceToolchain.ts index 132fbcebdb1fddfc3a4ca5fcd39f9c837411afe9..bd9a771483f478995d5619a287122e79418afcbf 100644 --- a/apps/server/src/device/DeviceToolchain.ts +++ b/apps/server/src/device/DeviceToolchain.ts @@ -1,5 +1,4 @@ import type { DeviceToolVersions } from "@t3tools/contracts"; -import { DEVICE_TOOL_VERSIONS } from "@t3tools/shared/deviceToolVersions"; /** * Pinned installs of the two external tools device support is built on. * @@ -25,6 +24,7 @@ import * as Schema from "effect/Schema"; import * as Semaphore from "effect/Semaphore"; import * as ProcessRunner from "../processRunner.ts"; +import DEVICE_TOOL_VERSIONS from "./deviceToolVersions.json" with { type: "json" }; const DEVICE_HUB_PACKAGE = "expo-device-hub"; export const DEVICE_HUB_VERSION = DEVICE_TOOL_VERSIONS[DEVICE_HUB_PACKAGE]; diff --git a/apps/server/src/device/deviceToolVersions.json b/apps/server/src/device/deviceToolVersions.json new file mode 100644 index 0000000000000000000000000000000000000000..8d2e5a3efebc709f34e1e7551fea7fd5ce8d61f1 --- /dev/null +++ b/apps/server/src/device/deviceToolVersions.json @@ -0,0 +1,4 @@ +{ + "agent-device": "0.21.24", + "expo-device-hub": "0.15.3" +} diff --git a/docs/internals/open-source-licenses.md b/docs/internals/open-source-licenses.md index 904c9be4471e85a24aa6051b45d75b4fb057e1f5..ef7a6dba42966e8c18931cbb8a3f97c4cdefa07d 100644 --- a/docs/internals/open-source-licenses.md +++ b/docs/internals/open-source-licenses.md @@ -61,7 +61,7 @@ supplies the label shown to users. Use `includeInBundles` when those differ, suc server tool that should appear in both client manifests but is not bundled into either client. The `agent-device` and `expo-device-hub` custom notices take their versions from the -[shared installer pins](../../packages/shared/src/deviceToolVersions.ts). Keep their package names +[installer pins](../../apps/server/src/device/deviceToolVersions.json). Keep their package names in the config; their versions do not need manual updates. Use `packageOverrides` only when an installed npm archive omits its notice or has incorrect diff --git a/packages/shared/package.json b/packages/shared/package.json index 7b750e7a3c50cdbfa79ebba715cd782f425d9387..4ccc2b6910236d428b1bf182fba04f81e9430a40 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -359,10 +359,6 @@ "types": "./src/thirdPartyLicenses.ts", "import": "./src/thirdPartyLicenses.ts" }, - "./deviceToolVersions": { - "types": "./src/deviceToolVersions.ts", - "import": "./src/deviceToolVersions.ts" - }, "./claudeCompaction": { "types": "./src/claudeCompaction.ts", "import": "./src/claudeCompaction.ts" diff --git a/packages/shared/src/deviceToolVersions.ts b/packages/shared/src/deviceToolVersions.ts deleted file mode 100644 index 12a7071831d2f5277ae5ed2fb7c4f3e236283b94..0000000000000000000000000000000000000000 --- a/packages/shared/src/deviceToolVersions.ts +++ /dev/null @@ -1,5 +0,0 @@ -// The installer and third-party notices share these pins for tools installed outside the workspace. -export const DEVICE_TOOL_VERSIONS = { - "agent-device": "0.21.24", - "expo-device-hub": "0.15.3", -} as const; diff --git a/scripts/lib/third-party-licenses.test.ts b/scripts/lib/third-party-licenses.test.ts index 638dd60e15d42eac35397a0e8b8abed6b47b4247..ae2403877e565456e85c8e8624b3ff4708ee78d8 100644 --- a/scripts/lib/third-party-licenses.test.ts +++ b/scripts/lib/third-party-licenses.test.ts @@ -1,11 +1,11 @@ // @effect-diagnostics nodeBuiltinImport:off - Tests exercise the Node filesystem build boundary. import * as NodeFSP from "node:fs/promises"; +import * as NodeChildProcess from "node:child_process"; import * as NodeOS from "node:os"; import * as NodePath from "node:path"; import * as NodeURL from "node:url"; -import { DEVICE_TOOL_VERSIONS } from "@t3tools/shared/deviceToolVersions"; import { afterEach, describe, expect, it } from "vite-plus/test"; import { @@ -19,6 +19,12 @@ const REPOSITORY_ROOT = NodePath.resolve( NodePath.dirname(NodeURL.fileURLToPath(import.meta.url)), "../..", ); +const DEVICE_TOOL_VERSIONS = JSON.parse( + await NodeFSP.readFile( + NodePath.join(REPOSITORY_ROOT, "apps/server/src/device/deviceToolVersions.json"), + "utf8", + ), +) as { readonly "agent-device": string; readonly "expo-device-hub": string }; async function writeJson(path: string, value: unknown): Promise { await NodeFSP.mkdir(NodePath.dirname(path), { recursive: true }); @@ -78,6 +84,77 @@ afterEach(async () => { }); describe("third-party license generation", () => { + it("generates mobile notices without scripts workspace dependency links", async () => { + const fixture = await createFixture(); + const generatorPath = NodePath.join(fixture.root, "scripts/lib/third-party-licenses.ts"); + const versionsPath = NodePath.join( + fixture.root, + "apps/server/src/device/deviceToolVersions.json", + ); + await Promise.all([ + NodeFSP.mkdir(NodePath.dirname(generatorPath), { recursive: true }), + NodeFSP.mkdir(NodePath.dirname(versionsPath), { recursive: true }), + ]); + await Promise.all([ + writeJson(NodePath.join(fixture.root, "scripts/package.json"), { type: "module" }), + NodeFSP.copyFile( + NodePath.join(REPOSITORY_ROOT, "scripts/lib/third-party-licenses.ts"), + generatorPath, + ), + NodeFSP.copyFile( + NodePath.join(REPOSITORY_ROOT, "apps/server/src/device/deviceToolVersions.json"), + versionsPath, + ), + writeJson(fixture.configFile, { + customNotices: Object.keys(DEVICE_TOOL_VERSIONS).map((name) => ({ + name, + license: "MIT", + noticeFile: "asset-notice.txt", + bundles: ["device-tools"], + includeInBundles: ["mobile", "web"], + })), + }), + ]); + + const output = NodeChildProcess.execFileSync( + process.execPath, + [ + "--input-type=module", + "--eval", + ` + import { pathToFileURL } from "node:url"; + const { generateThirdPartyLicenseManifest } = await import( + pathToFileURL(process.argv[1]).href + "?version=1" + ); + const manifest = await generateThirdPartyLicenseManifest({ + configFile: process.argv[2], + packageManifests: [{ bundle: "mobile", path: process.argv[3] }], + }); + process.stdout.write(JSON.stringify(manifest)); + `, + generatorPath, + fixture.configFile, + fixture.appManifest, + ], + { cwd: fixture.root, encoding: "utf8" }, + ); + const manifest = JSON.parse(output) as { + entries: ReadonlyArray<{ name: string; version: string }>; + }; + expect(manifest.entries).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + name: "agent-device", + version: DEVICE_TOOL_VERSIONS["agent-device"], + }), + expect.objectContaining({ + name: "expo-device-hub", + version: DEVICE_TOOL_VERSIONS["expo-device-hub"], + }), + ]), + ); + }); + it.each(["web", "mobile"])( "uses installer pins for device tool notices in the %s manifest", async (bundle) => { diff --git a/scripts/lib/third-party-licenses.ts b/scripts/lib/third-party-licenses.ts index 124f16a3ce4e000bcc02ac958599671ea3e9d822..c0332e494f3adae5e80fe91cf3b395d781ea9cbb 100644 --- a/scripts/lib/third-party-licenses.ts +++ b/scripts/lib/third-party-licenses.ts @@ -5,14 +5,12 @@ import * as NodePath from "node:path"; import * as NodeURL from "node:url"; import * as NodeModule from "node:module"; -import { DEVICE_TOOL_VERSIONS } from "@t3tools/shared/deviceToolVersions"; import type { Plugin } from "vite-plus"; export const THIRD_PARTY_LICENSES_FILE_NAME = "third-party-licenses.json"; const SPDX_LICENSE_LIST_VERSION = "v3.28.0"; const SPDX_LICENSE_LIST_REVISION = "c4a7237ec8f4654e867546f9f409749300f1bf4c"; const GENERATED_NOTICE_CACHE_DIRECTORY = ".generated/third-party-licenses/spdx"; -const DEVICE_TOOL_NOTICE_VERSIONS = new Map(Object.entries(DEVICE_TOOL_VERSIONS)); export interface ThirdPartyLicenseEntry { readonly bundles: ReadonlyArray; @@ -825,6 +823,13 @@ async function customEntries( includedBundles: ReadonlySet, allowMissingGeneratedNotices: boolean, ): Promise> { + const deviceToolVersions: unknown = JSON.parse( + await NodeFSP.readFile( + new URL("../../apps/server/src/device/deviceToolVersions.json", import.meta.url), + "utf8", + ), + ); + if (!isRecord(deviceToolVersions)) throw new Error("Device tool versions must be an object."); const entries = await Promise.all( config.customNotices .filter( @@ -870,7 +875,10 @@ async function customEntries( name: notice.name, noticeText, sourceUrl: notice.sourceUrl ?? null, - version: DEVICE_TOOL_NOTICE_VERSIONS.get(notice.name) ?? notice.version ?? null, + version: + readOptionalString(deviceToolVersions, notice.name, "Device tool versions") ?? + notice.version ?? + null, }; }), ); -- 2.54.0