@ethisyscore/protocol 0.7.0-alpha.3

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/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @ethisyscore/protocol
2
+
3
+ Canonical TypeScript protocol types for the EthisysCore plugin ecosystem.
4
+
5
+ This package is the TypeScript companion to the .NET `EthisysCore.Protocol` NuGet package. It exposes the same wire-level contracts so that the host app, App Bridge, and any future TypeScript clients consume identical types.
6
+
7
+ ## Scope (1.0.0)
8
+
9
+ This release lands the foundation layer for the capability-first plugin runtime:
10
+
11
+ - **Plugin manifest** — `PluginManifest`, `RenderMode`, and the optional `PluginUi` sub-shape (`src/manifest.ts`).
12
+ - **SDUI primitive vocabulary v1** — `KNOWN_PRIMITIVES`, recursive `SduiNode` schema (`src/sdui/primitives.ts`).
13
+ - **JsonLogic operator subset + reactive rule kinds** — `KNOWN_OPERATORS`, `KNOWN_RULE_KINDS`, `ReactiveRule` (`src/sdui/operators.ts`).
14
+ - **Portal contributions + host slot taxonomy** — `PortalContribution`, `KNOWN_SLOTS`, `HostSlot` (`src/sdui/portal.ts`).
15
+ - **Theme tokens** — design-token shape consumed by the host renderer (`src/theme/tokens.ts`).
16
+ - **Capability claims** — permission and capability-token types (`src/capability/permissions.ts`, `src/capability/token.ts`).
17
+ - **Bridge version constant** — `BRIDGE_VERSION` (`src/bridge/version.ts`).
18
+
19
+ Future contracts (reference-data, DataStore, MCP, events, logging, notifications, transport, packaging, host-callback) are not yet in this package — they will be added additively as the consuming clients land.
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ npm install @ethisyscore/protocol
25
+ ```
26
+
27
+ ## Scripts
28
+
29
+ ```bash
30
+ npm run build # bundle ESM + CJS + d.ts via tsup
31
+ npm test # run vitest in CI mode
32
+ npm run test:watch # vitest in watch mode
33
+ npm run lint # tsc --noEmit type check
34
+ ```
35
+
36
+ ## Layout
37
+
38
+ - `src/index.ts` — public barrel
39
+ - `src/manifest.ts` — plugin manifest + render mode
40
+ - `src/sdui/` — SDUI primitives, operators, portal contributions
41
+ - `src/theme/` — design tokens
42
+ - `src/capability/` — permissions and capability-token claims
43
+ - `src/bridge/` — bridge version constant
44
+ - `src/__tests__/` — vitest tests
45
+ - `dist/` — build output (gitignored)
46
+
47
+ ## Compatibility
48
+
49
+ Treat this package as a public compatibility boundary. Prefer additive changes; do not repurpose enum values; do not make breaking JSON shape changes without a coordinated release.
50
+
51
+ The vocabulary surfaces (SDUI primitives, JsonLogic operators, reactive rule kinds, host slot taxonomy) are gated by the RFC process documented in [`docs/rfcs/README.md`](../../../docs/rfcs/README.md). CI auto-rejects PRs that expand the vocabulary without an accepted RFC.
package/dist/index.cjs ADDED
@@ -0,0 +1,265 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+
5
+ // src/bridge/version.ts
6
+ var BRIDGE_VERSION = "2026-06";
7
+ var KNOWN_SLOTS = [
8
+ "sidebar",
9
+ "header",
10
+ "dashboard",
11
+ "command-palette",
12
+ "entity-detail"
13
+ ];
14
+ var HostSlot = zod.z.enum(KNOWN_SLOTS);
15
+ var PortalContribution = zod.z.object({
16
+ slot: HostSlot,
17
+ capability: zod.z.string().min(1).refine((s) => s.trim().length > 0, {
18
+ message: "capability must not be blank or whitespace-only"
19
+ }),
20
+ priority: zod.z.number().int().min(0).max(1e3)
21
+ });
22
+
23
+ // src/manifest.ts
24
+ var SEMVER_WILDCARD = "\\*|\\d+\\.[xX*](?:\\.[xX*])?|\\d+\\.\\d+\\.[xX*]";
25
+ var SEMVER_CORE = "\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?";
26
+ var SEMVER_COMPARATOR = `(?:[<>]=?|=|~|\\^)?(?:${SEMVER_CORE}|${SEMVER_WILDCARD})`;
27
+ var SEMVER_HYPHEN_RANGE = `${SEMVER_CORE}\\s+-\\s+${SEMVER_CORE}`;
28
+ var SEMVER_AND = `(?:${SEMVER_HYPHEN_RANGE}|${SEMVER_COMPARATOR})(?:\\s+(?:${SEMVER_HYPHEN_RANGE}|${SEMVER_COMPARATOR}))*`;
29
+ var SEMVER_RANGE_REGEX = new RegExp(`^${SEMVER_AND}(?:\\s*\\|\\|\\s*${SEMVER_AND})*$`);
30
+ var compatibleCoreVersionSchema = zod.z.string().min(1).refine((value) => SEMVER_RANGE_REGEX.test(value), {
31
+ message: 'compatibleCoreVersion must be a semver-range expression (e.g. "1.2.3", ">=1.0.0", "^1.2.0", "1.2.3 - 2.0.0").'
32
+ });
33
+ var RenderMode = zod.z.enum([
34
+ "host-rendered",
35
+ "remote-runtime",
36
+ "first-party-host-extension"
37
+ ]);
38
+ var PluginType = zod.z.enum(["CORE", "PLATFORM_APP", "TENANT_APP"]);
39
+ var PluginUi = zod.z.object({
40
+ /**
41
+ * Plugin contributions to well-known host UI slots. Optional: omitting the field leaves
42
+ * it `undefined`, matching the C# `UiContributions.PortalContributions` null encoding.
43
+ */
44
+ portalContributions: zod.z.array(PortalContribution).optional()
45
+ }).passthrough();
46
+ var PluginManifest = zod.z.object({
47
+ id: zod.z.string().uuid(),
48
+ name: zod.z.string().min(1),
49
+ version: zod.z.string().min(1),
50
+ type: PluginType,
51
+ owner: zod.z.string().min(1),
52
+ compatibleCoreVersion: compatibleCoreVersionSchema,
53
+ renderMode: RenderMode.default("host-rendered"),
54
+ bridgeVersion: zod.z.string().min(1).optional(),
55
+ ui: PluginUi.optional()
56
+ }).passthrough();
57
+ var KNOWN_RULE_KINDS = ["when", "visible", "required", "compute", "validate"];
58
+ var KNOWN_OPERATORS = [
59
+ "==",
60
+ "!=",
61
+ ">",
62
+ "<",
63
+ ">=",
64
+ "<=",
65
+ "and",
66
+ "or",
67
+ "not",
68
+ "+",
69
+ "-",
70
+ "*",
71
+ "/",
72
+ "%",
73
+ "var"
74
+ ];
75
+ var RuleKind = zod.z.enum(KNOWN_RULE_KINDS);
76
+ var LiteralValueSchema = zod.z.union([
77
+ zod.z.string(),
78
+ // `.finite()` rejects `Infinity`, `-Infinity`, and `NaN`. The wire format is JSON, where
79
+ // those numeric "values" serialise to `null` and would silently change semantics between
80
+ // tooling validation and host evaluation. Constraining the schema here keeps the
81
+ // expression vocabulary JSON-finite end-to-end.
82
+ zod.z.number().finite(),
83
+ zod.z.boolean(),
84
+ zod.z.null()
85
+ ]);
86
+ var Expr = zod.z.lazy(() => zod.z.union([
87
+ LiteralValueSchema,
88
+ zod.z.array(Expr),
89
+ zod.z.record(zod.z.string(), Expr).refine((obj) => {
90
+ const keys = Object.keys(obj);
91
+ if (keys.length !== 1) {
92
+ return false;
93
+ }
94
+ return KNOWN_OPERATORS.includes(keys[0]);
95
+ }, { message: "expression must have exactly one known operator key" })
96
+ ]));
97
+ var ReactiveRule = zod.z.object({
98
+ kind: RuleKind,
99
+ expr: Expr
100
+ });
101
+ var KNOWN_PRIMITIVES = [
102
+ "Page",
103
+ "Section",
104
+ "Stack",
105
+ "Grid",
106
+ "Form",
107
+ "Field",
108
+ "DataTable",
109
+ "Card",
110
+ "Stat",
111
+ "Action",
112
+ "Tabs",
113
+ "Toolbar",
114
+ "Filter",
115
+ "EmptyState",
116
+ "LoadingState",
117
+ "ErrorState",
118
+ "Portal"
119
+ ];
120
+ var PrimitiveName = zod.z.enum(KNOWN_PRIMITIVES);
121
+ var SduiNode = zod.z.lazy(
122
+ () => zod.z.object({
123
+ type: PrimitiveName,
124
+ props: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
125
+ children: zod.z.array(SduiNode).optional(),
126
+ bindings: zod.z.record(zod.z.string(), ReactiveRule).optional()
127
+ })
128
+ );
129
+ var TokenCategory = zod.z.record(zod.z.string(), zod.z.string()).default({});
130
+ var BridgeThemeTokens = zod.z.object({
131
+ // ── Core (8) ──────
132
+ brand: TokenCategory,
133
+ background: TokenCategory,
134
+ text: TokenCategory,
135
+ status: TokenCategory,
136
+ border: TokenCategory,
137
+ radius: TokenCategory,
138
+ spacing: TokenCategory,
139
+ typography: TokenCategory,
140
+ // ── Extended (6) ──────
141
+ focus: TokenCategory,
142
+ interaction: TokenCategory,
143
+ overlay: TokenCategory,
144
+ divider: TokenCategory,
145
+ shadow: TokenCategory,
146
+ input: TokenCategory
147
+ });
148
+ var BridgeThemeMode = zod.z.enum(["light", "dark"]);
149
+ var BridgeThemeAccessibility = zod.z.object({
150
+ highContrast: zod.z.boolean(),
151
+ reducedMotion: zod.z.boolean()
152
+ });
153
+ var BridgeTheme = zod.z.object({
154
+ tokenVersion: zod.z.string().min(1),
155
+ mode: BridgeThemeMode,
156
+ accessibility: BridgeThemeAccessibility,
157
+ tokens: BridgeThemeTokens
158
+ });
159
+ var ToolPermission = {
160
+ /** No permissions required. */
161
+ None: 0,
162
+ /** Permission to assign resources or roles. */
163
+ Assign: 1 << 0,
164
+ /** Permission to view resources in a summary or listing context. */
165
+ View: 1 << 1,
166
+ /** Permission to delete resources. */
167
+ Delete: 1 << 2,
168
+ /** Permission to create or modify resources. Default for tools. */
169
+ Write: 1 << 3,
170
+ /** Permission to read detailed resource content. */
171
+ Read: 1 << 4,
172
+ /** Permission to approve workflows or submissions. */
173
+ Approve: 1 << 5,
174
+ /** Permission to publish resources globally across tenants. */
175
+ PublishGlobal: 1 << 6,
176
+ /** Composite: `View | Read` (18). */
177
+ ReaderAccess: 1 << 1 | 1 << 4,
178
+ /** Composite: `View | Write | Read` (26). */
179
+ ContributorAccess: 1 << 1 | 1 << 3 | 1 << 4,
180
+ /** Composite: all atomic permissions combined (127). */
181
+ OwnerAccess: 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6
182
+ };
183
+ function hasPermission(set, required) {
184
+ return (set & required) === required;
185
+ }
186
+ var ToolPermissionFlags = zod.z.number().int().min(0).max(2147483647);
187
+ var CapabilityTokenAudience = zod.z.literal("coreconnect-mcp");
188
+ var CapabilityTokenSurfaceKind = zod.z.enum([
189
+ "page",
190
+ "dialog",
191
+ "panel",
192
+ "portal"
193
+ ]);
194
+ var CapabilityTokenRuntimeImplementation = zod.z.enum([
195
+ "host-rendered",
196
+ "worker-remote-dom",
197
+ "first-party-host-extension"
198
+ ]);
199
+ var CapabilityTokenClaims = zod.z.object({
200
+ /** JWT issuer (`iss`) — the Api endpoint that minted the token. */
201
+ iss: zod.z.string().min(1),
202
+ /** JWT subject (`sub`) — typically the acting user principal. */
203
+ sub: zod.z.string().min(1),
204
+ /** JWT audience (`aud`) — pinned to the MCP boundary. */
205
+ aud: CapabilityTokenAudience,
206
+ /** JWT issued-at (`iat`) — Unix seconds, non-negative. */
207
+ iat: zod.z.number().int().nonnegative(),
208
+ /** JWT expiry (`exp`) — Unix seconds, non-negative. */
209
+ exp: zod.z.number().int().nonnegative(),
210
+ /** Organisation the surface is scoped to. */
211
+ org_id: zod.z.string().uuid(),
212
+ /** Tenant the surface is scoped to within the organisation. */
213
+ tenant_id: zod.z.string().uuid(),
214
+ /** Acting user principal. */
215
+ user_id: zod.z.string().uuid(),
216
+ /** Identifier of the extension that owns the surface. */
217
+ extension_id: zod.z.string().uuid(),
218
+ /** Specific version of the extension currently rendered. */
219
+ extension_version: zod.z.string().min(1),
220
+ /** Stable identifier of the surface instance (per open dialog/page). */
221
+ surface_instance_id: zod.z.string().uuid(),
222
+ /** Taxonomic kind of the surface this token is bound to. */
223
+ surface_kind: CapabilityTokenSurfaceKind,
224
+ /** Runtime implementation rendering the surface. */
225
+ runtime_implementation: CapabilityTokenRuntimeImplementation,
226
+ /** JWT identifier (`jti`) — unique per token, supports replay detection. */
227
+ jti: zod.z.string().min(1)
228
+ }).refine((claims) => claims.exp > claims.iat, {
229
+ message: "exp must be strictly greater than iat",
230
+ path: ["exp"]
231
+ });
232
+
233
+ // src/index.ts
234
+ var PROTOCOL_PACKAGE = "@ethisyscore/protocol";
235
+
236
+ exports.BRIDGE_VERSION = BRIDGE_VERSION;
237
+ exports.BridgeTheme = BridgeTheme;
238
+ exports.BridgeThemeAccessibility = BridgeThemeAccessibility;
239
+ exports.BridgeThemeMode = BridgeThemeMode;
240
+ exports.BridgeThemeTokens = BridgeThemeTokens;
241
+ exports.CapabilityTokenAudience = CapabilityTokenAudience;
242
+ exports.CapabilityTokenClaims = CapabilityTokenClaims;
243
+ exports.CapabilityTokenRuntimeImplementation = CapabilityTokenRuntimeImplementation;
244
+ exports.CapabilityTokenSurfaceKind = CapabilityTokenSurfaceKind;
245
+ exports.HostSlot = HostSlot;
246
+ exports.KNOWN_OPERATORS = KNOWN_OPERATORS;
247
+ exports.KNOWN_PRIMITIVES = KNOWN_PRIMITIVES;
248
+ exports.KNOWN_RULE_KINDS = KNOWN_RULE_KINDS;
249
+ exports.KNOWN_SLOTS = KNOWN_SLOTS;
250
+ exports.PROTOCOL_PACKAGE = PROTOCOL_PACKAGE;
251
+ exports.PluginManifest = PluginManifest;
252
+ exports.PluginType = PluginType;
253
+ exports.PluginUi = PluginUi;
254
+ exports.PortalContribution = PortalContribution;
255
+ exports.PrimitiveName = PrimitiveName;
256
+ exports.ReactiveRule = ReactiveRule;
257
+ exports.RenderMode = RenderMode;
258
+ exports.RuleKind = RuleKind;
259
+ exports.SduiNode = SduiNode;
260
+ exports.TokenCategory = TokenCategory;
261
+ exports.ToolPermission = ToolPermission;
262
+ exports.ToolPermissionFlags = ToolPermissionFlags;
263
+ exports.hasPermission = hasPermission;
264
+ //# sourceMappingURL=index.cjs.map
265
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bridge/version.ts","../src/sdui/portal.ts","../src/manifest.ts","../src/sdui/operators.ts","../src/sdui/primitives.ts","../src/sdui/node.ts","../src/theme/tokens.ts","../src/capability/permissions.ts","../src/capability/token.ts","../src/index.ts"],"names":["z"],"mappings":"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","file":"index.cjs","sourcesContent":["export const BRIDGE_VERSION = \"2026-06\" as const;\nexport type BridgeVersion = typeof BRIDGE_VERSION;\n","import { z } from \"zod\";\n\n/**\n * The closed v1 host slot taxonomy.\n *\n * The host owns the slot taxonomy; plugins target slot names by string. Adding a new slot\n * is a coordinated host change — plugins cannot introduce slot names ad hoc.\n */\nexport const KNOWN_SLOTS = [\n \"sidebar\",\n \"header\",\n \"dashboard\",\n \"command-palette\",\n \"entity-detail\",\n] as const;\n\n/**\n * Zod schema for a host slot name. Rejects values outside the closed v1 taxonomy.\n */\nexport const HostSlot = z.enum(KNOWN_SLOTS);\nexport type HostSlot = z.infer<typeof HostSlot>;\n\n/**\n * A single plugin contribution targeting a host slot.\n *\n * - `slot`: the host slot the contribution targets (must be one of {@link KNOWN_SLOTS}).\n * - `capability`: the capability gate the viewer must hold for the host to render the contribution.\n * Must be a non-empty, non-whitespace string — whitespace-only values would render an\n * unaddressable contribution or, depending on host interpretation, an accidentally\n * unrestricted one. Wire-form parity with the C# `PortalContribution.Capability` init guard\n * and the JSON Schemas, which all reject whitespace-only strings.\n * - `priority`: arbitration weight when multiple plugins target the same slot. Higher wins.\n * Range `0..1000` inclusive to keep the priority space bounded and reviewable.\n */\nexport const PortalContribution = z.object({\n slot: HostSlot,\n capability: z\n .string()\n .min(1)\n .refine((s) => s.trim().length > 0, {\n message: \"capability must not be blank or whitespace-only\",\n }),\n priority: z.number().int().min(0).max(1000),\n});\nexport type PortalContribution = z.infer<typeof PortalContribution>;\n","import { z } from \"zod\";\nimport { PortalContribution } from \"./sdui/portal\";\n\n/**\n * Pragmatic validator for the semver-range expression vocabulary the C# manifest accepts on\n * `CompatibleCoreVersion`. The full npm `semver` grammar is intentionally not implemented —\n * dragging the runtime dep into a protocol package is heavier than the validation is worth.\n *\n * We accept the operator subset the rest of the platform actually emits:\n * - bare versions: `1.2.3`, `1.0.0-alpha.1`, `1.2.3+build.7`\n * - comparator-prefixed: `>=1.2.0`, `<2.0.0`, `=1.2.3`, `~1.2.3`, `^1.2.3`\n * - wildcard placeholders: `*` (any), `1.x`, `1.X`, `1.2.x`, `1.2.*` (npm semver-range\n * placeholders that mean \"any major\", \"any minor\", or \"any patch\")\n * - hyphen ranges: `1.2.3 - 2.0.0`\n * - logical-AND of the above (space-separated), and logical-OR via `||`.\n *\n * Wildcards are admitted because the C# `CompatibleCoreVersion` field is an unvalidated\n * `string` (the C# layer is the most permissive of the three) and the JSON Schemas place no\n * pattern restriction on the field. Rejecting `1.x` on the TS side alone would make the TS\n * package the only layer that disagrees with the wire form .NET admits — exactly the kind of\n * three-layer divergence this validator exists to prevent.\n *\n * The grammar still rejects obviously-malformed input (e.g. `\"latest\"`, `\"^\"`, empty string,\n * `\"1\"`, `\"1.0\"`) so common authoring typos fail loudly before reaching the wire. Full\n * semantic validation (e.g. \"does this range actually intersect the host version?\") is the\n * host's job at install time.\n */\n// Wildcard core: the bare star `*` or a partial version with x/X/* placeholders at any\n// position from the major segment onwards (`1.x`, `1.X.x`, `1.2.*`, etc.). A partial version\n// uses concrete digits up to some position and an x-style placeholder thereafter.\nconst SEMVER_WILDCARD = \"\\\\*|\\\\d+\\\\.[xX*](?:\\\\.[xX*])?|\\\\d+\\\\.\\\\d+\\\\.[xX*]\";\nconst SEMVER_CORE = \"\\\\d+\\\\.\\\\d+\\\\.\\\\d+(?:-[0-9A-Za-z.-]+)?(?:\\\\+[0-9A-Za-z.-]+)?\";\n// A comparator may prefix either a full version core or a wildcard partial — `>=1.x` is\n// legitimate npm semver-range syntax meaning \"any version at or above 1.0.0\".\nconst SEMVER_COMPARATOR = `(?:[<>]=?|=|~|\\\\^)?(?:${SEMVER_CORE}|${SEMVER_WILDCARD})`;\nconst SEMVER_HYPHEN_RANGE = `${SEMVER_CORE}\\\\s+-\\\\s+${SEMVER_CORE}`;\nconst SEMVER_AND = `(?:${SEMVER_HYPHEN_RANGE}|${SEMVER_COMPARATOR})(?:\\\\s+(?:${SEMVER_HYPHEN_RANGE}|${SEMVER_COMPARATOR}))*`;\nconst SEMVER_RANGE_REGEX = new RegExp(`^${SEMVER_AND}(?:\\\\s*\\\\|\\\\|\\\\s*${SEMVER_AND})*$`);\n\n/**\n * Zod refinement: validates a semver-range expression on the npm-compatible operator subset\n * accepted by the .NET `CompatibleCoreVersion` field. Trailing/leading whitespace is rejected\n * so the canonical wire form is stable.\n */\nconst compatibleCoreVersionSchema = z\n .string()\n .min(1)\n .refine((value) => SEMVER_RANGE_REGEX.test(value), {\n message:\n \"compatibleCoreVersion must be a semver-range expression (e.g. \\\"1.2.3\\\", \\\">=1.0.0\\\", \\\"^1.2.0\\\", \\\"1.2.3 - 2.0.0\\\").\",\n });\n\n/**\n * How a plugin's UI is rendered to the end user.\n *\n * - `host-rendered`: the host application renders the plugin UI from a declarative description.\n * - `remote-runtime`: the plugin ships its own runtime that the host loads into an isolation boundary.\n * - `first-party-host-extension`: the plugin is bundled with the host as a first-party extension\n * sharing the host's runtime.\n */\nexport const RenderMode = z.enum([\n \"host-rendered\",\n \"remote-runtime\",\n \"first-party-host-extension\",\n]);\nexport type RenderMode = z.infer<typeof RenderMode>;\n\n/**\n * Plugin classification enum — wire values mirror the C# `JsonStringEnumMemberName`\n * tokens on `PluginType` (`CORE`, `PLATFORM_APP`, `TENANT_APP`), so the TypeScript schema\n * round-trips through the .NET serialiser and through the JSON Schema enum gates.\n *\n * Earlier revisions accepted the C# member names (`Core`, `PlatformPlugin`, `TenantPlugin`),\n * which silently disagreed with the wire format. Exported as a dedicated Zod enum so\n * downstream consumers can validate `type` independently of the full manifest.\n */\nexport const PluginType = z.enum([\"CORE\", \"PLATFORM_APP\", \"TENANT_APP\"]);\nexport type PluginType = z.infer<typeof PluginType>;\n\n/**\n * UI sub-shape of the plugin manifest.\n *\n * Mirrors a strict subset of the C# `UiContributions` record. Only the fields the TS contract\n * currently consumes are modelled here — future tasks extend this schema additively as new\n * fields (pages, surfaces, navigation, etc.) come in.\n *\n * Wire-shape parity: every member is optional, matching the C# `UiContributions` record\n * where each sibling (`MenuItems`, `Pages`, `Surfaces`, `PortalContributions`, ...) is\n * nullable / property-omitted. Omitting `portalContributions` leaves it `undefined` on\n * parse — the consumer is responsible for treating undefined as \"no contributions\".\n *\n * The schema is `.passthrough()` so unrecognised UI sibling fields (e.g. `pages`,\n * `surfaces`, `declarativeSurfaces`, `workerPages`, `navigation`) survive parse → re-emit\n * unchanged instead of being silently stripped. The documented permissive intent\n * (additive evolution of UI contributions) requires this — Zod object schemas strip\n * unknown keys by default.\n */\nexport const PluginUi = z\n .object({\n /**\n * Plugin contributions to well-known host UI slots. Optional: omitting the field leaves\n * it `undefined`, matching the C# `UiContributions.PortalContributions` null encoding.\n */\n portalContributions: z.array(PortalContribution).optional(),\n })\n .passthrough();\nexport type PluginUi = z.infer<typeof PluginUi>;\n\n/**\n * Canonical plugin manifest contract. Mirrors the C# `PluginManifest` record on the .NET side.\n *\n * The schema is intentionally permissive about additional fields the host hasn't been taught\n * yet — `.passthrough()` keeps unknown root fields on the parsed object so a manifest\n * round-trip (parse → re-emit) does not silently drop fields the C# / JSON Schema layers\n * still recognise. Use a future `.strict()` variant for trust-boundary ingest where unknown\n * keys must be rejected.\n */\nexport const PluginManifest = z\n .object({\n id: z.string().uuid(),\n name: z.string().min(1),\n version: z.string().min(1),\n type: PluginType,\n owner: z.string().min(1),\n compatibleCoreVersion: compatibleCoreVersionSchema,\n renderMode: RenderMode.default(\"host-rendered\"),\n bridgeVersion: z.string().min(1).optional(),\n ui: PluginUi.optional(),\n })\n .passthrough();\nexport type PluginManifest = z.infer<typeof PluginManifest>;\n","import { z } from \"zod\";\n\n/**\n * The closed set of reactive rule kinds supported by the SDUI runtime.\n *\n * Plugins declare reactivity via these five kinds; the host owns evaluation order\n * and side-effect semantics. Adding a new kind is a coordinated host change.\n */\nexport const KNOWN_RULE_KINDS = [\"when\", \"visible\", \"required\", \"compute\", \"validate\"] as const;\n\n/**\n * The closed JsonLogic operator subset permitted in reactive rule expressions.\n *\n * The vocabulary is intentionally minimal: comparison, boolean, arithmetic, and `var`.\n * No custom operators, no async, no loops, no mutation. Adding an operator is a\n * coordinated protocol change — plugins cannot extend the vocabulary ad hoc.\n */\nexport const KNOWN_OPERATORS = [\n \"==\", \"!=\", \">\", \"<\", \">=\", \"<=\",\n \"and\", \"or\", \"not\",\n \"+\", \"-\", \"*\", \"/\", \"%\",\n \"var\",\n] as const;\n\n/**\n * Zod schema for a reactive rule kind. Rejects values outside {@link KNOWN_RULE_KINDS}.\n */\nexport const RuleKind = z.enum(KNOWN_RULE_KINDS);\nexport type RuleKind = z.infer<typeof RuleKind>;\n\n/**\n * Literal scalar values permitted inside a reactive expression tree.\n *\n * Functions, `undefined`, and arbitrary objects are intentionally rejected to keep\n * the expression vocabulary serialisable and free of host-side side effects.\n */\nexport type LiteralValue = string | number | boolean | null;\n\nconst LiteralValueSchema: z.ZodType<LiteralValue> = z.union([\n z.string(),\n // `.finite()` rejects `Infinity`, `-Infinity`, and `NaN`. The wire format is JSON, where\n // those numeric \"values\" serialise to `null` and would silently change semantics between\n // tooling validation and host evaluation. Constraining the schema here keeps the\n // expression vocabulary JSON-finite end-to-end.\n z.number().finite(),\n z.boolean(),\n z.null(),\n]);\n\n/**\n * Operator name from the closed JsonLogic subset {@link KNOWN_OPERATORS}.\n */\nexport type OperatorName = (typeof KNOWN_OPERATORS)[number];\n\n/**\n * An operator-object form for {@link Expr} — a single-key record whose key is one of the\n * closed {@link KNOWN_OPERATORS} and whose value is itself an {@link Expr}.\n *\n * The mapped-then-indexed shape `{ [K in OperatorName]: Record<K, Expr> }[OperatorName]`\n * collapses to the discriminated union\n * `{ \"==\": Expr } | { \"!=\": Expr } | ... | { var: Expr }`. Unlike the earlier optional-key\n * form (`{ [K in OperatorName]?: Expr }`), this:\n *\n * - rejects the empty object literal `{}` at compile time;\n * - rejects multi-key objects like `{ \"==\": a, \"!=\": b }` at compile time;\n * - matches the runtime schema, which requires exactly one known operator key.\n *\n * Authors and tooling no longer have to wait for a Zod parse failure to discover an\n * impossible-on-the-wire expression — the TypeScript compiler rejects it first.\n *\n * Modelled as an interface so the recursive `Expr` reference is resolved lazily; a plain\n * `type` alias with an indexed mapped type triggers TS2456 (circular reference) under\n * tsup's `--dts` build.\n */\nexport interface ExprObject extends Partial<Record<OperatorName, Expr>> {}\n\n/**\n * A JsonLogic expression in the closed operator subset.\n *\n * An expression is one of:\n * - a {@link LiteralValue} (`string | number | boolean | null`)\n * - an array of expressions (operand list)\n * - an {@link ExprObject} (single-key object whose key is from {@link KNOWN_OPERATORS})\n *\n * The discriminated form lets consumers narrow on `typeof expr` / `Array.isArray` / object\n * key inspection without resorting to `unknown` casts.\n *\n * Runtime validation (the `Expr` Zod schema below) is the authoritative check that the\n * object carries exactly one known operator key. The TypeScript type narrows the *kind* of\n * value an author may construct (it rules out arbitrary string keys); the schema enforces\n * the single-key invariant on the wire.\n */\nexport type Expr =\n | LiteralValue\n | Expr[]\n | ExprObject;\n\n/**\n * Recursive Zod schema for {@link Expr}. The runtime validation matches the type:\n * a literal, an array of expressions, or a single-key object whose key is a known operator.\n *\n * The recursive structure guarantees that function-typed inputs and unknown operators\n * are rejected anywhere in the tree, not just at the root.\n */\nconst Expr: z.ZodType<Expr> = z.lazy(() => z.union([\n LiteralValueSchema,\n z.array(Expr),\n z.record(z.string(), Expr).refine((obj) => {\n const keys = Object.keys(obj);\n if (keys.length !== 1)\n {\n return false;\n }\n return (KNOWN_OPERATORS as readonly string[]).includes(keys[0]);\n }, { message: \"expression must have exactly one known operator key\" }),\n]));\n\n/**\n * Zod schema for a single reactive rule: a {@link RuleKind} paired with an expression\n * built from the closed JsonLogic operator subset.\n */\nexport const ReactiveRule = z.object({\n kind: RuleKind,\n expr: Expr,\n});\nexport type ReactiveRule = z.infer<typeof ReactiveRule>;\n","import { z } from \"zod\";\n\n/**\n * The closed v1 SDUI primitive vocabulary.\n *\n * Plugins author UI trees using only these primitive names; the host owns the rendering\n * for each. Adding a new primitive is a coordinated host change — plugins cannot extend\n * the vocabulary ad hoc. Deferred-vocabulary names (`Wizard`, `Timeline`, `Chart`,\n * `EntityPicker`, `Detail`) are intentionally absent from v1 and are rejected by the\n * {@link PrimitiveName} schema.\n *\n * `Portal` is the 17th primitive: it lets a plugin contribute a subtree into a host slot\n * (see `./portal.ts` for the v1 slot taxonomy).\n */\nexport const KNOWN_PRIMITIVES = [\n \"Page\", \"Section\", \"Stack\", \"Grid\", \"Form\", \"Field\",\n \"DataTable\", \"Card\", \"Stat\", \"Action\", \"Tabs\", \"Toolbar\",\n \"Filter\", \"EmptyState\", \"LoadingState\", \"ErrorState\", \"Portal\",\n] as const;\n\n/**\n * Zod schema for a SDUI primitive name. Rejects values outside the closed v1 vocabulary.\n */\nexport const PrimitiveName = z.enum(KNOWN_PRIMITIVES);\nexport type PrimitiveName = z.infer<typeof PrimitiveName>;\n","import { z } from \"zod\";\nimport { PrimitiveName } from \"./primitives\";\nimport { ReactiveRule } from \"./operators\";\n\n/**\n * A SDUI tree node.\n *\n * - `type`: one of the closed v1 primitive names (see {@link PrimitiveName}).\n * - `props`: arbitrary per-primitive properties; the host owns interpretation.\n * - `children`: optional child nodes; recursion is type-checked end-to-end.\n * - `bindings`: optional reactive rules keyed by prop name (see {@link ReactiveRule}).\n *\n * The type alias and the Zod schema deliberately share the identifier `SduiNode` —\n * TypeScript's declaration-merging rules allow a `type` and a `const` of the same name\n * to coexist. The recursive schema is built with {@link z.lazy} so unknown primitives\n * are rejected at any depth of the tree.\n */\nexport type SduiNode = {\n type: z.infer<typeof PrimitiveName>;\n props?: Record<string, unknown>;\n children?: SduiNode[];\n bindings?: Record<string, z.infer<typeof ReactiveRule>>;\n};\n\n/**\n * Recursive Zod schema for {@link SduiNode}.\n *\n * Validates the full tree: an unknown primitive at any depth fails the parse. `props`\n * and `bindings` are permissive on the value side (props: `unknown`, bindings: a\n * {@link ReactiveRule}) — the host owns prop semantics per primitive.\n */\nexport const SduiNode: z.ZodType<SduiNode> = z.lazy(() =>\n z.object({\n type: PrimitiveName,\n props: z.record(z.string(), z.unknown()).optional(),\n children: z.array(SduiNode).optional(),\n bindings: z.record(z.string(), ReactiveRule).optional(),\n }),\n);\n","import { z } from \"zod\";\n\n/**\n * A single design-token category: a map of token name -> CSS value.\n *\n * The host owns the exact set of token names per category. At the protocol level we only\n * enforce that values are strings; the schema deliberately admits an empty category so\n * plugins can omit any category they do not care about.\n */\nexport const TokenCategory = z.record(z.string(), z.string()).default({});\nexport type TokenCategory = z.infer<typeof TokenCategory>;\n\n/**\n * The full token tree exchanged between host and plugin.\n *\n * Eight core categories carry the surface-level design language; six extended categories\n * supply interaction-specific tokens (focus rings, overlays, dividers, shadows, inputs).\n *\n * Each category defaults to an empty record, mirroring the host-side `BridgeThemeTokens`\n * shape in `sdk/app-bridge`.\n */\nexport const BridgeThemeTokens = z.object({\n // ── Core (8) ──────\n brand: TokenCategory,\n background: TokenCategory,\n text: TokenCategory,\n status: TokenCategory,\n border: TokenCategory,\n radius: TokenCategory,\n spacing: TokenCategory,\n typography: TokenCategory,\n // ── Extended (6) ──────\n focus: TokenCategory,\n interaction: TokenCategory,\n overlay: TokenCategory,\n divider: TokenCategory,\n shadow: TokenCategory,\n input: TokenCategory,\n});\nexport type BridgeThemeTokens = z.infer<typeof BridgeThemeTokens>;\n\n/**\n * Color scheme reported by the host. The plugin must subscribe to `onThemeChange`; the\n * user can toggle modes at runtime without a route change.\n */\nexport const BridgeThemeMode = z.enum([\"light\", \"dark\"]);\nexport type BridgeThemeMode = z.infer<typeof BridgeThemeMode>;\n\n/**\n * Accessibility signals piggy-backed on the theme payload.\n *\n * - `highContrast`: viewer has enabled the OS-level high-contrast preference.\n * - `reducedMotion`: viewer has enabled the OS-level reduced-motion preference. Animation\n * tokens should be disabled or shortened when this is `true`.\n */\nexport const BridgeThemeAccessibility = z.object({\n highContrast: z.boolean(),\n reducedMotion: z.boolean(),\n});\nexport type BridgeThemeAccessibility = z.infer<typeof BridgeThemeAccessibility>;\n\n/**\n * The full theme payload delivered to a plugin surface.\n *\n * - `tokenVersion`: semantic version of the host's token schema. Plugins compare this\n * against their `Manifest.TokenVersion` to detect incompatibilities at boot.\n * - `mode`: current color scheme.\n * - `accessibility`: viewer accessibility preferences.\n * - `tokens`: full 14-category token tree.\n */\nexport const BridgeTheme = z.object({\n tokenVersion: z.string().min(1),\n mode: BridgeThemeMode,\n accessibility: BridgeThemeAccessibility,\n tokens: BridgeThemeTokens,\n});\nexport type BridgeTheme = z.infer<typeof BridgeTheme>;\n","import { z } from \"zod\";\n\n/**\n * Tool permission flags. Bit values mirror the C# `EthisysCore.Protocol.Security.ToolPermission`\n * enum verbatim — these integers are part of the wire contract and must stay in sync.\n *\n * @remarks\n * Combine atomic flags with bitwise OR (e.g. `ToolPermission.View | ToolPermission.Read`)\n * and test membership with {@link hasPermission}. The composite values (`ReaderAccess`,\n * `ContributorAccess`, `OwnerAccess`) are convenience aliases for the most common\n * combinations.\n */\nexport const ToolPermission = {\n /** No permissions required. */\n None: 0,\n /** Permission to assign resources or roles. */\n Assign: 1 << 0,\n /** Permission to view resources in a summary or listing context. */\n View: 1 << 1,\n /** Permission to delete resources. */\n Delete: 1 << 2,\n /** Permission to create or modify resources. Default for tools. */\n Write: 1 << 3,\n /** Permission to read detailed resource content. */\n Read: 1 << 4,\n /** Permission to approve workflows or submissions. */\n Approve: 1 << 5,\n /** Permission to publish resources globally across tenants. */\n PublishGlobal: 1 << 6,\n /** Composite: `View | Read` (18). */\n ReaderAccess: (1 << 1) | (1 << 4),\n /** Composite: `View | Write | Read` (26). */\n ContributorAccess: (1 << 1) | (1 << 3) | (1 << 4),\n /** Composite: all atomic permissions combined (127). */\n OwnerAccess:\n (1 << 0) |\n (1 << 1) |\n (1 << 2) |\n (1 << 3) |\n (1 << 4) |\n (1 << 5) |\n (1 << 6),\n} as const;\nexport type ToolPermission = (typeof ToolPermission)[keyof typeof ToolPermission];\n\n/**\n * Returns `true` when `set` contains every bit in `required`.\n *\n * Semantics match the C# `HasFlag` behaviour: a required mask with multiple bits demands\n * that all of them are present in the granted set, not just any one of them.\n */\nexport function hasPermission(set: number, required: number): boolean {\n return (set & required) === required;\n}\n\n/**\n * Runtime validator for a serialized `ToolPermission` value. Accepts a non-negative\n * **signed 32-bit** integer (0..0x7FFFFFFF) because:\n *\n * 1. The C# `ToolPermission` enum's underlying type is `int` (signed 32-bit). Values\n * outside that range have no in-protocol representation.\n * 2. `hasPermission` performs `set & required` — JavaScript's bitwise `&` coerces both\n * operands to signed 32-bit, so values at or above 0x80000000 silently overflow\n * (the high bit becomes the sign bit). A schema that accepted them would let an\n * out-of-range manifest validate while `hasPermission` returned nonsense.\n *\n * Callers may still combine atomic flags into composites the protocol has not named\n * (e.g. `Write | Approve`) — any combination of the currently-defined bits fits inside\n * the 32-bit signed range with margin.\n */\nexport const ToolPermissionFlags = z.number().int().min(0).max(0x7fffffff);\nexport type ToolPermissionFlags = z.infer<typeof ToolPermissionFlags>;\n","import { z } from \"zod\";\n\n/**\n * Audience claim pinned to the CoreConnect MCP boundary.\n *\n * Capability tokens are minted by the Api for a single audience. The literal type prevents\n * accidental cross-audience reuse at parse time; cryptographic verification happens in the\n * Api layer, not here.\n */\nexport const CapabilityTokenAudience = z.literal(\"coreconnect-mcp\");\nexport type CapabilityTokenAudience = z.infer<typeof CapabilityTokenAudience>;\n\n/**\n * Surface taxonomy that the capability token is bound to.\n *\n * - `page` — a top-level routed surface inside an extension.\n * - `dialog` — modal dialog opened over the host.\n * - `panel` — non-modal side panel.\n * - `portal` — a contribution rendered into a host-owned slot (sidebar, header, etc.).\n *\n * @remarks\n * Distinct from the manifest-level `SurfaceType` enum: that enum describes how a plugin\n * *declares* a surface contribution, whereas this enum describes *which* surface a runtime\n * capability token is bound to at invocation time.\n */\nexport const CapabilityTokenSurfaceKind = z.enum([\n \"page\",\n \"dialog\",\n \"panel\",\n \"portal\",\n]);\nexport type CapabilityTokenSurfaceKind = z.infer<\n typeof CapabilityTokenSurfaceKind\n>;\n\n/**\n * Runtime implementation the surface is being rendered under.\n *\n * - `host-rendered` — host application renders the surface from a declarative description.\n * - `worker-remote-dom` — plugin ships a remote runtime hosted in a Web Worker /\n * isolation boundary, communicating with the host via remote-DOM.\n * - `first-party-host-extension` — plugin is bundled with the host and shares its runtime.\n *\n * @remarks\n * `worker-remote-dom` is the runtime-level analogue of the manifest's `remote-runtime`\n * `RenderMode`. The names diverge intentionally: the manifest declares an intent\n * (RenderMode.RemoteRuntime), and the token records the concrete runtime the host chose\n * to honour it with.\n */\nexport const CapabilityTokenRuntimeImplementation = z.enum([\n \"host-rendered\",\n \"worker-remote-dom\",\n \"first-party-host-extension\",\n]);\nexport type CapabilityTokenRuntimeImplementation = z.infer<\n typeof CapabilityTokenRuntimeImplementation\n>;\n\n/**\n * Claim shape for a CoreConnect capability token.\n *\n * The schema enforces structural validity only — cryptographic signature verification,\n * issuer trust, and expiry enforcement live in the Api. JWT registered claims (`iss`,\n * `sub`, `aud`, `iat`, `exp`, `jti`) are kept in their canonical lower-case form; the\n * tenancy + surface claims use snake_case to match how the Api emits them on the wire.\n *\n * Tightenings (beyond the bare JWT shape):\n *\n * - All required string claims are `.min(1)` — empty `tenant_id` / `extension_id` / `jti`\n * etc. are not meaningful tenancy values and must be rejected at parse time, not at\n * downstream rendering.\n * - `org_id`, `tenant_id`, `user_id`, `extension_id`, and `surface_instance_id` are\n * contractually UUIDs — `.uuid()` rejects free-form identifiers before they reach the\n * tenant boundary.\n * - `iat` / `exp` are Unix seconds; non-negative integers only. A `.refine()` then asserts\n * `exp > iat` so a token cannot validate with an expiry at-or-before its issuance.\n *\n * Cryptographic verification continues to be the Api's responsibility — these rules cover\n * the structural plane.\n */\nexport const CapabilityTokenClaims = z\n .object({\n /** JWT issuer (`iss`) — the Api endpoint that minted the token. */\n iss: z.string().min(1),\n /** JWT subject (`sub`) — typically the acting user principal. */\n sub: z.string().min(1),\n /** JWT audience (`aud`) — pinned to the MCP boundary. */\n aud: CapabilityTokenAudience,\n /** JWT issued-at (`iat`) — Unix seconds, non-negative. */\n iat: z.number().int().nonnegative(),\n /** JWT expiry (`exp`) — Unix seconds, non-negative. */\n exp: z.number().int().nonnegative(),\n /** Organisation the surface is scoped to. */\n org_id: z.string().uuid(),\n /** Tenant the surface is scoped to within the organisation. */\n tenant_id: z.string().uuid(),\n /** Acting user principal. */\n user_id: z.string().uuid(),\n /** Identifier of the extension that owns the surface. */\n extension_id: z.string().uuid(),\n /** Specific version of the extension currently rendered. */\n extension_version: z.string().min(1),\n /** Stable identifier of the surface instance (per open dialog/page). */\n surface_instance_id: z.string().uuid(),\n /** Taxonomic kind of the surface this token is bound to. */\n surface_kind: CapabilityTokenSurfaceKind,\n /** Runtime implementation rendering the surface. */\n runtime_implementation: CapabilityTokenRuntimeImplementation,\n /** JWT identifier (`jti`) — unique per token, supports replay detection. */\n jti: z.string().min(1),\n })\n .refine((claims) => claims.exp > claims.iat, {\n message: \"exp must be strictly greater than iat\",\n path: [\"exp\"],\n });\nexport type CapabilityTokenClaims = z.infer<typeof CapabilityTokenClaims>;\n","export const PROTOCOL_PACKAGE = \"@ethisyscore/protocol\";\nexport * from \"./bridge/version\";\nexport * from \"./manifest\";\nexport * from \"./sdui\";\nexport * from \"./theme/tokens\";\nexport * from \"./capability/permissions\";\nexport * from \"./capability/token\";\n"]}