1# Open source license notices
2
3License notices are generated independently for the client that ships them:
4
5- The web build emits `third-party-licenses.json` beside `index.html`. The Settings page loads that
6 static file, so the same artifact works in hosted web, the client bundled with `npx t3`, and
7 desktop.
8- The mobile Metro config generates an ignored virtual module before each development, native, or
9 over-the-air JavaScript bundle. Mobile loads and decodes that module only when a license screen
10 opens, so the notice text does not occupy memory during ordinary app startup. It does not need a
11 network request.
12
13Neither path depends on the connected environment or an RPC.
14
15## What the build collects
16
17The generator follows installed production and optional dependencies, including dependencies of
18workspace packages, and omits first-party `@t3tools/*` packages. The web manifest starts from the
19web, server, and desktop package manifests. The mobile manifest starts from the mobile package
20manifest. During the web bundle, the generator also checks emitted module ids to catch a bundled
21npm import missing from a package manifest.
22
23The mobile manifest deliberately follows the complete production dependency closure declared by
24Expo and React Native. That is conservative and can include build tooling that is not present in
25the final JavaScript bundle, but it avoids dropping a notice when platform bundling changes.
26
27The build fails when a collected package has no distributable license identifier or contains no
28license or notice text. Generated notices use license templates from the pinned SPDX License List.
29Strict web and EAS builds download a missing template into the gitignored `.generated/` cache;
30`pnpm licenses:sync` can warm that cache explicitly. Local web and Metro development do not make a
31network request and omit generated rows until the cache exists. This keeps dev startup optional
32while preventing incomplete release artifacts.
33
34## Custom notices and package overrides
35
36The repository-level `third-party-licenses.config.json` holds manually maintained exceptions for
37all clients. Add an entry to `customNotices` for adapted icons, fonts, media, native modules, or
38another asset that did not come from an npm package:
39
40```json
41{
42 "name": "asset-name",
43 "license": "CC-BY-4.0",
44 "generatedNotices": [
45 {
46 "licenseId": "CC-BY-4.0",
47 "preamble": ["Asset by Example Author. Changes: converted to MP3."]
48 }
49 ],
50 "sourceUrl": "https://example.com/source",
51 "bundles": ["assets", "web"]
52}
53```
54
55Each `generatedNotices` item names an SPDX license template and can add `copyrights` or a short
56`preamble` for attribution and provenance. Multiple items are joined into one row for software
57that vendors separately licensed code. Keep `noticeFile` or `noticeFiles` only when a vendored
58source tree already carries an intrinsic license file that should remain beside it. Paths are
59relative to the config file. `bundles` controls which generated manifests include the entry and
60supplies 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.
62
63The `agent-device` and `expo-device-hub` custom notices take their versions from the
64[installer pins](../../apps/server/src/device/deviceToolVersions.json). Keep their package names
65in the config; their versions do not need manual updates.
66
67Use `packageOverrides` only when an installed npm archive omits its notice or has incorrect
68metadata:
69
70```json
71{
72 "name": "package-name",
73 "version": "1.2.3",
74 "generatedNotice": {
75 "licenseId": "MIT",
76 "copyrights": ["Copyright (c) 2026 Example Author"]
77 },
78 "license": "MIT",
79 "sourceUrl": "https://example.com/package-name"
80}
81```
82
83For packages containing separately licensed code, use `generatedNotices` with an array of templates instead of `generatedNotice`. The generator includes every notice in the package row.
84
85`version`, `license`, and `sourceUrl` are optional. Omitting `version` applies the override to every
86installed version of that package. An override can use `repositoryUrl` instead of `name` when
87several packages from one monorepo share the same notice:
88
89```json
90{
91 "repositoryUrl": "https://github.com/example/project",
92 "generatedNotice": {
93 "licenseId": "Apache-2.0"
94 }
95}
96```
97
98The generator also reuses an installed sibling package's notice when both packages declare the
99same normalized repository and license. A name-and-version override always wins over these
100repository fallbacks.
101
102The `@react-grab/cli` override uses the root React Grab repository's MIT license because the CLI's
103npm archive omits both its license field and license file. Keep the override until the published
104CLI package carries that metadata itself.
105
106Generated mobile files live under `apps/mobile/.generated/`, while fetched SPDX templates live
107under the repository `.generated/` directory. Both are ignored. Do not commit or edit them;
108updating dependencies or configuration is enough for the next strict build to refresh the output.