@exponential_app/engine 0.0.0-stage → 0.1.1

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 (85) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +54 -0
  3. package/README.md +35 -2
  4. package/dist/capabilities.js +29 -0
  5. package/dist/capabilities.js.map +9 -0
  6. package/dist/chunks/index-3nf9f7pv.js +315 -0
  7. package/dist/chunks/index-3nf9f7pv.js.map +10 -0
  8. package/dist/chunks/index-3rgr16n2.js +443 -0
  9. package/dist/chunks/index-3rgr16n2.js.map +9 -0
  10. package/dist/chunks/index-79swfbsm.js +366 -0
  11. package/dist/chunks/index-79swfbsm.js.map +10 -0
  12. package/dist/chunks/index-knntt4cb.js +259 -0
  13. package/dist/chunks/index-knntt4cb.js.map +10 -0
  14. package/dist/chunks/index-m2845dn6.js +72 -0
  15. package/dist/chunks/index-m2845dn6.js.map +10 -0
  16. package/dist/chunks/index-pqpnz4ns.js +2213 -0
  17. package/dist/chunks/index-pqpnz4ns.js.map +9 -0
  18. package/dist/chunks/index-q4zws02e.js +2301 -0
  19. package/dist/chunks/index-q4zws02e.js.map +10 -0
  20. package/dist/chunks/index-s3xjr701.js +170 -0
  21. package/dist/chunks/index-s3xjr701.js.map +10 -0
  22. package/dist/chunks/index-sk8b0dh4.js +126 -0
  23. package/dist/chunks/index-sk8b0dh4.js.map +10 -0
  24. package/dist/chunks/index-tvsykgcv.js +3015 -0
  25. package/dist/chunks/index-tvsykgcv.js.map +19 -0
  26. package/dist/chunks/index-v0m7r4y3.js +6869 -0
  27. package/dist/chunks/index-v0m7r4y3.js.map +13 -0
  28. package/dist/consent.js +24 -0
  29. package/dist/consent.js.map +9 -0
  30. package/dist/index.js +654 -0
  31. package/dist/index.js.map +12 -0
  32. package/dist/lifecycle.js +11 -0
  33. package/dist/lifecycle.js.map +9 -0
  34. package/dist/outbox.js +27 -0
  35. package/dist/outbox.js.map +9 -0
  36. package/dist/pdf.js +15 -0
  37. package/dist/pdf.js.map +9 -0
  38. package/dist/providers.js +26 -0
  39. package/dist/providers.js.map +9 -0
  40. package/dist/runner.js +24 -0
  41. package/dist/runner.js.map +9 -0
  42. package/dist/tools.js +38 -0
  43. package/dist/tools.js.map +9 -0
  44. package/dist/types/domain-contract/src/app-records.d.ts +3148 -0
  45. package/dist/types/domain-contract/src/app-share.d.ts +222 -0
  46. package/dist/types/domain-contract/src/apps.d.ts +612 -0
  47. package/dist/types/eengine/fixtures/providers.json +55 -0
  48. package/dist/types/eengine/src/broker.d.ts +80 -0
  49. package/dist/types/eengine/src/capabilities.d.ts +88 -0
  50. package/dist/types/eengine/src/consent.d.ts +50 -0
  51. package/dist/types/eengine/src/index.d.ts +12 -0
  52. package/dist/types/eengine/src/instance.d.ts +131 -0
  53. package/dist/types/eengine/src/lifecycle.d.ts +64 -0
  54. package/dist/types/eengine/src/outbox.d.ts +3 -0
  55. package/dist/types/eengine/src/pdf.d.ts +36 -0
  56. package/dist/types/eengine/src/providers.d.ts +38 -0
  57. package/dist/types/eengine/src/runner.d.ts +82 -0
  58. package/dist/types/eengine/src/stores.d.ts +125 -0
  59. package/dist/types/eengine/src/synced.d.ts +59 -0
  60. package/dist/types/eengine/src/tools.d.ts +79 -0
  61. package/dist/types/eengine/src/web/index.d.ts +20 -0
  62. package/dist/types/eengine/src/web/mcp.d.ts +27 -0
  63. package/dist/types/eengine/src/web/platform.d.ts +91 -0
  64. package/dist/types/eengine/src/web/stores.d.ts +125 -0
  65. package/dist/types/emcp/fixtures/automations.json +521 -0
  66. package/dist/types/emcp/fixtures/hub.json +498 -0
  67. package/dist/types/emcp/src/access.d.ts +55 -0
  68. package/dist/types/emcp/src/audit.d.ts +22 -0
  69. package/dist/types/emcp/src/automations.d.ts +111 -0
  70. package/dist/types/emcp/src/exposes.d.ts +242 -0
  71. package/dist/types/emcp/src/hub.d.ts +63 -0
  72. package/dist/types/emcp/src/index.d.ts +7 -0
  73. package/dist/types/emcp/src/pure.d.ts +11 -0
  74. package/dist/types/emcp/src/upstream.d.ts +288 -0
  75. package/dist/types/emcp/src/vault.d.ts +34 -0
  76. package/dist/web/index.js +791 -0
  77. package/dist/web/index.js.map +13 -0
  78. package/fixtures/bundle.json +1165 -0
  79. package/fixtures/capabilities.json +434 -0
  80. package/fixtures/consent.json +146 -0
  81. package/fixtures/lifecycle.json +125 -0
  82. package/fixtures/outbox.json +22 -0
  83. package/fixtures/providers.json +55 -0
  84. package/fixtures/runner.json +2167 -0
  85. package/package.json +92 -4
