| 1 | # Open source license notices |
| 2 | |
| 3 | License 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 | |
| 13 | Neither path depends on the connected environment or an RPC. |
| 14 | |
| 15 | ## What the build collects |
| 16 | |
| 17 | The generator follows installed production and optional dependencies, including dependencies of |
| 18 | workspace packages, and omits first-party `@t3tools/*` packages. The web manifest starts from the |
| 19 | web, server, and desktop package manifests. The mobile manifest starts from the mobile package |
| 20 | manifest. During the web bundle, the generator also checks emitted module ids to catch a bundled |
| 21 | npm import missing from a package manifest. |
| 22 | |
| 23 | The mobile manifest deliberately follows the complete production dependency closure declared by |
| 24 | Expo and React Native. That is conservative and can include build tooling that is not present in |
| 25 | the final JavaScript bundle, but it avoids dropping a notice when platform bundling changes. |
| 26 | |
| 27 | The build fails when a collected package has no distributable license identifier or contains no |
| 28 | license or notice text. Generated notices use license templates from the pinned SPDX License List. |
| 29 | Strict 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 |
| 31 | network request and omit generated rows until the cache exists. This keeps dev startup optional |
| 32 | while preventing incomplete release artifacts. |
| 33 | |
| 34 | ## Custom notices and package overrides |
| 35 | |
| 36 | The repository-level `third-party-licenses.config.json` holds manually maintained exceptions for |
| 37 | all clients. Add an entry to `customNotices` for adapted icons, fonts, media, native modules, or |
| 38 | another 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 | |
| 55 | Each `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 |
| 57 | that vendors separately licensed code. Keep `noticeFile` or `noticeFiles` only when a vendored |
| 58 | source tree already carries an intrinsic license file that should remain beside it. Paths are |
| 59 | relative to the config file. `bundles` controls which generated manifests include the entry and |
| 60 | supplies the label shown to users. Use `includeInBundles` when those differ, such as an optional |
| 61 | server tool that should appear in both client manifests but is not bundled into either client. |
| 62 | |
| 63 | The `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 |
| 65 | in the config; their versions do not need manual updates. |
| 66 | |
| 67 | Use `packageOverrides` only when an installed npm archive omits its notice or has incorrect |
| 68 | metadata: |
| 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 | |
| 83 | For 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 |
| 86 | installed version of that package. An override can use `repositoryUrl` instead of `name` when |
| 87 | several 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 | |
| 98 | The generator also reuses an installed sibling package's notice when both packages declare the |
| 99 | same normalized repository and license. A name-and-version override always wins over these |
| 100 | repository fallbacks. |
| 101 | |
| 102 | The `@react-grab/cli` override uses the root React Grab repository's MIT license because the CLI's |
| 103 | npm archive omits both its license field and license file. Keep the override until the published |
| 104 | CLI package carries that metadata itself. |
| 105 | |
| 106 | Generated mobile files live under `apps/mobile/.generated/`, while fetched SPDX templates live |
| 107 | under the repository `.generated/` directory. Both are ignored. Do not commit or edit them; |
| 108 | updating dependencies or configuration is enough for the next strict build to refresh the output. |