@xemahq/kernel-contracts 0.32.0 → 0.34.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.
Files changed (105) hide show
  1. package/dist/app-runtime/index.d.ts +3 -0
  2. package/dist/app-runtime/index.d.ts.map +1 -1
  3. package/dist/app-runtime/index.js +3 -0
  4. package/dist/app-runtime/index.js.map +1 -1
  5. package/dist/app-runtime/lib/app-channel.d.ts +7 -0
  6. package/dist/app-runtime/lib/app-channel.d.ts.map +1 -0
  7. package/dist/app-runtime/lib/app-channel.js +11 -0
  8. package/dist/app-runtime/lib/app-channel.js.map +1 -0
  9. package/dist/app-runtime/lib/app-release.d.ts +24 -0
  10. package/dist/app-runtime/lib/app-release.d.ts.map +1 -0
  11. package/dist/app-runtime/lib/app-release.js +29 -0
  12. package/dist/app-runtime/lib/app-release.js.map +1 -0
  13. package/dist/app-runtime/lib/app.d.ts +3 -0
  14. package/dist/app-runtime/lib/app.d.ts.map +1 -1
  15. package/dist/app-runtime/lib/app.js +19 -4
  16. package/dist/app-runtime/lib/app.js.map +1 -1
  17. package/dist/app-runtime/lib/branding-config.d.ts.map +1 -1
  18. package/dist/app-runtime/lib/branding-config.js.map +1 -1
  19. package/dist/app-runtime/lib/delegated-session.js +1 -1
  20. package/dist/app-runtime/lib/delegated-session.js.map +1 -1
  21. package/dist/app-runtime/lib/surface-kind.d.ts +8 -0
  22. package/dist/app-runtime/lib/surface-kind.d.ts.map +1 -0
  23. package/dist/app-runtime/lib/surface-kind.js +12 -0
  24. package/dist/app-runtime/lib/surface-kind.js.map +1 -0
  25. package/dist/capability/index.d.ts +1 -0
  26. package/dist/capability/index.d.ts.map +1 -1
  27. package/dist/capability/index.js +1 -0
  28. package/dist/capability/index.js.map +1 -1
  29. package/dist/capability/lib/first-party-capability-domains.d.ts +29 -0
  30. package/dist/capability/lib/first-party-capability-domains.d.ts.map +1 -0
  31. package/dist/capability/lib/first-party-capability-domains.js +35 -0
  32. package/dist/capability/lib/first-party-capability-domains.js.map +1 -0
  33. package/dist/connector/index.d.ts +1 -0
  34. package/dist/connector/index.d.ts.map +1 -1
  35. package/dist/connector/index.js +1 -0
  36. package/dist/connector/index.js.map +1 -1
  37. package/dist/connector/lib/connector-adapter-kind.d.ts +1 -0
  38. package/dist/connector/lib/connector-adapter-kind.d.ts.map +1 -1
  39. package/dist/connector/lib/connector-adapter-kind.js +1 -0
  40. package/dist/connector/lib/connector-adapter-kind.js.map +1 -1
  41. package/dist/connector/lib/connector-descriptor.d.ts +29 -1
  42. package/dist/connector/lib/connector-descriptor.d.ts.map +1 -1
  43. package/dist/connector/lib/connector-descriptor.js +22 -1
  44. package/dist/connector/lib/connector-descriptor.js.map +1 -1
  45. package/dist/connector/lib/connector-http-request.d.ts +56 -0
  46. package/dist/connector/lib/connector-http-request.d.ts.map +1 -0
  47. package/dist/connector/lib/connector-http-request.js +86 -0
  48. package/dist/connector/lib/connector-http-request.js.map +1 -0
  49. package/dist/connector/lib/integration-provider-contribution.d.ts +17 -1
  50. package/dist/connector/lib/integration-provider-contribution.d.ts.map +1 -1
  51. package/dist/connector/lib/integration-provider-contribution.js +11 -0
  52. package/dist/connector/lib/integration-provider-contribution.js.map +1 -1
  53. package/dist/connector/lib/provider-descriptor.d.ts +3 -0
  54. package/dist/connector/lib/provider-descriptor.d.ts.map +1 -1
  55. package/dist/connector/lib/provider-descriptor.js +1 -0
  56. package/dist/connector/lib/provider-descriptor.js.map +1 -1
  57. package/dist/contribution/lib/contribution-kind.d.ts.map +1 -1
  58. package/dist/contribution/lib/contribution-kind.js.map +1 -1
  59. package/dist/principal/index.d.ts +6 -0
  60. package/dist/principal/index.d.ts.map +1 -0
  61. package/dist/principal/index.js +22 -0
  62. package/dist/principal/index.js.map +1 -0
  63. package/dist/principal/lib/app-invocation-identity.d.ts +22 -0
  64. package/dist/principal/lib/app-invocation-identity.d.ts.map +1 -0
  65. package/dist/principal/lib/app-invocation-identity.js +36 -0
  66. package/dist/principal/lib/app-invocation-identity.js.map +1 -0
  67. package/dist/principal/lib/clamp-authority.d.ts +4 -0
  68. package/dist/principal/lib/clamp-authority.d.ts.map +1 -0
  69. package/dist/principal/lib/clamp-authority.js +23 -0
  70. package/dist/principal/lib/clamp-authority.js.map +1 -0
  71. package/dist/principal/lib/delegation-chain.d.ts +26 -0
  72. package/dist/principal/lib/delegation-chain.d.ts.map +1 -0
  73. package/dist/principal/lib/delegation-chain.js +81 -0
  74. package/dist/principal/lib/delegation-chain.js.map +1 -0
  75. package/dist/principal/lib/delegation-grant.d.ts +10 -0
  76. package/dist/principal/lib/delegation-grant.d.ts.map +1 -0
  77. package/dist/principal/lib/delegation-grant.js +12 -0
  78. package/dist/principal/lib/delegation-grant.js.map +1 -0
  79. package/dist/principal/lib/execution-principal.d.ts +20 -0
  80. package/dist/principal/lib/execution-principal.d.ts.map +1 -0
  81. package/dist/principal/lib/execution-principal.js +22 -0
  82. package/dist/principal/lib/execution-principal.js.map +1 -0
  83. package/package.json +1 -1
  84. package/src/app-runtime/index.ts +3 -0
  85. package/src/app-runtime/lib/app-channel.ts +32 -0
  86. package/src/app-runtime/lib/app-release.ts +90 -0
  87. package/src/app-runtime/lib/app.ts +48 -17
  88. package/src/app-runtime/lib/branding-config.ts +12 -6
  89. package/src/app-runtime/lib/delegated-session.ts +2 -2
  90. package/src/app-runtime/lib/surface-kind.ts +30 -0
  91. package/src/capability/index.ts +1 -0
  92. package/src/capability/lib/first-party-capability-domains.ts +76 -0
  93. package/src/connector/index.ts +1 -0
  94. package/src/connector/lib/connector-adapter-kind.ts +9 -1
  95. package/src/connector/lib/connector-descriptor.ts +44 -8
  96. package/src/connector/lib/connector-http-request.ts +187 -0
  97. package/src/connector/lib/integration-provider-contribution.ts +21 -0
  98. package/src/connector/lib/provider-descriptor.ts +10 -0
  99. package/src/contribution/lib/contribution-kind.ts +111 -19
  100. package/src/principal/index.ts +5 -0
  101. package/src/principal/lib/app-invocation-identity.ts +95 -0
  102. package/src/principal/lib/clamp-authority.ts +64 -0
  103. package/src/principal/lib/delegation-chain.ts +145 -0
  104. package/src/principal/lib/delegation-grant.ts +36 -0
  105. package/src/principal/lib/execution-principal.ts +74 -0
