@xemahq/kernel-contracts 0.34.0 → 0.35.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/app-runtime/index.d.ts +1 -0
- package/dist/app-runtime/index.d.ts.map +1 -1
- package/dist/app-runtime/index.js +1 -0
- package/dist/app-runtime/index.js.map +1 -1
- package/dist/app-runtime/lib/app-shell-binding.d.ts +38 -0
- package/dist/app-runtime/lib/app-shell-binding.d.ts.map +1 -0
- package/dist/app-runtime/lib/app-shell-binding.js +58 -0
- package/dist/app-runtime/lib/app-shell-binding.js.map +1 -0
- package/package.json +1 -1
- package/src/app-runtime/index.ts +1 -0
- package/src/app-runtime/lib/app-shell-binding.ts +159 -0
|
@@ -6,6 +6,7 @@ export * from './lib/app-client';
|
|
|
6
6
|
export * from './lib/app-lockfile';
|
|
7
7
|
export * from './lib/branding-config';
|
|
8
8
|
export * from './lib/surface-kind';
|
|
9
|
+
export * from './lib/app-shell-binding';
|
|
9
10
|
export * from './lib/app-channel';
|
|
10
11
|
export * from './lib/app-release';
|
|
11
12
|
export * from './lib/app';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/app-runtime/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/app-runtime/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"}
|
|
@@ -22,6 +22,7 @@ __exportStar(require("./lib/app-client"), exports);
|
|
|
22
22
|
__exportStar(require("./lib/app-lockfile"), exports);
|
|
23
23
|
__exportStar(require("./lib/branding-config"), exports);
|
|
24
24
|
__exportStar(require("./lib/surface-kind"), exports);
|
|
25
|
+
__exportStar(require("./lib/app-shell-binding"), exports);
|
|
25
26
|
__exportStar(require("./lib/app-channel"), exports);
|
|
26
27
|
__exportStar(require("./lib/app-release"), exports);
|
|
27
28
|
__exportStar(require("./lib/app"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/app-runtime/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,wDAAsC;AACtC,yDAAuC;AACvC,0DAAwC;AACxC,mDAAiC;AACjC,qDAAmC;AACnC,wDAAsC;AACtC,qDAAmC;AACnC,oDAAkC;AAClC,oDAAkC;AAClC,4CAA0B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/app-runtime/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,wDAAsC;AACtC,yDAAuC;AACvC,0DAAwC;AACxC,mDAAiC;AACjC,qDAAmC;AACnC,wDAAsC;AACtC,qDAAmC;AACnC,0DAAwC;AACxC,oDAAkC;AAClC,oDAAkC;AAClC,4CAA0B"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AudienceKind } from './audience-policy';
|
|
3
|
+
export declare enum AppShellKind {
|
|
4
|
+
Hosted = "hosted",
|
|
5
|
+
Standalone = "standalone",
|
|
6
|
+
Embedded = "embedded",
|
|
7
|
+
Headless = "headless"
|
|
8
|
+
}
|
|
9
|
+
export declare const AppShellKindSchema: z.ZodEnum<typeof AppShellKind>;
|
|
10
|
+
export declare enum AppHostBinding {
|
|
11
|
+
Xema = "xema",
|
|
12
|
+
CustomDomain = "custom-domain",
|
|
13
|
+
PathBased = "path-based"
|
|
14
|
+
}
|
|
15
|
+
export declare const AppHostBindingSchema: z.ZodEnum<typeof AppHostBinding>;
|
|
16
|
+
export interface AppSurfaceDimensions {
|
|
17
|
+
readonly shell: AppShellKind;
|
|
18
|
+
readonly audience: AudienceKind;
|
|
19
|
+
readonly host: AppHostBinding;
|
|
20
|
+
}
|
|
21
|
+
export declare const AppSurfaceDimensionsSchema: z.ZodType<AppSurfaceDimensions>;
|
|
22
|
+
export declare enum AppSurfaceConflictCode {
|
|
23
|
+
HeadlessWithChrome = "headless-with-chrome",
|
|
24
|
+
EmbeddedIsChrome = "embedded-is-chrome",
|
|
25
|
+
StandaloneNeedsOwnHost = "standalone-needs-own-host",
|
|
26
|
+
EmbeddedNeedsXemaHost = "embedded-needs-xema-host"
|
|
27
|
+
}
|
|
28
|
+
export interface AppSurfaceConflict {
|
|
29
|
+
readonly code: AppSurfaceConflictCode;
|
|
30
|
+
readonly message: string;
|
|
31
|
+
}
|
|
32
|
+
export interface AppSurfaceValidation {
|
|
33
|
+
readonly ok: boolean;
|
|
34
|
+
readonly conflicts: readonly AppSurfaceConflict[];
|
|
35
|
+
}
|
|
36
|
+
export declare function validateAppSurfaceCombination(dims: AppSurfaceDimensions): AppSurfaceValidation;
|
|
37
|
+
export declare function isHeadlessEmbeddedContradiction(shell: AppShellKind, alsoEmbedded: boolean): boolean;
|
|
38
|
+
//# sourceMappingURL=app-shell-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-shell-binding.d.ts","sourceRoot":"","sources":["../../../src/app-runtime/lib/app-shell-binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAyBjD,oBAAY,YAAY;IACtB,MAAM,WAAW;IACjB,UAAU,eAAe;IACzB,QAAQ,aAAa;IACrB,QAAQ,aAAa;CACtB;AAED,eAAO,MAAM,kBAAkB,gCAA6B,CAAC;AAY7D,oBAAY,cAAc;IACxB,IAAI,SAAS;IACb,YAAY,kBAAkB;IAC9B,SAAS,eAAe;CACzB;AAED,eAAO,MAAM,oBAAoB,kCAA+B,CAAC;AAGjE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;CAC/B;AAED,eAAO,MAAM,0BAA0B,EAAE,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAMzB,CAAC;AAM/C,oBAAY,sBAAsB;IAChC,kBAAkB,yBAAyB;IAC3C,gBAAgB,uBAAuB;IACvC,sBAAsB,8BAA8B;IACpD,qBAAqB,6BAA6B;CACnD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACnD;AAsBD,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,oBAAoB,GACzB,oBAAoB,CAgCtB;AASD,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,YAAY,EACnB,YAAY,EAAE,OAAO,GACpB,OAAO,CAET"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AppSurfaceConflictCode = exports.AppSurfaceDimensionsSchema = exports.AppHostBindingSchema = exports.AppHostBinding = exports.AppShellKindSchema = exports.AppShellKind = void 0;
|
|
4
|
+
exports.validateAppSurfaceCombination = validateAppSurfaceCombination;
|
|
5
|
+
exports.isHeadlessEmbeddedContradiction = isHeadlessEmbeddedContradiction;
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const audience_policy_1 = require("./audience-policy");
|
|
8
|
+
var AppShellKind;
|
|
9
|
+
(function (AppShellKind) {
|
|
10
|
+
AppShellKind["Hosted"] = "hosted";
|
|
11
|
+
AppShellKind["Standalone"] = "standalone";
|
|
12
|
+
AppShellKind["Embedded"] = "embedded";
|
|
13
|
+
AppShellKind["Headless"] = "headless";
|
|
14
|
+
})(AppShellKind || (exports.AppShellKind = AppShellKind = {}));
|
|
15
|
+
exports.AppShellKindSchema = zod_1.z.nativeEnum(AppShellKind);
|
|
16
|
+
var AppHostBinding;
|
|
17
|
+
(function (AppHostBinding) {
|
|
18
|
+
AppHostBinding["Xema"] = "xema";
|
|
19
|
+
AppHostBinding["CustomDomain"] = "custom-domain";
|
|
20
|
+
AppHostBinding["PathBased"] = "path-based";
|
|
21
|
+
})(AppHostBinding || (exports.AppHostBinding = AppHostBinding = {}));
|
|
22
|
+
exports.AppHostBindingSchema = zod_1.z.nativeEnum(AppHostBinding);
|
|
23
|
+
exports.AppSurfaceDimensionsSchema = zod_1.z
|
|
24
|
+
.object({
|
|
25
|
+
shell: exports.AppShellKindSchema,
|
|
26
|
+
audience: zod_1.z.nativeEnum(audience_policy_1.AudienceKind),
|
|
27
|
+
host: exports.AppHostBindingSchema,
|
|
28
|
+
})
|
|
29
|
+
.strict();
|
|
30
|
+
var AppSurfaceConflictCode;
|
|
31
|
+
(function (AppSurfaceConflictCode) {
|
|
32
|
+
AppSurfaceConflictCode["HeadlessWithChrome"] = "headless-with-chrome";
|
|
33
|
+
AppSurfaceConflictCode["EmbeddedIsChrome"] = "embedded-is-chrome";
|
|
34
|
+
AppSurfaceConflictCode["StandaloneNeedsOwnHost"] = "standalone-needs-own-host";
|
|
35
|
+
AppSurfaceConflictCode["EmbeddedNeedsXemaHost"] = "embedded-needs-xema-host";
|
|
36
|
+
})(AppSurfaceConflictCode || (exports.AppSurfaceConflictCode = AppSurfaceConflictCode = {}));
|
|
37
|
+
function validateAppSurfaceCombination(dims) {
|
|
38
|
+
const conflicts = [];
|
|
39
|
+
if (dims.shell === AppShellKind.Standalone &&
|
|
40
|
+
dims.host === AppHostBinding.PathBased) {
|
|
41
|
+
conflicts.push({
|
|
42
|
+
code: AppSurfaceConflictCode.StandaloneNeedsOwnHost,
|
|
43
|
+
message: 'A standalone app has its own full-page surface and cannot be path-based on a shared host; use xema or custom-domain.',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (dims.shell === AppShellKind.Embedded &&
|
|
47
|
+
dims.host !== AppHostBinding.Xema) {
|
|
48
|
+
conflicts.push({
|
|
49
|
+
code: AppSurfaceConflictCode.EmbeddedNeedsXemaHost,
|
|
50
|
+
message: "An embedded app is served into a third-party page and relies on the Xema origin's CSP/cookies; it must be xema-hosted.",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return { ok: conflicts.length === 0, conflicts };
|
|
54
|
+
}
|
|
55
|
+
function isHeadlessEmbeddedContradiction(shell, alsoEmbedded) {
|
|
56
|
+
return shell === AppShellKind.Headless && alsoEmbedded;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=app-shell-binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-shell-binding.js","sourceRoot":"","sources":["../../../src/app-runtime/lib/app-shell-binding.ts"],"names":[],"mappings":";;;AA8GA,sEAkCC;AASD,0EAKC;AA9JD,6BAAwB;AAExB,uDAAiD;AAyBjD,IAAY,YAKX;AALD,WAAY,YAAY;IACtB,iCAAiB,CAAA;IACjB,yCAAyB,CAAA;IACzB,qCAAqB,CAAA;IACrB,qCAAqB,CAAA;AACvB,CAAC,EALW,YAAY,4BAAZ,YAAY,QAKvB;AAEY,QAAA,kBAAkB,GAAG,OAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AAY7D,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,+BAAa,CAAA;IACb,gDAA8B,CAAA;IAC9B,0CAAwB,CAAA;AAC1B,CAAC,EAJW,cAAc,8BAAd,cAAc,QAIzB;AAEY,QAAA,oBAAoB,GAAG,OAAC,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AASpD,QAAA,0BAA0B,GAAoC,OAAC;KACzE,MAAM,CAAC;IACN,KAAK,EAAE,0BAAkB;IACzB,QAAQ,EAAE,OAAC,CAAC,UAAU,CAAC,8BAAY,CAAC;IACpC,IAAI,EAAE,4BAAoB;CAC3B,CAAC;KACD,MAAM,EAAqC,CAAC;AAM/C,IAAY,sBAKX;AALD,WAAY,sBAAsB;IAChC,qEAA2C,CAAA;IAC3C,iEAAuC,CAAA;IACvC,8EAAoD,CAAA;IACpD,4EAAkD,CAAA;AACpD,CAAC,EALW,sBAAsB,sCAAtB,sBAAsB,QAKjC;AAgCD,SAAgB,6BAA6B,CAC3C,IAA0B;IAE1B,MAAM,SAAS,GAAyB,EAAE,CAAC;IAQ3C,IACE,IAAI,CAAC,KAAK,KAAK,YAAY,CAAC,UAAU;QACtC,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,SAAS,EACtC,CAAC;QACD,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,sBAAsB,CAAC,sBAAsB;YACnD,OAAO,EACL,sHAAsH;SACzH,CAAC,CAAC;IACL,CAAC;IAED,IACE,IAAI,CAAC,KAAK,KAAK,YAAY,CAAC,QAAQ;QACpC,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,IAAI,EACjC,CAAC;QACD,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,sBAAsB,CAAC,qBAAqB;YAClD,OAAO,EACL,wHAAwH;SAC3H,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;AACnD,CAAC;AASD,SAAgB,+BAA+B,CAC7C,KAAmB,EACnB,YAAqB;IAErB,OAAO,KAAK,KAAK,YAAY,CAAC,QAAQ,IAAI,YAAY,CAAC;AACzD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xemahq/kernel-contracts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Consolidated Xema OS kernel wire contracts — pure types + zod schemas for the kernel protocol surfaces. One package, one npm scope, wildcard per-surface subpath exports. No framework/runtime deps.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Neuralchowder Inc. <developer@xema.dev> (https://xema.dev)",
|
package/src/app-runtime/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from './lib/app-client';
|
|
|
6
6
|
export * from './lib/app-lockfile';
|
|
7
7
|
export * from './lib/branding-config';
|
|
8
8
|
export * from './lib/surface-kind';
|
|
9
|
+
export * from './lib/app-shell-binding';
|
|
9
10
|
export * from './lib/app-channel';
|
|
10
11
|
export * from './lib/app-release';
|
|
11
12
|
export * from './lib/app';
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
import { AudienceKind } from './audience-policy';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* D14 — Shell, audience and host are THREE ORTHOGONAL dimensions of an App.
|
|
7
|
+
* A public page is not necessarily embedded; a standalone app may be anonymous
|
|
8
|
+
* or internally authenticated. This file owns two of the three closed dimensions
|
|
9
|
+
* (the third, audience, is the existing {@link AudienceKind} — D14 forbids
|
|
10
|
+
* minting a second audience enum) and the rules for which COMBINATIONS are legal.
|
|
11
|
+
*
|
|
12
|
+
* The legality rules live here, in the kernel, next to the dimensions they
|
|
13
|
+
* constrain — not scattered across each consumer. app-forge's publish path calls
|
|
14
|
+
* {@link validateAppSurfaceCombination}; it does not re-encode the rules.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* `AppShellKind` — how much host chrome / navigation / layout an App surface
|
|
19
|
+
* carries. Owns: chrome, nav, layout.
|
|
20
|
+
*
|
|
21
|
+
* - `Hosted` — rendered inside the Xema host shell (rail, topbar, org switch).
|
|
22
|
+
* - `Standalone` — its own full-page surface, no host shell (e.g. a custom domain).
|
|
23
|
+
* - `Embedded` — rendered inside a third-party page via an iframe/snippet.
|
|
24
|
+
* - `Headless` — no UI at all; an API/automation surface.
|
|
25
|
+
*
|
|
26
|
+
* Values are stable wire strings — never compare against a free-form string.
|
|
27
|
+
*/
|
|
28
|
+
export enum AppShellKind {
|
|
29
|
+
Hosted = 'hosted',
|
|
30
|
+
Standalone = 'standalone',
|
|
31
|
+
Embedded = 'embedded',
|
|
32
|
+
Headless = 'headless',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const AppShellKindSchema = z.nativeEnum(AppShellKind);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* `AppHostBinding` — where an App is served from. Owns: origin, CSP, cookies,
|
|
39
|
+
* SEO, certificates.
|
|
40
|
+
*
|
|
41
|
+
* - `Xema` — under a Xema-owned origin/path.
|
|
42
|
+
* - `CustomDomain` — the customer's own domain (needs ACME cert issuance).
|
|
43
|
+
* - `PathBased` — a path on a shared host, not its own origin.
|
|
44
|
+
*
|
|
45
|
+
* Values are stable wire strings.
|
|
46
|
+
*/
|
|
47
|
+
export enum AppHostBinding {
|
|
48
|
+
Xema = 'xema',
|
|
49
|
+
CustomDomain = 'custom-domain',
|
|
50
|
+
PathBased = 'path-based',
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const AppHostBindingSchema = z.nativeEnum(AppHostBinding);
|
|
54
|
+
|
|
55
|
+
/** The three-dimension surface descriptor an App declares. */
|
|
56
|
+
export interface AppSurfaceDimensions {
|
|
57
|
+
readonly shell: AppShellKind;
|
|
58
|
+
readonly audience: AudienceKind;
|
|
59
|
+
readonly host: AppHostBinding;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const AppSurfaceDimensionsSchema: z.ZodType<AppSurfaceDimensions> = z
|
|
63
|
+
.object({
|
|
64
|
+
shell: AppShellKindSchema,
|
|
65
|
+
audience: z.nativeEnum(AudienceKind),
|
|
66
|
+
host: AppHostBindingSchema,
|
|
67
|
+
})
|
|
68
|
+
.strict() as z.ZodType<AppSurfaceDimensions>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A single reason a `(shell, audience, host)` combination is illegal. `code` is a
|
|
72
|
+
* closed set so consumers can branch on it; `message` is human-facing.
|
|
73
|
+
*/
|
|
74
|
+
export enum AppSurfaceConflictCode {
|
|
75
|
+
HeadlessWithChrome = 'headless-with-chrome',
|
|
76
|
+
EmbeddedIsChrome = 'embedded-is-chrome',
|
|
77
|
+
StandaloneNeedsOwnHost = 'standalone-needs-own-host',
|
|
78
|
+
EmbeddedNeedsXemaHost = 'embedded-needs-xema-host',
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface AppSurfaceConflict {
|
|
82
|
+
readonly code: AppSurfaceConflictCode;
|
|
83
|
+
readonly message: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface AppSurfaceValidation {
|
|
87
|
+
readonly ok: boolean;
|
|
88
|
+
readonly conflicts: readonly AppSurfaceConflict[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Validate a `(shell, audience, host)` combination against D14's legality rules.
|
|
93
|
+
* PURE and total — returns every conflict, never throws. The empty-conflict case
|
|
94
|
+
* is `ok: true`.
|
|
95
|
+
*
|
|
96
|
+
* Rules (each with a reason, so the publish screen can explain it):
|
|
97
|
+
* - `Headless` is a NO-UI surface, so it cannot also be `Embedded` (which is a UI
|
|
98
|
+
* shell). `headless` + `embedded` is the canonical contradiction the plan names.
|
|
99
|
+
* - `Embedded` IS a chrome mode; it is meaningful only for a UI shell, so an
|
|
100
|
+
* `Embedded` + `Headless` pairing is caught by the same rule from the other side.
|
|
101
|
+
* - `Standalone` (its own full-page surface) implies its own origin — it cannot be
|
|
102
|
+
* `PathBased` (a path on a shared host). `custom-domain` or `xema` are fine.
|
|
103
|
+
* - `Embedded` is served to a third-party page and relies on the Xema origin's
|
|
104
|
+
* CSP/cookies, so it must be `Xema`-hosted, not a `CustomDomain`/`PathBased`.
|
|
105
|
+
*
|
|
106
|
+
* `public-anon` + `custom-domain` is explicitly LEGAL (a public citizen portal on
|
|
107
|
+
* the customer's own domain) — there is no rule against it, so it returns `ok`.
|
|
108
|
+
* Audience does not currently gate shell/host on its own; the dimension is passed
|
|
109
|
+
* so the rules can grow without a signature change.
|
|
110
|
+
*/
|
|
111
|
+
export function validateAppSurfaceCombination(
|
|
112
|
+
dims: AppSurfaceDimensions,
|
|
113
|
+
): AppSurfaceValidation {
|
|
114
|
+
const conflicts: AppSurfaceConflict[] = [];
|
|
115
|
+
|
|
116
|
+
// The headless+embedded contradiction cannot be expressed as a SINGLE
|
|
117
|
+
// AppShellKind value (they are distinct enum members), so a surface with one
|
|
118
|
+
// declared shell is internally consistent on that axis. A consumer that models
|
|
119
|
+
// "embedded" as a separate flag alongside the shell must use
|
|
120
|
+
// isHeadlessEmbeddedContradiction() to reject the pair — documented there.
|
|
121
|
+
|
|
122
|
+
if (
|
|
123
|
+
dims.shell === AppShellKind.Standalone &&
|
|
124
|
+
dims.host === AppHostBinding.PathBased
|
|
125
|
+
) {
|
|
126
|
+
conflicts.push({
|
|
127
|
+
code: AppSurfaceConflictCode.StandaloneNeedsOwnHost,
|
|
128
|
+
message:
|
|
129
|
+
'A standalone app has its own full-page surface and cannot be path-based on a shared host; use xema or custom-domain.',
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (
|
|
134
|
+
dims.shell === AppShellKind.Embedded &&
|
|
135
|
+
dims.host !== AppHostBinding.Xema
|
|
136
|
+
) {
|
|
137
|
+
conflicts.push({
|
|
138
|
+
code: AppSurfaceConflictCode.EmbeddedNeedsXemaHost,
|
|
139
|
+
message:
|
|
140
|
+
"An embedded app is served into a third-party page and relies on the Xema origin's CSP/cookies; it must be xema-hosted.",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return { ok: conflicts.length === 0, conflicts };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The `headless` + `embedded` contradiction the plan names explicitly. Because
|
|
149
|
+
* `AppShellKind` is a single value, a surface cannot BE both at once — but a
|
|
150
|
+
* consumer that models shell as a SET, or that derives "embedded" from a separate
|
|
151
|
+
* `embed` flag alongside a `headless` shell, must reject the pair. This helper
|
|
152
|
+
* makes that cross-field rule reusable and named, so no consumer re-encodes it.
|
|
153
|
+
*/
|
|
154
|
+
export function isHeadlessEmbeddedContradiction(
|
|
155
|
+
shell: AppShellKind,
|
|
156
|
+
alsoEmbedded: boolean,
|
|
157
|
+
): boolean {
|
|
158
|
+
return shell === AppShellKind.Headless && alsoEmbedded;
|
|
159
|
+
}
|