@@ -0,0 +1,242 @@
1
+ export declare const EXPOSES_LIMITS: {
2
+ namePattern: string;
3
+ nameMax: number;
4
+ titleMax: number;
5
+ descriptionMax: number;
6
+ maxTools: number;
7
+ separator: string;
8
+ toolNameMax: number;
9
+ slugHashLength: number;
10
+ };
11
+ export declare const EXPOSES_ERRORS: string[];
12
+ export declare const PROVENANCE_KEYS: {
13
+ app: string;
14
+ tool: string;
15
+ via: string;
16
+ upstream: string;
17
+ device: string;
18
+ };
19
+ export type ToolAccess = `read` | `write`;
20
+ export type RecordsRun = {
21
+ records: {
22
+ op: `list` | `get` | `upsert`;
23
+ kind: string;
24
+ id?: unknown;
25
+ /** An object = jsonb containment; a list = the Q1 query's conditions. */
26
+ where?: Record<string, unknown> | unknown[];
27
+ data?: Record<string, unknown>;
28
+ limit?: unknown;
29
+ /** #VAPP-216: a list may name one of the package's `queries`, and may
30
+ * carry any Q1 JSON query key (sort, sum, group, aggregate, running,
31
+ * before, mine, user, month) beside `where` and `limit`. */
32
+ query?: string;
33
+ [key: string]: unknown;
34
+ };
35
+ };
36
+ export type ActionRun = {
37
+ action: string;
38
+ args?: Record<string, unknown>;
39
+ };
40
+ export type UpstreamRun = {
41
+ upstream: string;
42
+ tool: string;
43
+ args?: Record<string, unknown>;
44
+ };
45
+ /** #VAPP-236 (A2): hand judgement to a team agent (`agent` = its slug). */
46
+ export type AgentRun = {
47
+ agent: string;
48
+ prompt: string;
49
+ device?: string;
50
+ };
51
+ export type ExposeRun = RecordsRun | ActionRun | UpstreamRun | AgentRun;
52
+ export interface Expose {
53
+ name: string;
54
+ title: string;
55
+ description: string;
56
+ /** A JSON Schema of `type: "object"`. */
57
+ input: {
58
+ type: `object`;
59
+ properties?: Record<string, unknown>;
60
+ required?: string[];
61
+ };
62
+ access: ToolAccess;
63
+ run: ExposeRun;
64
+ }
65
+ /** What the app's package declares beside its `exposes`. */
66
+ export interface ExposeContext {
67
+ /** The record kinds of the manifest (`records: {<kind>: …}`). */
68
+ kinds: readonly string[];
69
+ /** The team MCP server names the app declares (`upstreams`): an app sees
70
+ * only its own. */
71
+ upstreams: readonly string[];
72
+ }
73
+ export type RunVia = `records` | `action` | `upstream` | `agent`;
74
+ export declare function runVia(run: ExposeRun): RunVia;
75
+ /** #VAPP-236 (A2): the agent hand-off's limits (exposes.json `agent`). */
76
+ export declare const AGENT_RUN: {
77
+ slugPattern: string;
78
+ slugMax: number;
79
+ promptMax: number;
80
+ devices: string[];
81
+ runsPerMinute: number;
82
+ valueMax: number;
83
+ dataMax: number;
84
+ auditPrefix: string;
85
+ agentSlugCases: {
86
+ name: string;
87
+ expected: string;
88
+ }[];
89
+ agentRateCases: {
90
+ handoffsLastMinute: number;
91
+ allowed: boolean;
92
+ }[];
93
+ promptCutCase: {
94
+ template: string;
95
+ repeat: number;
96
+ value: string;
97
+ valueRepeat: number;
98
+ promptLength: number;
99
+ endsWith: string;
100
+ };
101
+ briefCases: ({
102
+ name: string;
103
+ brief: {
104
+ prompt: string;
105
+ input: {
106
+ record: {
107
+ id: string;
108
+ title: string;
109
+ hours: number;
110
+ };
111
+ firedAt: string;
112
+ note?: undefined;
113
+ t?: undefined;
114
+ };
115
+ app: {
116
+ name: string;
117
+ slug: string;
118
+ };
119
+ source: string;
120
+ ref: {
121
+ kind: string;
122
+ id: string;
123
+ };
124
+ };
125
+ expected: string;
126
+ } | {
127
+ name: string;
128
+ brief: {
129
+ prompt: string;
130
+ input: {
131
+ note: string;
132
+ record?: undefined;
133
+ firedAt?: undefined;
134
+ t?: undefined;
135
+ };
136
+ app: {
137
+ name: string;
138
+ slug: string;
139
+ };
140
+ source: string;
141
+ ref?: undefined;
142
+ };
143
+ expected: string;
144
+ } | {
145
+ name: string;
146
+ brief: {
147
+ prompt: string;
148
+ input: {
149
+ t: string;
150
+ record?: undefined;
151
+ firedAt?: undefined;
152
+ note?: undefined;
153
+ };
154
+ app: {
155
+ name: string;
156
+ slug: string;
157
+ };
158
+ source: string;
159
+ ref?: undefined;
160
+ };
161
+ expected: string;
162
+ })[];
163
+ };
164
+ /** An agent's slug: its name lower-cased, every run of characters outside
165
+ * ASCII `a-z0-9` one `-`, dashes trimmed, cut to `slugMax`. */
166
+ export declare function agentSlug(name: string): string;
167
+ /** Whether another hand-off may start (the app's hand-offs of the last 60 s). */
168
+ export declare function agentRateAllows(handoffsLastMinute: number): boolean;
169
+ /** The audit row's `tool` of a hand-off. */
170
+ export declare function agentAuditTool(slug: string): string;
171
+ export interface AgentBriefInput {
172
+ prompt: string;
173
+ input: Record<string, unknown>;
174
+ app: {
175
+ name: string;
176
+ slug: string;
177
+ };
178
+ /** `automation <name>`, `tool <name>`, `handoff <name>`. */
179
+ source: string;
180
+ ref?: {
181
+ kind: string;
182
+ id: string;
183
+ } | null;
184
+ }
185
+ /** The hand-off's message: the frozen prompt (its templates filled as
186
+ * inline data), then the input as a fenced data block. Data is never
187
+ * instructions (§12.1). */
188
+ export declare function agentBrief(brief: AgentBriefInput): string;
189
+ /** An `exponential_<noun>_<op>` action is a read when the last word of its
190
+ * op is a read word (`list`, `get`, …); a verb tool is a write. */
191
+ export declare function actionAccess(name: string): ToolAccess;
192
+ export { upstreamDestructive, type UpstreamAnnotations } from "./pure.js";
193
+ import { type UpstreamAnnotations } from "./pure.js";
194
+ /** An upstream tool reads only when it says so (`readOnlyHint: true`). */
195
+ export declare function upstreamAccess(annotations: UpstreamAnnotations | null | undefined): ToolAccess;
196
+ /** The input paths a value's templates name (`${input.a.b}` → `a.b`). */
197
+ export declare function templatePaths(value: unknown): string[];
198
+ /** Fill a binding's args from the call's input. A string that is exactly
199
+ * one template takes the value itself (its type kept); an absent value
200
+ * drops the object key and is null in an array. A template inside other
201
+ * text is replaced by the value as text (absent/null = empty, objects =
202
+ * compact JSON). Everything else is copied. */
203
+ export declare function resolveArgs(template: unknown, input: Record<string, unknown>): unknown;
204
+ export interface ExposeError {
205
+ /** The binding's index in `exposes`, null for the list itself. */
206
+ index: number | null;
207
+ code: string;
208
+ }
209
+ /** Every error of an app's `exposes`, in order (empty = valid). */
210
+ export declare function validateExposes(exposes: readonly Expose[], ctx: ExposeContext): ExposeError[];
211
+ /** The call-time check of an upstream binding against the upstream tool's
212
+ * live annotations: null = callable, else the error code. */
213
+ export declare function upstreamCallError(expose: Expose, annotations: UpstreamAnnotations | null | undefined): string | null;
214
+ /** `n` lowercase base32 characters of the SHA-256 of `text`. */
215
+ export declare function shortHash(text: string, n?: number): string;
216
+ /** The MCP name of an app's tool: `<slug>__<name>`. Longer than
217
+ * `toolNameMax`, the slug is cut and ends in `-<hash of the full slug>`
218
+ * so the name stays unique and stable. */
219
+ export declare function qualifiedToolName(slug: string, name: string): string;
220
+ /** `<slug>__<name>` back to its parts (the first `__` splits: a binding
221
+ * name never holds one); null for anything else. */
222
+ export declare function splitToolName(qualified: string): {
223
+ app: string;
224
+ tool: string;
225
+ } | null;
226
+ export interface ListedApp {
227
+ slug: string;
228
+ exposes: readonly {
229
+ name: string;
230
+ }[];
231
+ }
232
+ /** The tool names of several apps on one endpoint, apps sorted by slug. A
233
+ * name an earlier app already holds is dropped (only a cut slug can
234
+ * collide). */
235
+ export declare function listToolNames(apps: readonly ListedApp[]): {
236
+ app: string;
237
+ tool: string;
238
+ name: string;
239
+ }[];
240
+ /** The `_meta` every result of an app tool carries (provenance: which app
241
+ * and binding answered, and through what). */
242
+ export declare function provenanceMeta(slug: string, expose: Expose): Record<string, string>;
@@ -0,0 +1,63 @@
1
+ import fixture from "../fixtures/hub.json" with { type: "json" };
2
+ import { type Level } from "./access.js";
3
+ import { type CallStatus } from "./audit.js";
4
+ import { type UpstreamAnnotations } from "./exposes.js";
5
+ export type HubOutcome = keyof typeof fixture.outcomes;
6
+ /** What a run may reach: a level per mounted server (not named = none). */
7
+ export interface HubGrant {
8
+ servers: Record<string, Exclude<Level, `none`>>;
9
+ teamId: string | null;
10
+ userId: string | null;
11
+ }
12
+ export interface HubTool {
13
+ name: string;
14
+ annotations?: UpstreamAnnotations | null;
15
+ }
16
+ export interface HubServer {
17
+ name: string;
18
+ tools: readonly HubTool[];
19
+ }
20
+ export interface HubRoute {
21
+ server: string;
22
+ tool: string;
23
+ }
24
+ /** May a server be mounted under `name`? */
25
+ export declare function hubServerNameValid(name: string): boolean;
26
+ /** The run's tools/list: every tool its grant lets it see, qualified. */
27
+ export declare function hubToolList(grant: HubGrant, servers: readonly HubServer[]): {
28
+ app: string;
29
+ tool: string;
30
+ name: string;
31
+ }[];
32
+ /** Where a call goes: a name on the run's own list, else null (unknown). */
33
+ export declare function hubRoute(grant: HubGrant, servers: readonly HubServer[], name: string): HubRoute | null;
34
+ /** The row's status and error code for an outcome. */
35
+ export declare function hubOutcomeStatus(outcome: HubOutcome): {
36
+ status: CallStatus;
37
+ error: string | null;
38
+ };
39
+ export interface HubAuditRow {
40
+ id: string;
41
+ teamId: string | null;
42
+ userId: string | null;
43
+ clientId: string;
44
+ appId: null;
45
+ tool: string;
46
+ status: CallStatus;
47
+ error: string | null;
48
+ latencyMs: number;
49
+ argsHash: string;
50
+ createdAt: string;
51
+ }
52
+ /** The `mcp_calls` row of one hub call (`outcome` = `unknown` when it was
53
+ * not routed). */
54
+ export declare function hubAuditRow(input: {
55
+ id: string;
56
+ grant: HubGrant;
57
+ run: string;
58
+ name: string;
59
+ args: unknown;
60
+ outcome: HubOutcome;
61
+ latencyMs: number;
62
+ createdAtMs: number;
63
+ }): HubAuditRow;
@@ -0,0 +1,7 @@
1
+ export * from "./exposes.js";
2
+ export * from "./access.js";
3
+ export * from "./audit.js";
4
+ export * from "./vault.js";
5
+ export * from "./upstream.js";
6
+ export * from "./hub.js";
7
+ export * from "./automations.js";
@@ -0,0 +1,11 @@
1
+ /** Canonical JSON: object keys sorted by code point, recursively, no
2
+ * whitespace; `undefined` object members dropped; -0 prints as 0. */
3
+ export declare function canonicalJson(value: unknown): string;
4
+ /** The MCP annotations of an upstream tool (from its `tools/list`). */
5
+ export interface UpstreamAnnotations {
6
+ readOnlyHint?: boolean;
7
+ destructiveHint?: boolean;
8
+ }
9
+ /** An upstream tool is destructive when it says so (`destructiveHint:
10
+ * true`) or a word of its name is a destructive word. */
11
+ export declare function upstreamDestructive(tool: string, annotations: UpstreamAnnotations | null | undefined): boolean;
@@ -0,0 +1,288 @@
1
+ export declare const UPSTREAM_STATES: readonly UpstreamState[];
2
+ export declare const UPSTREAM_LABELS: Record<UpstreamState, string>;
3
+ export declare const UPSTREAM_ERRORS: {
4
+ disconnected: string;
5
+ missing: string;
6
+ failed: string;
7
+ };
8
+ export type UpstreamState = `disconnected` | `connecting` | `connected` | `expired` | `reconnect` | `failed`;
9
+ export type UpstreamEvent = `connect` | `callbackOk` | `callbackError` | `flowExpired` | `secretSet` | `expire` | `refreshOk` | `refreshFailed` | `unauthorized` | `disconnect` | `serverChanged`;
10
+ /** The next state; an event a state does not list changes nothing. */
11
+ export declare function upstreamStep(state: UpstreamState, event: UpstreamEvent): UpstreamState;
12
+ /** May the broker call through it (an expired token is refreshed first)? */
13
+ export declare function upstreamCallable(state: UpstreamState): boolean;
14
+ /** The upstreams the consent page offers to connect: every server the
15
+ * chosen apps declare whose member state is not callable (no state =
16
+ * `disconnected`), sorted, each once. A server that no longer exists is
17
+ * not offered (its bindings answer `upstreamMissing`). */
18
+ export declare function missingUpstreams(declared: readonly (readonly string[])[], states: Readonly<Record<string, UpstreamState>>, servers: readonly string[]): string[];
19
+ export declare const UPSTREAM_MAPPING: {
20
+ $comment: string;
21
+ resolveCases: ({
22
+ name: string;
23
+ upstream: string;
24
+ bound: null;
25
+ servers: {
26
+ id: string;
27
+ name: string;
28
+ }[];
29
+ expected: {
30
+ id: string;
31
+ source: string;
32
+ };
33
+ } | {
34
+ name: string;
35
+ upstream: string;
36
+ bound: string;
37
+ servers: {
38
+ id: string;
39
+ name: string;
40
+ }[];
41
+ expected: {
42
+ id: string;
43
+ source: string;
44
+ };
45
+ } | {
46
+ name: string;
47
+ upstream: string;
48
+ bound: null;
49
+ servers: {
50
+ id: string;
51
+ name: string;
52
+ }[];
53
+ expected: null;
54
+ })[];
55
+ writeCases: ({
56
+ name: string;
57
+ upstream: string;
58
+ serverId: string;
59
+ servers: {
60
+ id: string;
61
+ name: string;
62
+ }[];
63
+ expected: {
64
+ op: string;
65
+ serverId: string;
66
+ error?: undefined;
67
+ };
68
+ } | {
69
+ name: string;
70
+ upstream: string;
71
+ serverId: null;
72
+ servers: {
73
+ id: string;
74
+ name: string;
75
+ }[];
76
+ expected: {
77
+ op: string;
78
+ serverId?: undefined;
79
+ error?: undefined;
80
+ };
81
+ } | {
82
+ name: string;
83
+ upstream: string;
84
+ serverId: string;
85
+ servers: {
86
+ id: string;
87
+ name: string;
88
+ }[];
89
+ expected: {
90
+ op: string;
91
+ serverId?: undefined;
92
+ error?: undefined;
93
+ };
94
+ } | {
95
+ name: string;
96
+ upstream: string;
97
+ serverId: string;
98
+ servers: {
99
+ id: string;
100
+ name: string;
101
+ }[];
102
+ expected: {
103
+ error: string;
104
+ op?: undefined;
105
+ serverId?: undefined;
106
+ };
107
+ })[];
108
+ auditCases: ({
109
+ upstream: string;
110
+ server: string;
111
+ expected: string;
112
+ } | {
113
+ upstream: string;
114
+ server: null;
115
+ expected: string;
116
+ })[];
117
+ };
118
+ export interface UpstreamServerRef {
119
+ id: string;
120
+ name: string;
121
+ }
122
+ export type UpstreamResolution<T> = {
123
+ server: T;
124
+ source: `mapped` | `name`;
125
+ };
126
+ /** The team server filling a declared upstream: a binding on the team, else
127
+ * the server of exactly that name, else null. */
128
+ export declare function resolveUpstreamServer<T extends UpstreamServerRef>(upstream: string, bound: string | null, servers: readonly T[]): UpstreamResolution<T> | null;
129
+ export type UpstreamMappingWrite = {
130
+ op: `set`;
131
+ serverId: string;
132
+ } | {
133
+ op: `clear`;
134
+ } | {
135
+ error: string;
136
+ };
137
+ /** What an owner's pick writes: the exact-name default keeps no row. */
138
+ export declare function upstreamMappingWrite(upstream: string, serverId: string | null, servers: readonly UpstreamServerRef[]): UpstreamMappingWrite;
139
+ /** The audit row's `tool` for a mapping change. */
140
+ export declare function upstreamMappingTool(upstream: string, server: string | null): string;
141
+ export declare const UPSTREAM_BINDING: {
142
+ readonly scheme: string;
143
+ readonly cacheSeconds: number;
144
+ readonly banner: string;
145
+ readonly connect: string;
146
+ readonly errors: {
147
+ notReadOnly: string;
148
+ destructive: string;
149
+ notDeclared: string;
150
+ invalid: string;
151
+ };
152
+ };
153
+ export interface UpstreamBinding {
154
+ server: string;
155
+ tool: string;
156
+ args: Record<string, unknown>;
157
+ }
158
+ /** A param's text as an argument: JSON literals, numbers, objects and
159
+ * arrays read as JSON; anything else stays the string. */
160
+ export declare function upstreamArg(text: string): unknown;
161
+ /** `upstream:crm/search?q=acme` → `{server: "crm", tool: "search", args:
162
+ * {q: "acme"}}` (eUI's source grammar; the name splits at its LAST `/`),
163
+ * null when it is not an upstream source. */
164
+ export declare function parseUpstreamSource(source: string): UpstreamBinding | null;
165
+ /** Exponential's install check: every `upstream:` source of a package's
166
+ * template bindings parses and names one of its `upstreams`. */
167
+ export declare function upstreamDeclareIssues(sources: readonly string[], upstreams: readonly string[]): {
168
+ index: number;
169
+ code: string;
170
+ }[];
171
+ /** The broker's call-time check against the tool's live annotations and the
172
+ * package's `sources` (an exact `upstream:<server>/<tool>` vouches for a
173
+ * tool that sets no readOnlyHint): null = it reads, else the error. */
174
+ export declare function upstreamReadError(binding: Pick<UpstreamBinding, `server` | `tool`>, annotations: {
175
+ readOnlyHint?: unknown;
176
+ destructiveHint?: unknown;
177
+ } | null | undefined, sources: readonly string[]): string | null;
178
+ /** The cache key of one read: member, server id, tool and canonical args. */
179
+ export declare function upstreamCacheKey(member: string, serverId: string, tool: string, args: Record<string, unknown>): string;
180
+ /** An MCP tools/call result as the binding's value. */
181
+ export declare function upstreamBindingValue(result: Record<string, unknown>): {
182
+ value: unknown;
183
+ } | {
184
+ error: string;
185
+ };
186
+ /** One host answer of `apps.upstreamRead`. */
187
+ export type UpstreamReadAnswer = {
188
+ ok: true;
189
+ value: unknown;
190
+ } | {
191
+ ok: false;
192
+ error: string;
193
+ server: string;
194
+ offline?: string;
195
+ };
196
+ /** The host's banners: one per server whose read answered
197
+ * upstreamDisconnected, sorted, each once. */
198
+ export declare function upstreamBanners(answers: readonly UpstreamReadAnswer[]): string[];
199
+ export declare const UPSTREAM_DEVICE: {
200
+ readonly ttlSeconds: number;
201
+ readonly answerTimeoutMs: number;
202
+ readonly maxAnswerBytes: number;
203
+ readonly errors: {
204
+ notOwner: string;
205
+ noDevice: string;
206
+ offline: string;
207
+ noAnswer: string;
208
+ };
209
+ readonly copy: {
210
+ noDevice: string;
211
+ notOwner: string;
212
+ offline: string;
213
+ noAnswer: string;
214
+ };
215
+ };
216
+ /** A server row as the router reads it: its transport and the device it
217
+ * names (with the device's owner and label), if any. */
218
+ export interface RoutedServer {
219
+ name: string;
220
+ transport: string;
221
+ device: {
222
+ id: string;
223
+ ownerId: string;
224
+ label: string;
225
+ } | null;
226
+ }
227
+ export type UpstreamRoute = {
228
+ route: `server`;
229
+ } | {
230
+ route: `device`;
231
+ deviceId: string;
232
+ } | {
233
+ error: string;
234
+ message: string;
235
+ };
236
+ /** Where one call to `server` by `callerId` (the member, or an automation's
237
+ * sponsor) runs: the server, the owner's device, or a refusal. */
238
+ export declare function upstreamRoute(server: RoutedServer, callerId: string): UpstreamRoute;
239
+ /** What the relay answered `POST /devices/:userId/:deviceId/upstream` with. */
240
+ export type DeviceRelayOutcome = {
241
+ delivered: true;
242
+ } | {
243
+ delivered: false;
244
+ reason: string;
245
+ };
246
+ /** The device's (opened) answer: the tool's result, or why it did not run. */
247
+ export type DeviceAnswer = {
248
+ ok: true;
249
+ result: Record<string, unknown>;
250
+ } | {
251
+ ok: false;
252
+ reason: `vetoed` | `refused` | `failed`;
253
+ error: string;
254
+ };
255
+ export type DeviceCallOutcome = {
256
+ result: Record<string, unknown>;
257
+ } | {
258
+ error: string;
259
+ message: string;
260
+ offline?: string;
261
+ };
262
+ /** One device call's outcome for the broker. `answer` = null when the relay
263
+ * delivered nothing that opens. */
264
+ export declare function deviceCallOutcome(server: string, deviceLabel: string, relay: DeviceRelayOutcome, answer: DeviceAnswer | null): DeviceCallOutcome;
265
+ /** Whether a device may claim a call: the member's own, on that device,
266
+ * unexpired (`expiresAt` ms) and not claimed yet. */
267
+ export declare function deviceCallClaimable(call: {
268
+ userId: string;
269
+ deviceId: string;
270
+ expiresAt: number;
271
+ claimed: boolean;
272
+ }, claim: {
273
+ userId: string;
274
+ deviceId: string;
275
+ }, now: number): boolean;
276
+ /** One host banner: its text and whether it carries the Connect action. */
277
+ export interface UpstreamHostBanner {
278
+ server: string;
279
+ text: string;
280
+ connect: boolean;
281
+ }
282
+ /** The host's banners ×4: `Connect <server>` for an upstreamDisconnected
283
+ * read, the offline copy for a device that is offline; one per server,
284
+ * sorted by server. */
285
+ export declare function upstreamHostBanners(answers: readonly UpstreamReadAnswer[]): UpstreamHostBanner[];
286
+ /** A server row's URL rule: https anywhere; http on loopback or a LAN host
287
+ * (a device-routed server's reach). */
288
+ export declare function mcpUrlAllowed(value: string): boolean;
@@ -0,0 +1,34 @@
1
+ export declare const VAULT_VERSION: string;
2
+ export interface VaultKey {
3
+ kid: string;
4
+ key: Buffer;
5
+ }
6
+ /** The current key and the retired ones (decrypt only). */
7
+ export interface Keyring {
8
+ current: VaultKey;
9
+ retired: readonly VaultKey[];
10
+ }
11
+ /** `<kid>:<base64 of 32 bytes>` → the key; null for anything else. */
12
+ export declare function parseVaultKey(spec: string | null | undefined): VaultKey | null;
13
+ /** `VAULT_KEY` + `VAULT_KEYS_RETIRED` (comma-separated) → the keyring;
14
+ * null when the current key is missing or malformed, or a kid repeats. A
15
+ * malformed retired entry is null too: a typo must not lose a key. */
16
+ export declare function parseKeyring(current: string | null | undefined, retired: string | null | undefined): Keyring | null;
17
+ /** The additional data binding a value to its row and the key that sealed
18
+ * it: `ev1|<kid>|<table>.<column>|<row id>`. */
19
+ export declare function vaultAad(kid: string, table: string, column: string, rowId: string): string;
20
+ export interface VaultSlot {
21
+ table: string;
22
+ column: string;
23
+ rowId: string;
24
+ }
25
+ /** Seal with an explicit iv (the vectors); `vaultSeal` draws one. */
26
+ export declare function vaultSealWith(key: VaultKey, iv: Buffer, plaintext: string, slot: VaultSlot): string;
27
+ export declare function vaultSeal(keyring: Keyring, plaintext: string, slot: VaultSlot): string;
28
+ /** The kid a value was sealed with; null for anything not a vault value. */
29
+ export declare function vaultKid(value: string | null | undefined): string | null;
30
+ /** The plaintext, or null for anything that does not open: another
31
+ * version, an unknown kid, another slot, a tampered value. */
32
+ export declare function vaultOpen(keyring: Keyring, value: string | null | undefined, slot: VaultSlot): string | null;
33
+ /** A value sealed with a retired key: the rotation sweep re-seals it. */
34
+ export declare function vaultNeedsRotation(keyring: Keyring, value: string | null | undefined): boolean;