@xemahq/ui-kernel 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ui/branding/app-branding-provider.d.ts.map +1 -1
- package/dist/ui/branding/app-branding-provider.js +15 -10
- package/dist/ui/branding/app-branding-provider.js.map +1 -1
- package/dist/ui/branding/sanitize.d.ts +5 -3
- package/dist/ui/branding/sanitize.d.ts.map +1 -1
- package/dist/ui/branding/sanitize.js +9 -32
- package/dist/ui/branding/sanitize.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-branding-provider.d.ts","sourceRoot":"","sources":["../../../src/ui/branding/app-branding-provider.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-branding-provider.d.ts","sourceRoot":"","sources":["../../../src/ui/branding/app-branding-provider.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAUrE,eAAO,MAAM,qBAAqB,wBAAwB,CAAC;AAE3D,MAAM,WAAW,wBAAwB;IAEvC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAOlC,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAElD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAsDD,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,cAAc,EACd,SAAS,EACT,QAAQ,GACT,EAAE,wBAAwB,GAAG,KAAK,CAAC,YAAY,CAmB/C"}
|
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { BrandingConfigSchema } from '@xemahq/contracts/app-platform';
|
|
3
|
+
import { assertSafeCssTokenValue, CSS_TOKEN_KEY_PATTERN, UnsafeCssValueError, } from '@xemahq/contracts/css-safe';
|
|
2
4
|
import * as React from 'react';
|
|
3
5
|
import { cn } from '../cn';
|
|
4
6
|
import { AppBrandingContext, } from './app-branding-context';
|
|
5
|
-
import {
|
|
7
|
+
import { assertSafeLogoUrl } from './sanitize';
|
|
8
|
+
const PRIMARY_COLOR_PROBE_NAME = 'primaryColor';
|
|
6
9
|
export const APP_PRIMARY_COLOR_VAR = '--app-primary-color';
|
|
7
10
|
function resolveBranding(branding, tenantBranding) {
|
|
8
11
|
const displayName = tenantBranding?.displayName ?? branding.displayName;
|
|
9
12
|
const rawPrimary = tenantBranding?.primaryColor ?? branding.primaryColor;
|
|
10
13
|
const rawLogo = tenantBranding?.logoUrl ?? branding.logoUrl;
|
|
11
14
|
const cssTokens = { ...branding.cssTokens, ...tenantBranding?.cssTokens };
|
|
12
|
-
const primaryColor = rawPrimary
|
|
13
|
-
?
|
|
14
|
-
:
|
|
15
|
-
|
|
15
|
+
const primaryColor = rawPrimary === undefined
|
|
16
|
+
? undefined
|
|
17
|
+
: BrandingConfigSchema.parse({
|
|
18
|
+
displayName: PRIMARY_COLOR_PROBE_NAME,
|
|
19
|
+
primaryColor: rawPrimary,
|
|
20
|
+
}).primaryColor;
|
|
21
|
+
const logoUrl = assertSafeLogoUrl(rawLogo);
|
|
16
22
|
const cssVars = {};
|
|
17
23
|
if (primaryColor !== undefined) {
|
|
18
24
|
cssVars[APP_PRIMARY_COLOR_VAR] = primaryColor;
|
|
19
25
|
}
|
|
20
|
-
for (const [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (name !== null && value !== null) {
|
|
24
|
-
cssVars[name] = value;
|
|
26
|
+
for (const [key, value] of Object.entries(cssTokens)) {
|
|
27
|
+
if (!CSS_TOKEN_KEY_PATTERN.test(key)) {
|
|
28
|
+
throw new UnsafeCssValueError(`cssTokens.${key}`, 'a token key is lowercase kebab-case without the leading "--", at most 64 characters');
|
|
25
29
|
}
|
|
30
|
+
cssVars[`--${key}`] = assertSafeCssTokenValue(`cssTokens.${key}`, value);
|
|
26
31
|
}
|
|
27
32
|
return {
|
|
28
33
|
context: { displayName, logoUrl, primaryColor },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-branding-provider.js","sourceRoot":"","sources":["../../../src/ui/branding/app-branding-provider.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"app-branding-provider.js","sourceRoot":"","sources":["../../../src/ui/branding/app-branding-provider.tsx"],"names":[],"mappings":";AAwBA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAC3B,OAAO,EACL,kBAAkB,GAEnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAS/C,MAAM,wBAAwB,GAAG,cAAc,CAAC;AAGhD,MAAM,CAAC,MAAM,qBAAqB,GAAG,qBAAqB,CAAC;AAsB3D,SAAS,eAAe,CACtB,QAAwB,EACxB,cAAmD;IAKnD,MAAM,WAAW,GAAG,cAAc,EAAE,WAAW,IAAI,QAAQ,CAAC,WAAW,CAAC;IACxE,MAAM,UAAU,GAAG,cAAc,EAAE,YAAY,IAAI,QAAQ,CAAC,YAAY,CAAC;IACzE,MAAM,OAAO,GAAG,cAAc,EAAE,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC;IAC5D,MAAM,SAAS,GAAG,EAAE,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,cAAc,EAAE,SAAS,EAAE,CAAC;IAE1E,MAAM,YAAY,GAChB,UAAU,KAAK,SAAS;QACtB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC;YACzB,WAAW,EAAE,wBAAwB;YACrC,YAAY,EAAE,UAAU;SACzB,CAAC,CAAC,YAAY,CAAC;IACtB,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAE3C,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,CAAC,qBAAqB,CAAC,GAAG,YAAY,CAAC;IAChD,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,mBAAmB,CAC3B,aAAa,GAAG,EAAE,EAClB,qFAAqF,CACtF,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,uBAAuB,CAAC,aAAa,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO;QACL,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE;QAC/C,OAAO;KACR,CAAC;AACJ,CAAC;AAQD,MAAM,UAAU,mBAAmB,CAAC,EAClC,QAAQ,EACR,cAAc,EACd,SAAS,EACT,QAAQ,GACiB;IACzB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,CACxC,GAAG,EAAE,CAAC,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC,EAC/C,CAAC,QAAQ,EAAE,cAAc,CAAC,CAC3B,CAAC;IAEF,OAAO,CACL,KAAC,kBAAkB,CAAC,QAAQ,IAAC,KAAK,EAAE,OAAO,YACzC,mCACoB,EAAE,EACpB,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAGxB,KAAK,EAAE,OAAO,YAEb,QAAQ,GACL,GACsB,CAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export declare
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export declare class UnsafeLogoUrlError extends Error {
|
|
2
|
+
readonly field: string;
|
|
3
|
+
constructor(field: string, reason: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function assertSafeLogoUrl(raw: string | undefined): string | undefined;
|
|
4
6
|
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../../src/ui/branding/sanitize.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../../src/ui/branding/sanitize.ts"],"names":[],"mappings":"AAWA,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAK1C;AAOD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAc7E"}
|
|
@@ -1,35 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
return true;
|
|
8
|
-
}
|
|
1
|
+
export class UnsafeLogoUrlError extends Error {
|
|
2
|
+
field;
|
|
3
|
+
constructor(field, reason) {
|
|
4
|
+
super(`Refusing to render '${field}' as an image source: ${reason}.`);
|
|
5
|
+
this.name = 'UnsafeLogoUrlError';
|
|
6
|
+
this.field = field;
|
|
9
7
|
}
|
|
10
|
-
return false;
|
|
11
8
|
}
|
|
12
|
-
export function
|
|
13
|
-
const value = raw.trim();
|
|
14
|
-
if (value.length === 0) {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
if (CSS_VALUE_UNSAFE.test(value)) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
if (hasControlChar(value)) {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
return value;
|
|
24
|
-
}
|
|
25
|
-
export function sanitizeCssCustomPropertyName(rawKey) {
|
|
26
|
-
const name = rawKey.trim();
|
|
27
|
-
if (!CSS_CUSTOM_PROPERTY_NAME.test(name)) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
return `--${name}`;
|
|
31
|
-
}
|
|
32
|
-
export function sanitizeLogoUrl(raw) {
|
|
9
|
+
export function assertSafeLogoUrl(raw) {
|
|
33
10
|
if (raw === undefined) {
|
|
34
11
|
return undefined;
|
|
35
12
|
}
|
|
@@ -38,10 +15,10 @@ export function sanitizeLogoUrl(raw) {
|
|
|
38
15
|
parsed = new URL(raw);
|
|
39
16
|
}
|
|
40
17
|
catch {
|
|
41
|
-
|
|
18
|
+
throw new UnsafeLogoUrlError('logoUrl', 'the value is not an absolute URL');
|
|
42
19
|
}
|
|
43
20
|
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
44
|
-
|
|
21
|
+
throw new UnsafeLogoUrlError('logoUrl', 'only http(s) URLs are allowed');
|
|
45
22
|
}
|
|
46
23
|
return parsed.href;
|
|
47
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../../src/ui/branding/sanitize.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../../src/ui/branding/sanitize.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,KAAK,CAAS;IAEvB,YAAY,KAAa,EAAE,MAAc;QACvC,KAAK,CAAC,uBAAuB,KAAK,yBAAyB,MAAM,GAAG,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AAOD,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,kBAAkB,CAAC,SAAS,EAAE,kCAAkC,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAChE,MAAM,IAAI,kBAAkB,CAAC,SAAS,EAAE,+BAA+B,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/ui-kernel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Host-framework-agnostic UI kernel for Xema. Defines the SystemBus orchestration contract (capability.invoke, cross-biome intents, command palette, xema:// deeplinks, window manager) AND the biome-host contract surface (FrontendBiome/FrontendBiomeFactory, HostBridge, the singleton biomeRegistry, session contributions) that every frontend biome composes against. No Vite, Next.js, or React-Router — React itself IS allowed as the shared component model (the contracts traffic in ReactNode/ComponentType and a React context). Concrete host adapters (router/auth/toast wiring) live in separate packages that consume this kernel. The SystemBus is pure orchestration: it never authorizes, the backend capability-router enforces all policy.",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"@tanstack/react-query": "^5.0.0",
|
|
64
64
|
"react": "^18.3.1",
|
|
65
|
-
"@xemahq/contracts": ">=0.
|
|
65
|
+
"@xemahq/contracts": ">=0.90.0"
|
|
66
66
|
},
|
|
67
67
|
"peerDependenciesMeta": {
|
|
68
68
|
"@tanstack/react-query": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@types/node": "25.2.3",
|
|
75
75
|
"@types/react": "^18.3.30",
|
|
76
76
|
"@types/react-dom": "^18.3.7",
|
|
77
|
-
"@xemahq/contracts": "^0.
|
|
77
|
+
"@xemahq/contracts": "^0.90.0",
|
|
78
78
|
"eslint": "^9.39.4",
|
|
79
79
|
"prettier": "3.6.2",
|
|
80
80
|
"react": "^18.3.1",
|
|
@@ -119,6 +119,6 @@
|
|
|
119
119
|
"typecheck": "tsc -p tsconfig.lint.json --noEmit"
|
|
120
120
|
},
|
|
121
121
|
"xemaRelease": {
|
|
122
|
-
"sourceDigest": "sha256:
|
|
122
|
+
"sourceDigest": "sha256:7543ee6ff94afbaa3a2e75b2a11f429b08ebccf70725986bd21d350b9f46b5e1"
|
|
123
123
|
}
|
|
124
124
|
}
|