From 6053e829981d9dc96dfaaa4a55324d4f7096627f Mon Sep 17 00:00:00 2001 From: Einar Date: Sun, 16 Aug 2026 17:46:26 +0200 Subject: [PATCH] Let a package and a theme link to their license terms `ScenePackage` gained `License` and `LicenseUrl`, and `Theme` gained the matching `LicenseUrl` to go with the `License` it already carried. A license name on its own does not tell an author what they are taking on. "PrimeUI Community / Commercial" answers nothing about whether they qualify for the free tier or owe a fee - the link is the part that does, so the model carries it rather than making someone go and search. This matters now because it stopped being uniform. Every package here was MIT until PrimeReact 11 relicensed under PrimeTek's commercial PrimeUI, so `Cratis.PrimeReact` and the themes built on its presets now point at https://primeui.dev/licenses/community while everything else points at ours. A package picker can show the difference at the moment someone is choosing, instead of leaving it to a banner in production. Co-Authored-By: Claude Opus 5 (1M context) --- Source/DotNET/Model/Packages/ScenePackage.cs | 14 +++++++++++++- Source/DotNET/Model/Profiles/Theme.cs | 4 +++- .../blueprint.components/componentsBlueprint.ts | 2 ++ .../blueprint.default/defaultBlueprint.ts | 2 ++ .../components/cratisComponentsPackage.ts | 2 ++ Source/JavaScript/model/packages/ScenePackage.ts | 16 ++++++++++++++++ Source/JavaScript/model/profiles/Theme.ts | 6 ++++++ .../when_checking_attribution.ts | 14 ++++++++++++-- .../JavaScript/primereact/primeReactPackage.ts | 5 +++++ .../primereact/theme/primeReactThemes.ts | 10 +++++++++- Source/JavaScript/react/core/corePackage.ts | 2 ++ Source/JavaScript/tailwind/tailwindPackage.ts | 2 ++ scene-model-shape.json | 7 +++++-- 13 files changed, 79 insertions(+), 7 deletions(-) diff --git a/Source/DotNET/Model/Packages/ScenePackage.cs b/Source/DotNET/Model/Packages/ScenePackage.cs index a86db6a..a018694 100644 --- a/Source/DotNET/Model/Packages/ScenePackage.cs +++ b/Source/DotNET/Model/Packages/ScenePackage.cs @@ -23,6 +23,16 @@ namespace Cratis.Scene.Model.Packages; /// The module that implements the package - an npm package name for a web renderer. Design-time tooling /// needs it to know what to import; the model itself never loads anything. /// +/// +/// The license the package is available under, as a short human-readable name (MIT, +/// PrimeUI Community). A package picker shows it, because "what am I taking on by selecting this" +/// is a question an author needs answered before they select it, not after. +/// +/// +/// Where the license terms actually live, so a reader can go and check rather than take +/// on trust. Required in practice for anything that is not a permissive +/// standard license - a name alone tells an author nothing about eligibility or obligations. +/// public record ScenePackage( string Name, string Version, @@ -35,4 +45,6 @@ public record ScenePackage( IReadOnlyList Themes, string? DisplayName = null, string? Description = null, - string? Module = null); + string? Module = null, + string? License = null, + string? LicenseUrl = null); diff --git a/Source/DotNET/Model/Profiles/Theme.cs b/Source/DotNET/Model/Profiles/Theme.cs index 3dcc76f..9bc706e 100644 --- a/Source/DotNET/Model/Profiles/Theme.cs +++ b/Source/DotNET/Model/Profiles/Theme.cs @@ -23,6 +23,7 @@ namespace Cratis.Scene.Model.Profiles; /// /// A link to the original creator or the theme's home, shown alongside . /// The license the theme is used under, so redistributing it stays honest. +/// Where those license terms live, so a reader can check them rather than take on trust. /// A one-line description for a theme picker. public record Theme( string Name, @@ -32,4 +33,5 @@ public record Theme( string? Author = null, string? AuthorUrl = null, string? License = null, - string? Description = null); + string? Description = null, + string? LicenseUrl = null); diff --git a/Source/JavaScript/blueprint.components/componentsBlueprint.ts b/Source/JavaScript/blueprint.components/componentsBlueprint.ts index 44e8941..c645ecc 100644 --- a/Source/JavaScript/blueprint.components/componentsBlueprint.ts +++ b/Source/JavaScript/blueprint.components/componentsBlueprint.ts @@ -49,6 +49,8 @@ export const componentsBlueprintManifest: ScenePackage = { displayName: 'Cratis Components Blueprint', description: 'Arc-bound screen and dialog templates: whole pages built from the Cratis Components composites, for the default blueprint shell.', module: '@cratis/scene.blueprint.components', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/Source/JavaScript/blueprint.default/defaultBlueprint.ts b/Source/JavaScript/blueprint.default/defaultBlueprint.ts index b9f79ab..be42f47 100644 --- a/Source/JavaScript/blueprint.default/defaultBlueprint.ts +++ b/Source/JavaScript/blueprint.default/defaultBlueprint.ts @@ -42,6 +42,8 @@ export const defaultBlueprintManifest: ScenePackage = { displayName: 'Cratis Default Blueprint', description: 'Application shells with eight menu modes, the components that fill their slots, and a full screen and dialog template set.', module: '@cratis/scene.blueprint.default', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/Source/JavaScript/components/cratisComponentsPackage.ts b/Source/JavaScript/components/cratisComponentsPackage.ts index be46fcb..d7fdbec 100644 --- a/Source/JavaScript/components/cratisComponentsPackage.ts +++ b/Source/JavaScript/components/cratisComponentsPackage.ts @@ -90,6 +90,8 @@ export const cratisComponentsPackageManifest: ScenePackage = { displayName: 'Cratis Components', description: "Cratis' Arc-bound data, form and dialog composites, built on PrimeReact and Tailwind.", module: '@cratis/scene.components', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/Source/JavaScript/model/packages/ScenePackage.ts b/Source/JavaScript/model/packages/ScenePackage.ts index 9e6e3ae..9a92ba8 100644 --- a/Source/JavaScript/model/packages/ScenePackage.ts +++ b/Source/JavaScript/model/packages/ScenePackage.ts @@ -72,6 +72,20 @@ export interface ScenePackage { * tooling needs it to know what to import; the model itself never loads anything. */ module?: string; + + /** + * The license the package is available under, as a short human-readable name (`MIT`, + * `PrimeUI Community`). A package picker shows it, because "what am I taking on by selecting this" + * is a question an author needs answered before they select it, not after. + */ + license?: string; + + /** + * Where the license terms actually live, so a reader can go and check rather than take `license` on + * trust. Required in practice for anything that is not a permissive standard license — a name alone + * tells an author nothing about eligibility or obligations. + */ + licenseUrl?: string; } export const ScenePackagePropertyNames: (keyof ScenePackage)[] = [ @@ -87,4 +101,6 @@ export const ScenePackagePropertyNames: (keyof ScenePackage)[] = [ 'displayName', 'description', 'module', + 'license', + 'licenseUrl', ]; diff --git a/Source/JavaScript/model/profiles/Theme.ts b/Source/JavaScript/model/profiles/Theme.ts index e4807ed..1b8368c 100644 --- a/Source/JavaScript/model/profiles/Theme.ts +++ b/Source/JavaScript/model/profiles/Theme.ts @@ -50,6 +50,11 @@ export interface Theme { * A one-line description for a theme picker. */ description?: string; + + /** + * Where those license terms live, so a reader can check them rather than take `license` on trust. + */ + licenseUrl?: string; } export const ThemePropertyNames: (keyof Theme)[] = [ @@ -61,4 +66,5 @@ export const ThemePropertyNames: (keyof Theme)[] = [ 'authorUrl', 'license', 'description', + 'licenseUrl', ]; diff --git a/Source/JavaScript/primereact/for_primeReactThemes/when_checking_attribution.ts b/Source/JavaScript/primereact/for_primeReactThemes/when_checking_attribution.ts index 44f2c2d..911d3ec 100644 --- a/Source/JavaScript/primereact/for_primeReactThemes/when_checking_attribution.ts +++ b/Source/JavaScript/primereact/for_primeReactThemes/when_checking_attribution.ts @@ -1,7 +1,7 @@ // Copyright (c) Cratis. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -import { primeReactThemes } from '../theme'; +import { primeReactThemeLicense, primeReactThemeLicenseUrl, primeReactThemes } from '../theme'; describe('when checking attribution', () => { it('should credit an author on every theme', () => { @@ -27,7 +27,17 @@ describe('when checking attribution', () => { * catalog would have gone on advertising MIT indefinitely. */ it('should state the commercial license PrimeReact 11 actually ships under, not the MIT of v10', () => { - primeReactThemes.filter((theme) => theme.license !== 'PrimeUI Commercial').should.deep.equal([]); + primeReactThemeLicense.should.equal('PrimeUI Community / Commercial'); + primeReactThemes.filter((theme) => theme.license !== primeReactThemeLicense).should.deep.equal([]); + }); + + /** + * A license name on its own does not tell a reader whether they qualify for the free Community tier + * or owe a commercial fee. The link is the part that answers that, so it is pinned too. + */ + it('should link to the terms on every theme, not just name them', () => { + primeReactThemeLicenseUrl.should.equal('https://primeui.dev/licenses/community'); + primeReactThemes.filter((theme) => theme.licenseUrl !== primeReactThemeLicenseUrl).should.deep.equal([]); }); it('should describe every theme for a picker', () => { diff --git a/Source/JavaScript/primereact/primeReactPackage.ts b/Source/JavaScript/primereact/primeReactPackage.ts index eebae95..0f7307d 100644 --- a/Source/JavaScript/primereact/primeReactPackage.ts +++ b/Source/JavaScript/primereact/primeReactPackage.ts @@ -71,6 +71,11 @@ export const primeReactPackageManifest: ScenePackage = { displayName: 'PrimeReact', description: 'PrimeReact 11 components and PrimeTek\'s @primeuix/themes presets, mapped onto Scene\'s abstract component names.', module: '@cratis/scene.primereact', + // PrimeReact 11 is PrimeTek's commercial PrimeUI, not MIT as version 10 was. The Community + // tier is free for eligible projects but still requires a key, so an author selecting this + // package needs to see the terms before they select it, not after a banner appears. + license: 'PrimeUI Community / Commercial', + licenseUrl: 'https://primeui.dev/licenses/community', }; /** diff --git a/Source/JavaScript/primereact/theme/primeReactThemes.ts b/Source/JavaScript/primereact/theme/primeReactThemes.ts index a1103d2..c780e7a 100644 --- a/Source/JavaScript/primereact/theme/primeReactThemes.ts +++ b/Source/JavaScript/primereact/theme/primeReactThemes.ts @@ -41,7 +41,14 @@ export const primeReactThemeCompatibility: string[] = ['PrimeReact', 'Tailwind', * @see https://primeui.dev/licenses/community for the free community tier and its eligibility limits. * @see https://primeui.dev/licenses/commercial for the paid tier. */ -export const primeReactThemeLicense = 'PrimeUI Commercial'; +export const primeReactThemeLicense = 'PrimeUI Community / Commercial'; + +/** + * Where those terms live. A license name alone tells a reader nothing about whether they qualify for the + * free Community tier or owe a commercial fee, so the catalog carries the link rather than making them + * search for it. + */ +export const primeReactThemeLicenseUrl = 'https://primeui.dev/licenses/community'; /** * Every theme this package ships, as Scene {@link Theme}s. @@ -61,6 +68,7 @@ export const primeReactThemes: Theme[] = themePresets.map((preset) => ({ author: 'PrimeTek', authorUrl: 'https://primereact.org', license: primeReactThemeLicense, + licenseUrl: primeReactThemeLicenseUrl, })); /** diff --git a/Source/JavaScript/react/core/corePackage.ts b/Source/JavaScript/react/core/corePackage.ts index 5a5b120..17da3b4 100644 --- a/Source/JavaScript/react/core/corePackage.ts +++ b/Source/JavaScript/react/core/corePackage.ts @@ -25,6 +25,8 @@ export const corePackageManifest: ScenePackage = { displayName: 'Core', description: 'The built-in fallback vocabulary every ui profile resolves against.', module: '@cratis/scene.react', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/Source/JavaScript/tailwind/tailwindPackage.ts b/Source/JavaScript/tailwind/tailwindPackage.ts index 1165cf6..cde78e5 100644 --- a/Source/JavaScript/tailwind/tailwindPackage.ts +++ b/Source/JavaScript/tailwind/tailwindPackage.ts @@ -27,6 +27,8 @@ export const tailwindPackageManifest: ScenePackage = { displayName: 'Tailwind CSS', description: 'Utility-first CSS. The styling system Cratis Components and the default layouts are written against.', module: '@cratis/scene.tailwind', + license: 'MIT', + licenseUrl: 'https://github.com/Cratis/Scene/blob/main/LICENSE', }; /** diff --git a/scene-model-shape.json b/scene-model-shape.json index 1e1a988..4ba7d2a 100644 --- a/scene-model-shape.json +++ b/scene-model-shape.json @@ -191,7 +191,8 @@ "author", "authorUrl", "license", - "description" + "description", + "licenseUrl" ], "PackageDependency": [ "name", @@ -209,7 +210,9 @@ "themes", "displayName", "description", - "module" + "module", + "license", + "licenseUrl" ], "Screen": [ "name",