@@ -0,0 +1,145 @@
1
+ import { z } from 'zod';
2
+ import { subjectRefToString, type SubjectRef } from '../../subject';
3
+ import type { DelegationGrant } from './delegation-grant';
4
+
5
+ /**
6
+ * Maximum number of hops permitted in a single delegation chain. Delegation is
7
+ * bounded: user → app → workflow → agent is the deepest legitimate path, so a
8
+ * chain of more than THREE grants is rejected outright. This is a hard cap, not
9
+ * a truncation point — an over-long chain is an error, never silently clipped.
10
+ */
11
+ export const MAX_DELEGATION_DEPTH = 3;
12
+
13
+ /**
14
+ * Closed set of delegation-chain validation failures. Every rejection carries a
15
+ * structured code so callers branch without string parsing.
16
+ */
17
+ export enum DelegationErrorCode {
18
+ /** The chain has more hops than `MAX_DELEGATION_DEPTH`. */
19
+ ChainTooDeep = 'DELEGATION_CHAIN_TOO_DEEP',
20
+ /** A subject appears more than once across the chain — a delegation cycle. */
21
+ Cycle = 'DELEGATION_CHAIN_CYCLE',
22
+ /** Hop `i`'s `to` is not hop `i+1`'s `from` — the chain is not contiguous. */
23
+ Discontinuous = 'DELEGATION_CHAIN_DISCONTINUOUS',
24
+ /** The chain's first `from` is not the principal's `actor`. */
25
+ NotAnchoredAtActor = 'DELEGATION_CHAIN_NOT_ANCHORED_AT_ACTOR',
26
+ /** The chain's last `to` is not the principal's `executor`. */
27
+ NotAnchoredAtExecutor = 'DELEGATION_CHAIN_NOT_ANCHORED_AT_EXECUTOR',
28
+ /**
29
+ * The chain is empty but `actor` and `executor` differ. An empty chain is
30
+ * only valid for a self-acting principal (`actor === executor`, e.g. a
31
+ * scheduled `AsApp` app); claiming delegation with no hops is malformed.
32
+ */
33
+ EmptyChainMismatch = 'DELEGATION_CHAIN_EMPTY_MISMATCH',
34
+ }
35
+
36
+ export const DelegationErrorCodeSchema = z.nativeEnum(DelegationErrorCode);
37
+
38
+ /**
39
+ * Structured, fail-fast error thrown by `resolveDelegationChain`. Never a
40
+ * warning, never a coercion — an invalid chain aborts resolution.
41
+ */
42
+ export class DelegationChainError extends Error {
43
+ readonly code: DelegationErrorCode;
44
+
45
+ constructor(args: { code: DelegationErrorCode; message: string }) {
46
+ super(args.message);
47
+ this.name = 'DelegationChainError';
48
+ this.code = args.code;
49
+ }
50
+ }
51
+
52
+ function subjectsEqual(a: SubjectRef, b: SubjectRef): boolean {
53
+ return subjectRefToString(a) === subjectRefToString(b);
54
+ }
55
+
56
+ /**
57
+ * Validate a delegation chain against its principal's `actor`/`executor`
58
+ * endpoints and return the (frozen) chain when it is well-formed.
59
+ *
60
+ * Fail-fast — throws `DelegationChainError` on ANY of:
61
+ *
62
+ * - a chain longer than `MAX_DELEGATION_DEPTH` (`ChainTooDeep`);
63
+ * - a cycle: any subject appearing twice in the hop sequence (`Cycle`);
64
+ * - a chain whose first `from` is not `actor` (`NotAnchoredAtActor`);
65
+ * - a chain whose last `to` is not `executor` (`NotAnchoredAtExecutor`);
66
+ * - a non-contiguous chain where hop i's `to` ≠ hop i+1's `from`
67
+ * (`Discontinuous`);
68
+ * - an empty chain when `actor` ≠ `executor` (`EmptyChainMismatch`).
69
+ *
70
+ * Cycles and over-depth are ERRORS, never truncations: the chain is rejected
71
+ * whole, never clipped to fit.
72
+ */
73
+ export function resolveDelegationChain(args: {
74
+ actor: SubjectRef;
75
+ executor: SubjectRef;
76
+ chain: readonly DelegationGrant[];
77
+ }): readonly DelegationGrant[] {
78
+ const { actor, executor, chain } = args;
79
+
80
+ // Empty chain: only a self-acting principal (actor === executor) may omit
81
+ // delegation. Anything else is a delegation claim with no proof.
82
+ if (chain.length === 0) {
83
+ if (!subjectsEqual(actor, executor)) {
84
+ throw new DelegationChainError({
85
+ code: DelegationErrorCode.EmptyChainMismatch,
86
+ message: `Empty delegation chain requires actor === executor, but actor "${subjectRefToString(
87
+ actor,
88
+ )}" ≠ executor "${subjectRefToString(executor)}".`,
89
+ });
90
+ }
91
+ return Object.freeze([]);
92
+ }
93
+
94
+ if (chain.length > MAX_DELEGATION_DEPTH) {
95
+ throw new DelegationChainError({
96
+ code: DelegationErrorCode.ChainTooDeep,
97
+ message: `Delegation chain has ${chain.length} hops; the maximum is ${MAX_DELEGATION_DEPTH}.`,
98
+ });
99
+ }
100
+
101
+ // Anchor: first from === actor, last to === executor.
102
+ if (!subjectsEqual(chain[0]!.from, actor)) {
103
+ throw new DelegationChainError({
104
+ code: DelegationErrorCode.NotAnchoredAtActor,
105
+ message: `Delegation chain must start at actor "${subjectRefToString(
106
+ actor,
107
+ )}", but its first hop starts at "${subjectRefToString(chain[0]!.from)}".`,
108
+ });
109
+ }
110
+ const last = chain[chain.length - 1]!;
111
+ if (!subjectsEqual(last.to, executor)) {
112
+ throw new DelegationChainError({
113
+ code: DelegationErrorCode.NotAnchoredAtExecutor,
114
+ message: `Delegation chain must end at executor "${subjectRefToString(
115
+ executor,
116
+ )}", but its last hop ends at "${subjectRefToString(last.to)}".`,
117
+ });
118
+ }
119
+
120
+ // Contiguity + cycle detection over the node sequence
121
+ // [from0, to0, to1, …, toN-1].
122
+ const seen = new Set<string>();
123
+ const firstKey = subjectRefToString(chain[0]!.from);
124
+ seen.add(firstKey);
125
+ for (let i = 0; i < chain.length; i += 1) {
126
+ if (i > 0 && !subjectsEqual(chain[i - 1]!.to, chain[i]!.from)) {
127
+ throw new DelegationChainError({
128
+ code: DelegationErrorCode.Discontinuous,
129
+ message: `Delegation chain is not contiguous at hop ${i}: previous "to" "${subjectRefToString(
130
+ chain[i - 1]!.to,
131
+ )}" ≠ this "from" "${subjectRefToString(chain[i]!.from)}".`,
132
+ });
133
+ }
134
+ const toKey = subjectRefToString(chain[i]!.to);
135
+ if (seen.has(toKey)) {
136
+ throw new DelegationChainError({
137
+ code: DelegationErrorCode.Cycle,
138
+ message: `Delegation chain contains a cycle: subject "${toKey}" appears more than once.`,
139
+ });
140
+ }
141
+ seen.add(toKey);
142
+ }
143
+
144
+ return Object.freeze([...chain]);
145
+ }
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod';
2
+ import { SubjectRefSchema, type SubjectRef } from '../../subject';
3
+
4
+ /**
5
+ * `DelegationGrant` — one hop in a delegation chain. It records HOW authority
6
+ * moved from one subject to the next, so the PDP and the audit trail can prove
7
+ * the path an invocation took (user → app → workflow → agent → connector)
8
+ * rather than collapsing it to "the workflow service called a connector".
9
+ *
10
+ * Deliberately minimal — `{ from, to, grantedAt, reason? }` — and it does NOT
11
+ * carry a per-hop capability subset. Justification: effective authority is
12
+ * resolved by `clampAuthority` as `grants(executor) ∩ effective(actor)` from the
13
+ * authorization plane's grant tables keyed by SUBJECT, not from data embedded in
14
+ * the chain. A grant here is a PROVENANCE record (who handed authority to whom,
15
+ * when, and why), never a capability carrier — putting a capability set on the
16
+ * hop would duplicate the clamp responsibility and create a second, forgeable
17
+ * source of truth for "what may this delegate do". `grantedAt` (ISO-8601) plus
18
+ * an optional human `reason` is the whole audit payload a hop needs.
19
+ */
20
+ export interface DelegationGrant {
21
+ /** The subject handing authority DOWN at this hop. */
22
+ from: SubjectRef;
23
+ /** The subject RECEIVING authority at this hop. */
24
+ to: SubjectRef;
25
+ /** ISO-8601 timestamp at which this hop was minted. */
26
+ grantedAt: string;
27
+ /** Optional human-readable rationale for the delegation (audit only). */
28
+ reason?: string;
29
+ }
30
+
31
+ export const DelegationGrantSchema = z.object({
32
+ from: SubjectRefSchema,
33
+ to: SubjectRefSchema,
34
+ grantedAt: z.string().datetime(),
35
+ reason: z.string().min(1).optional(),
36
+ }) as z.ZodType<DelegationGrant>;
@@ -0,0 +1,74 @@
1
+ import { z } from 'zod';
2
+ import {
3
+ SubjectRefSchema,
4
+ TokenClassSchema,
5
+ type SubjectRef,
6
+ type TokenClass,
7
+ } from '../../subject';
8
+ import {
9
+ ExecutionEnvironmentRefSchema,
10
+ type ExecutionEnvironmentRef,
11
+ } from '../../execution-environment';
12
+ import { AppChannelSchema, type AppChannel } from '../../app-runtime';
13
+ import { DelegationGrantSchema, type DelegationGrant } from './delegation-grant';
14
+
15
+ /**
16
+ * `ExecutionPrincipal` — the SINGLE delegation contract (plan D5).
17
+ *
18
+ * The tree previously answered "who is acting, on whose behalf, with what
19
+ * authority" in six divergent coats: `SubjectKind`, `TokenClass`,
20
+ * `SubjectRef.actingFor`, delegated sessions, external subjects, anonymous
21
+ * sessions, and a PDP "delegation clamp". `ExecutionPrincipal` is the one
22
+ * answer. It SURVIVES the whole hop path user → app → workflow → agent →
23
+ * connector — if it did not, the audit trail would collapse to "the workflow
24
+ * service called a connector" and the PDP could not prove HOW authority was
25
+ * delegated.
26
+ *
27
+ * - `actor` is the ORIGINAL human or external subject whose authority is being
28
+ * exercised. `executor` is what is actually running (app | workflow | agent |
29
+ * service). Effective authority is `clampAuthority(grants(executor),
30
+ * effective(actor))` — an intersection, never a union.
31
+ * - `delegationChain` records every hop; `resolveDelegationChain` bounds it to
32
+ * `MAX_DELEGATION_DEPTH` and rejects cycles fail-fast.
33
+ * - `channel` (preview/live), `appId`, `releaseId`, `tenantId`, `purpose` are
34
+ * the invocation-context fields the PDP and audit trail stamp; all optional
35
+ * because not every principal is an app invocation.
36
+ */
37
+ export interface ExecutionPrincipal {
38
+ /** The original human or external subject on whose behalf execution runs. */
39
+ actor: SubjectRef;
40
+ /** What is actually running: app | workflow | agent | service. */
41
+ executor: SubjectRef;
42
+ /** Ordered record of how authority moved from `actor` to `executor`. */
43
+ delegationChain: DelegationGrant[];
44
+ /** The minted token class carried by this invocation. */
45
+ tokenClass: TokenClass;
46
+ /** The permission-plane environment this invocation is tagged with. */
47
+ environment: ExecutionEnvironmentRef;
48
+ /** The single tenant org this invocation is fenced to. */
49
+ orgId: string;
50
+ /** The app being invoked, when this is an app invocation. */
51
+ appId?: string;
52
+ /** The pinned release of `appId`, when applicable. */
53
+ releaseId?: string;
54
+ /** Which definition + data the invocation sees (preview | live). */
55
+ channel?: AppChannel;
56
+ /** Sub-tenant scope within `orgId`, when the app is multi-tenant. */
57
+ tenantId?: string;
58
+ /** Free-form audit annotation of why this invocation is happening. */
59
+ purpose?: string;
60
+ }
61
+
62
+ export const ExecutionPrincipalSchema = z.object({
63
+ actor: SubjectRefSchema,
64
+ executor: SubjectRefSchema,
65
+ delegationChain: z.array(DelegationGrantSchema),
66
+ tokenClass: TokenClassSchema,
67
+ environment: ExecutionEnvironmentRefSchema,
68
+ orgId: z.string().min(1),
69
+ appId: z.string().min(1).optional(),
70
+ releaseId: z.string().min(1).optional(),
71
+ channel: AppChannelSchema.optional(),
72
+ tenantId: z.string().min(1).optional(),
73
+ purpose: z.string().min(1).optional(),
74
+ }) as z.ZodType<ExecutionPrincipal>;