@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.
- package/LICENSE +201 -0
- package/NOTICE +54 -0
- package/README.md +35 -2
- package/dist/capabilities.js +29 -0
- package/dist/capabilities.js.map +9 -0
- package/dist/chunks/index-3nf9f7pv.js +315 -0
- package/dist/chunks/index-3nf9f7pv.js.map +10 -0
- package/dist/chunks/index-3rgr16n2.js +443 -0
- package/dist/chunks/index-3rgr16n2.js.map +9 -0
- package/dist/chunks/index-79swfbsm.js +366 -0
- package/dist/chunks/index-79swfbsm.js.map +10 -0
- package/dist/chunks/index-knntt4cb.js +259 -0
- package/dist/chunks/index-knntt4cb.js.map +10 -0
- package/dist/chunks/index-m2845dn6.js +72 -0
- package/dist/chunks/index-m2845dn6.js.map +10 -0
- package/dist/chunks/index-pqpnz4ns.js +2213 -0
- package/dist/chunks/index-pqpnz4ns.js.map +9 -0
- package/dist/chunks/index-q4zws02e.js +2301 -0
- package/dist/chunks/index-q4zws02e.js.map +10 -0
- package/dist/chunks/index-s3xjr701.js +170 -0
- package/dist/chunks/index-s3xjr701.js.map +10 -0
- package/dist/chunks/index-sk8b0dh4.js +126 -0
- package/dist/chunks/index-sk8b0dh4.js.map +10 -0
- package/dist/chunks/index-tvsykgcv.js +3015 -0
- package/dist/chunks/index-tvsykgcv.js.map +19 -0
- package/dist/chunks/index-v0m7r4y3.js +6869 -0
- package/dist/chunks/index-v0m7r4y3.js.map +13 -0
- package/dist/consent.js +24 -0
- package/dist/consent.js.map +9 -0
- package/dist/index.js +654 -0
- package/dist/index.js.map +12 -0
- package/dist/lifecycle.js +11 -0
- package/dist/lifecycle.js.map +9 -0
- package/dist/outbox.js +27 -0
- package/dist/outbox.js.map +9 -0
- package/dist/pdf.js +15 -0
- package/dist/pdf.js.map +9 -0
- package/dist/providers.js +26 -0
- package/dist/providers.js.map +9 -0
- package/dist/runner.js +24 -0
- package/dist/runner.js.map +9 -0
- package/dist/tools.js +38 -0
- package/dist/tools.js.map +9 -0
- package/dist/types/domain-contract/src/app-records.d.ts +3148 -0
- package/dist/types/domain-contract/src/app-share.d.ts +222 -0
- package/dist/types/domain-contract/src/apps.d.ts +612 -0
- package/dist/types/eengine/fixtures/providers.json +55 -0
- package/dist/types/eengine/src/broker.d.ts +80 -0
- package/dist/types/eengine/src/capabilities.d.ts +88 -0
- package/dist/types/eengine/src/consent.d.ts +50 -0
- package/dist/types/eengine/src/index.d.ts +12 -0
- package/dist/types/eengine/src/instance.d.ts +131 -0
- package/dist/types/eengine/src/lifecycle.d.ts +64 -0
- package/dist/types/eengine/src/outbox.d.ts +3 -0
- package/dist/types/eengine/src/pdf.d.ts +36 -0
- package/dist/types/eengine/src/providers.d.ts +38 -0
- package/dist/types/eengine/src/runner.d.ts +82 -0
- package/dist/types/eengine/src/stores.d.ts +125 -0
- package/dist/types/eengine/src/synced.d.ts +59 -0
- package/dist/types/eengine/src/tools.d.ts +79 -0
- package/dist/types/eengine/src/web/index.d.ts +20 -0
- package/dist/types/eengine/src/web/mcp.d.ts +27 -0
- package/dist/types/eengine/src/web/platform.d.ts +91 -0
- package/dist/types/eengine/src/web/stores.d.ts +125 -0
- package/dist/types/emcp/fixtures/automations.json +521 -0
- package/dist/types/emcp/fixtures/hub.json +498 -0
- package/dist/types/emcp/src/access.d.ts +55 -0
- package/dist/types/emcp/src/audit.d.ts +22 -0
- package/dist/types/emcp/src/automations.d.ts +111 -0
- package/dist/types/emcp/src/exposes.d.ts +242 -0
- package/dist/types/emcp/src/hub.d.ts +63 -0
- package/dist/types/emcp/src/index.d.ts +7 -0
- package/dist/types/emcp/src/pure.d.ts +11 -0
- package/dist/types/emcp/src/upstream.d.ts +288 -0
- package/dist/types/emcp/src/vault.d.ts +34 -0
- package/dist/web/index.js +791 -0
- package/dist/web/index.js.map +13 -0
- package/fixtures/bundle.json +1165 -0
- package/fixtures/capabilities.json +434 -0
- package/fixtures/consent.json +146 -0
- package/fixtures/lifecycle.json +125 -0
- package/fixtures/outbox.json +22 -0
- package/fixtures/providers.json +55 -0
- package/fixtures/runner.json +2167 -0
- package/package.json +92 -4
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type BrokerAuditRow, type BrokerVerdict, type CallFrom, type Grants, type GrantValue, type ManifestEntry } from "./capabilities.js";
|
|
2
|
+
import { type ConsentAnswer, type GrantVia, type SurfaceComponent } from "./consent.js";
|
|
3
|
+
import { type BlobStore, type McpCallResult, type NativeCapability } from "./tools.js";
|
|
4
|
+
/** A refusal or a failure (eCore's shape: a code + a message). */
|
|
5
|
+
export interface Failure {
|
|
6
|
+
code: string;
|
|
7
|
+
message: string;
|
|
8
|
+
}
|
|
9
|
+
/** Where secrets live (Keychain, Keystore, libsecret; the web: IndexedDB). */
|
|
10
|
+
export interface Vault {
|
|
11
|
+
read(key: string): Promise<string | null>;
|
|
12
|
+
write(key: string, value: string): Promise<void>;
|
|
13
|
+
delete(key: string): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/** Where the broker's audit rows go. */
|
|
16
|
+
export interface CallAudit {
|
|
17
|
+
record(row: BrokerAuditRow): void;
|
|
18
|
+
}
|
|
19
|
+
/** The ask sheet the person answers (consent.json `consentSheet`): a genUI surface. */
|
|
20
|
+
export interface ConsentSheet {
|
|
21
|
+
scope: string;
|
|
22
|
+
components: SurfaceComponent[];
|
|
23
|
+
data: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
/** What a brokered call answers. */
|
|
26
|
+
export type BrokerAnswer = {
|
|
27
|
+
result: McpCallResult;
|
|
28
|
+
}
|
|
29
|
+
/** The person decides first: paint the sheet, then `answer`. */
|
|
30
|
+
| {
|
|
31
|
+
ask: BrokerVerdict;
|
|
32
|
+
sheet: ConsentSheet;
|
|
33
|
+
}
|
|
34
|
+
/** `code` = `UNKNOWN_TOOL` for unknown, else `FORBIDDEN`; `message` = the reason. */
|
|
35
|
+
| {
|
|
36
|
+
refused: Failure;
|
|
37
|
+
};
|
|
38
|
+
export interface BrokerSetup {
|
|
39
|
+
appId: string;
|
|
40
|
+
appName: string;
|
|
41
|
+
signer: string;
|
|
42
|
+
manifest: readonly ManifestEntry[];
|
|
43
|
+
grants: Grants;
|
|
44
|
+
capabilities: readonly NativeCapability[];
|
|
45
|
+
vault: Vault;
|
|
46
|
+
/** The app's files: what capabilities read (`fileId`) and store. */
|
|
47
|
+
blobs: BlobStore;
|
|
48
|
+
/** The package's screen names (a notification's tap opens one). */
|
|
49
|
+
screens: readonly string[];
|
|
50
|
+
audit?: CallAudit | null;
|
|
51
|
+
}
|
|
52
|
+
/** One app instance's broker. */
|
|
53
|
+
export declare class Broker {
|
|
54
|
+
private readonly setup;
|
|
55
|
+
private grantsNow;
|
|
56
|
+
private foreground;
|
|
57
|
+
/** The last grants write (tests and a closing page await it). */
|
|
58
|
+
persisted: Promise<void>;
|
|
59
|
+
constructor(setup: BrokerSetup);
|
|
60
|
+
get appId(): string;
|
|
61
|
+
get manifest(): readonly ManifestEntry[];
|
|
62
|
+
get capabilities(): readonly NativeCapability[];
|
|
63
|
+
grants(): Grants;
|
|
64
|
+
/** The lifecycle tells the broker whether a sheet may show. */
|
|
65
|
+
setForeground(foreground: boolean): void;
|
|
66
|
+
private provided;
|
|
67
|
+
private record;
|
|
68
|
+
private run;
|
|
69
|
+
/** One call from app UI (`client` = null) or an agent run (`client` = its run id). */
|
|
70
|
+
call(from: CallFrom, client: string | null, name: string, args: unknown): Promise<BrokerAnswer>;
|
|
71
|
+
/** The person's answer to the sheet for `verdict` (an Ask): store it per
|
|
72
|
+
* consent.json, then run or refuse the call. The answer is the gesture. */
|
|
73
|
+
answer(from: CallFrom, client: string | null, name: string, args: unknown, verdict: BrokerVerdict, answer: ConsentAnswer): Promise<BrokerAnswer>;
|
|
74
|
+
/** Change a grant (the Permissions sheet's Switch). Only the ConsentUi
|
|
75
|
+
* after a gesture; `value` null = revoke. Answers consent.json's refusal, or null. */
|
|
76
|
+
setGrant(via: GrantVia, gesture: boolean, scope: string, value: GrantValue | null): string | null;
|
|
77
|
+
/** The Permissions sheet (consent.json `manageSheet`). */
|
|
78
|
+
permissionsSheet(): SurfaceComponent[];
|
|
79
|
+
private persist;
|
|
80
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { type CallStatus, type HubOutcome } from "../../emcp/src/index.js";
|
|
2
|
+
export type ConsentKind = `ask` | `picker`;
|
|
3
|
+
export type GrantValue = `granted` | `denied`;
|
|
4
|
+
export type Grants = Record<string, GrantValue>;
|
|
5
|
+
export type CallFrom = `ui` | `agent`;
|
|
6
|
+
export interface CapabilityScope {
|
|
7
|
+
id: string;
|
|
8
|
+
verb: string;
|
|
9
|
+
consent: ConsentKind;
|
|
10
|
+
tools: readonly string[];
|
|
11
|
+
hostOnly?: boolean;
|
|
12
|
+
origins?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface CapabilityDef {
|
|
15
|
+
name: string;
|
|
16
|
+
label: string;
|
|
17
|
+
scopes: readonly CapabilityScope[];
|
|
18
|
+
/** #VAPP-273: a capability one host alone provides (`ede`); every other host answers `unavailable`. */
|
|
19
|
+
host?: string;
|
|
20
|
+
}
|
|
21
|
+
/** One entry of a package's capability manifest (format 5 `capabilities`). */
|
|
22
|
+
export interface ManifestEntry {
|
|
23
|
+
id: string;
|
|
24
|
+
why: string;
|
|
25
|
+
origins?: readonly string[];
|
|
26
|
+
}
|
|
27
|
+
export declare const CAPABILITIES: readonly CapabilityDef[];
|
|
28
|
+
export declare const RESERVED_CAPABILITY_NAMES: readonly string[];
|
|
29
|
+
/** Is `id` a scope id of the right form (`<capability>.<scope>`)? */
|
|
30
|
+
export declare const scopeIdValid: (id: string) => boolean;
|
|
31
|
+
/** May a capability be mounted under `name`? A hub server name that is not reserved. */
|
|
32
|
+
export declare const capabilityNameValid: (name: string) => boolean;
|
|
33
|
+
export declare const capabilityDef: (name: string) => CapabilityDef | null;
|
|
34
|
+
/** The catalog scope with `id`, with its capability. */
|
|
35
|
+
export declare function scopeDef(id: string): {
|
|
36
|
+
capability: CapabilityDef;
|
|
37
|
+
scope: CapabilityScope;
|
|
38
|
+
} | null;
|
|
39
|
+
/** A call's name → `{capability, tool}`: `<capability>__<tool>` from an agent,
|
|
40
|
+
* `<capability>_<tool>` from app UI (round 9 §6.3: split at the first `_`); null for any other form or a reserved name. */
|
|
41
|
+
export declare function parseCapabilityCall(from: CallFrom, name: string): {
|
|
42
|
+
capability: string;
|
|
43
|
+
tool: string;
|
|
44
|
+
} | null;
|
|
45
|
+
export type BrokerVerdictKind = `call` | `ask` | `denied` | `unknown` | `unavailable`;
|
|
46
|
+
export interface BrokerVerdict {
|
|
47
|
+
verdict: BrokerVerdictKind;
|
|
48
|
+
capability: string | null;
|
|
49
|
+
tool: string | null;
|
|
50
|
+
scope: string | null;
|
|
51
|
+
reason: string | null;
|
|
52
|
+
}
|
|
53
|
+
export interface BrokerCall {
|
|
54
|
+
from: CallFrom;
|
|
55
|
+
name: string;
|
|
56
|
+
arguments?: unknown;
|
|
57
|
+
}
|
|
58
|
+
export interface BrokerInput {
|
|
59
|
+
manifest: readonly ManifestEntry[];
|
|
60
|
+
grants: Grants;
|
|
61
|
+
/** The capability names this host mounts. */
|
|
62
|
+
provided: readonly string[];
|
|
63
|
+
foreground: boolean;
|
|
64
|
+
call: BrokerCall;
|
|
65
|
+
}
|
|
66
|
+
/** An `https://host[:port]` origin of a URL, or null. */
|
|
67
|
+
export declare function urlOrigin(url: unknown): string | null;
|
|
68
|
+
/** The broker's verdict for one call (capabilities.json `decideCases`). */
|
|
69
|
+
export declare function brokerDecide(input: BrokerInput): BrokerVerdict;
|
|
70
|
+
/** An agent's tools/list: every tool of a declared, provided, non-host-only scope. */
|
|
71
|
+
export declare function agentToolList(manifest: readonly ManifestEntry[], provided: readonly string[]): string[];
|
|
72
|
+
export interface BrokerAuditRow {
|
|
73
|
+
appId: string;
|
|
74
|
+
clientId: string;
|
|
75
|
+
tool: string;
|
|
76
|
+
status: CallStatus;
|
|
77
|
+
error: string | null;
|
|
78
|
+
argsHash: string;
|
|
79
|
+
}
|
|
80
|
+
/** The audit row of one brokered call. `client` = the agent run's id (null for UI);
|
|
81
|
+
* `outcome` = the call's outcome when it ran (`verdict: call`), else ignored. */
|
|
82
|
+
export declare function brokerAuditRow(input: {
|
|
83
|
+
appId: string;
|
|
84
|
+
client: string | null;
|
|
85
|
+
call: BrokerCall;
|
|
86
|
+
verdict: BrokerVerdict;
|
|
87
|
+
outcome: HubOutcome | null;
|
|
88
|
+
}): BrokerAuditRow;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type BrokerVerdictKind, type Grants, type GrantValue, type ManifestEntry } from "./capabilities.js";
|
|
2
|
+
export type ConsentAnswer = `allow` | `once` | `deny` | `dismiss`;
|
|
3
|
+
export type GrantVia = `consentUi` | `agent` | `hubTool` | `package` | `hostConfig` | `sync`;
|
|
4
|
+
export declare const CONSENT_COPY: {
|
|
5
|
+
title: string;
|
|
6
|
+
options: {
|
|
7
|
+
label: string;
|
|
8
|
+
value: string;
|
|
9
|
+
}[];
|
|
10
|
+
confirm: string;
|
|
11
|
+
manageTitle: string;
|
|
12
|
+
};
|
|
13
|
+
export declare const GRANTS_RECORD_VERSION: number;
|
|
14
|
+
/** A genUI component (the flat A2UI list a surface carries). */
|
|
15
|
+
export type SurfaceComponent = Record<string, unknown> & {
|
|
16
|
+
id: string;
|
|
17
|
+
component: string;
|
|
18
|
+
};
|
|
19
|
+
/** The sheet's answer → the call's verdict and the grants to store. */
|
|
20
|
+
export declare function consentAnswer(grants: Grants, scope: string, answer: ConsentAnswer): {
|
|
21
|
+
verdict: BrokerVerdictKind;
|
|
22
|
+
reason: string | null;
|
|
23
|
+
grants: Grants;
|
|
24
|
+
};
|
|
25
|
+
/** A grant write: only the ConsentUi, only after a gesture, only an ask scope. */
|
|
26
|
+
export declare function grantWrite(manifest: readonly ManifestEntry[], grants: Grants, write: {
|
|
27
|
+
via: GrantVia;
|
|
28
|
+
gesture: boolean;
|
|
29
|
+
scope: string;
|
|
30
|
+
value: GrantValue | null;
|
|
31
|
+
}): {
|
|
32
|
+
grants: Grants;
|
|
33
|
+
refused: string | null;
|
|
34
|
+
};
|
|
35
|
+
/** The Vault key and canonical JSON value of an app's grants. */
|
|
36
|
+
export declare function grantsRecord(app: string, signer: string, manifest: readonly ManifestEntry[], grants: Grants): {
|
|
37
|
+
key: string;
|
|
38
|
+
value: string;
|
|
39
|
+
};
|
|
40
|
+
/** The grants that survive a package load (`stored` = the Vault value, or null). */
|
|
41
|
+
export declare function grantsOnPackage(stored: string | null, signer: string, manifest: readonly ManifestEntry[]): Grants;
|
|
42
|
+
/** The ask sheet for one manifest entry: the surface's components and data. */
|
|
43
|
+
export declare function consentSheet(app: string, entry: ManifestEntry): {
|
|
44
|
+
components: SurfaceComponent[];
|
|
45
|
+
data: {
|
|
46
|
+
answer: ConsentAnswer;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
/** The Permissions sheet: one Switch per declared ask scope, in manifest order. */
|
|
50
|
+
export declare function manageSheet(manifest: readonly ManifestEntry[], grants: Grants): SurfaceComponent[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./capabilities.js";
|
|
2
|
+
export * from "./consent.js";
|
|
3
|
+
export * from "./lifecycle.js";
|
|
4
|
+
export * from "./providers.js";
|
|
5
|
+
export * from "./outbox.js";
|
|
6
|
+
export * from "./tools.js";
|
|
7
|
+
export * from "./pdf.js";
|
|
8
|
+
export * from "./runner.js";
|
|
9
|
+
export * from "./broker.js";
|
|
10
|
+
export * from "./stores.js";
|
|
11
|
+
export * from "./instance.js";
|
|
12
|
+
export * from "./synced.js";
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { type PackageIssue, type RecordsValue } from "@exponential_app/eui/host";
|
|
2
|
+
import { Broker, type CallAudit, type ConsentSheet, type Failure, type Vault } from "./broker.js";
|
|
3
|
+
import type { BrokerVerdict, Grants, GrantValue, ManifestEntry } from "./capabilities.js";
|
|
4
|
+
import { type ConsentAnswer, type GrantVia, type SurfaceComponent } from "./consent.js";
|
|
5
|
+
import { type LifecycleEffect, type LifecycleEvent, type LifecycleState } from "./lifecycle.js";
|
|
6
|
+
import { type OutboxCall, type OutboxEntry, type OutboxResult } from "./outbox.js";
|
|
7
|
+
import { type EngineIdentity, type NetworkPolicy } from "./providers.js";
|
|
8
|
+
import type { EngineRecordStore, WriteBatch } from "./stores.js";
|
|
9
|
+
import type { BlobStore, NativeCapability } from "./tools.js";
|
|
10
|
+
export type Presentation = `replace` | `push` | `sheet`;
|
|
11
|
+
/** Maps screens to windows (desktop), nav stacks and sheets (phones), the page (the web). */
|
|
12
|
+
export interface WindowHost {
|
|
13
|
+
open(app: string, screen: string, params: Record<string, string>, how: Presentation): void;
|
|
14
|
+
}
|
|
15
|
+
/** An optional transport to an authority; absent = the store is the authority, no outbox. */
|
|
16
|
+
export interface SyncTransport {
|
|
17
|
+
push(app: string, call: OutboxCall, input: Record<string, unknown>): Promise<OutboxResult>;
|
|
18
|
+
/** `push` with the server's answer, for a call that awaits its own entry. */
|
|
19
|
+
send?(app: string, call: OutboxCall, input: Record<string, unknown>): Promise<Pushed>;
|
|
20
|
+
}
|
|
21
|
+
/** One replay as a transport answers it. */
|
|
22
|
+
export interface Pushed {
|
|
23
|
+
result: OutboxResult;
|
|
24
|
+
answer?: unknown;
|
|
25
|
+
message?: string;
|
|
26
|
+
invalid?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** What a host hands the Engine (providers.json; no telemetry or update key: none exists). */
|
|
29
|
+
export interface EngineHostConfig {
|
|
30
|
+
host: {
|
|
31
|
+
kind: string;
|
|
32
|
+
platform: string;
|
|
33
|
+
formFactor: string;
|
|
34
|
+
locale: string;
|
|
35
|
+
};
|
|
36
|
+
storage: EngineRecordStore;
|
|
37
|
+
blobs: BlobStore;
|
|
38
|
+
identity: EngineIdentity;
|
|
39
|
+
vault: Vault;
|
|
40
|
+
window: WindowHost;
|
|
41
|
+
/** ISO 8601 UTC with milliseconds (tests pin it). */
|
|
42
|
+
clock?: () => string;
|
|
43
|
+
network: NetworkPolicy;
|
|
44
|
+
sync?: SyncTransport | null;
|
|
45
|
+
capabilities: readonly NativeCapability[];
|
|
46
|
+
audit?: CallAudit | null;
|
|
47
|
+
newId?: () => string;
|
|
48
|
+
}
|
|
49
|
+
/** Why a package could not load: `signature` (signed, does not verify) or `invalid` (genUI refuses it). */
|
|
50
|
+
export declare class LoadError extends Error {
|
|
51
|
+
readonly kind: `signature` | `invalid`;
|
|
52
|
+
readonly issues: PackageIssue[];
|
|
53
|
+
constructor(kind: `signature` | `invalid`, issues: PackageIssue[]);
|
|
54
|
+
}
|
|
55
|
+
/** What a host function call answers. */
|
|
56
|
+
export type CallResult = {
|
|
57
|
+
value: unknown;
|
|
58
|
+
}
|
|
59
|
+
/** The person decides first: paint the sheet, then `answerConsent` with the same call. */
|
|
60
|
+
| {
|
|
61
|
+
ask: BrokerVerdict;
|
|
62
|
+
sheet: ConsentSheet;
|
|
63
|
+
}
|
|
64
|
+
/** Refused (the failed-action toast's reason). */
|
|
65
|
+
| {
|
|
66
|
+
refused: Failure;
|
|
67
|
+
};
|
|
68
|
+
/** Where the instance keeps its last screen (lifecycle.json `persist`). */
|
|
69
|
+
export declare const screenKey: (app: string) => string;
|
|
70
|
+
type Pkg = Record<string, unknown> & {
|
|
71
|
+
id?: unknown;
|
|
72
|
+
name?: unknown;
|
|
73
|
+
records?: unknown;
|
|
74
|
+
capabilities?: unknown;
|
|
75
|
+
screens?: unknown;
|
|
76
|
+
};
|
|
77
|
+
/** The package a file carries (`package`), or the value itself when it is a bare package. */
|
|
78
|
+
export declare const packageOf: (file: unknown) => unknown;
|
|
79
|
+
/** One running app. */
|
|
80
|
+
export declare class AppInstance {
|
|
81
|
+
private readonly config;
|
|
82
|
+
readonly pkg: Pkg;
|
|
83
|
+
readonly appId: string;
|
|
84
|
+
readonly signer: string | null;
|
|
85
|
+
readonly broker: Broker;
|
|
86
|
+
private stateNow;
|
|
87
|
+
private outboxNow;
|
|
88
|
+
private lastScreen;
|
|
89
|
+
private constructor();
|
|
90
|
+
/** Load a package file (or a bare package): verify its signature when it
|
|
91
|
+
* carries one, validate the package, reconcile its grants. */
|
|
92
|
+
static load(config: EngineHostConfig, file: unknown): Promise<AppInstance>;
|
|
93
|
+
get manifest(): readonly ManifestEntry[];
|
|
94
|
+
grants(): Grants;
|
|
95
|
+
get state(): LifecycleState;
|
|
96
|
+
/** The outbox entries still pending or acked (queue mode). */
|
|
97
|
+
get outbox(): readonly OutboxEntry[];
|
|
98
|
+
get mode(): `queue` | `direct`;
|
|
99
|
+
private me;
|
|
100
|
+
private now;
|
|
101
|
+
/** The person answered the sheet of an Ask for this call (the answer is the gesture). */
|
|
102
|
+
answerConsent(name: string, args: unknown, verdict: BrokerVerdict, answer: ConsentAnswer): Promise<CallResult>;
|
|
103
|
+
/** The Permissions sheet's Switch: only the ConsentUi, after a gesture. Answers the refusal, or null. */
|
|
104
|
+
setGrant(via: GrantVia, gesture: boolean, scope: string, value: GrantValue | null): string | null;
|
|
105
|
+
/** The Permissions sheet (a genUI surface). */
|
|
106
|
+
permissionsSheet(): SurfaceComponent[];
|
|
107
|
+
/** One lifecycle event: the next state, with its effects carried out
|
|
108
|
+
* (open → the WindowHost, persist → the Vault, flush → the outbox).
|
|
109
|
+
* Answers the effects (sources and automations are the host's). */
|
|
110
|
+
event(event: LifecycleEvent): Promise<LifecycleEffect[]>;
|
|
111
|
+
/** A `records:<kind>?…` source's value (genUI's records query over the
|
|
112
|
+
* store's rows with the outbox laid over them); undefined = not a records source. */
|
|
113
|
+
recordsValue(source: string): Promise<RecordsValue | null | undefined>;
|
|
114
|
+
/** Called with every change to the app's rows (re-resolve the bound sources). */
|
|
115
|
+
subscribe(on: () => void): () => void;
|
|
116
|
+
/** A host function call from the app's UI: `records_upsert` /
|
|
117
|
+
* `records_delete` / `records_batch`, `app_navigate`, or a capability
|
|
118
|
+
* (`<capability>.<tool>`, through the broker). `newIds` = the client ids of
|
|
119
|
+
* its creates, in order. */
|
|
120
|
+
call(name: string, args: unknown, newIds?: readonly string[]): Promise<CallResult>;
|
|
121
|
+
/** The kind policy check for a write, as the identity sees it. */
|
|
122
|
+
private refusal;
|
|
123
|
+
private write;
|
|
124
|
+
/** Flush the outbox through the sync provider (FIFO, a retry stops it). */
|
|
125
|
+
flush(): Promise<void>;
|
|
126
|
+
}
|
|
127
|
+
/** An outbox entry as one store batch. */
|
|
128
|
+
export declare function batchOf(entry: OutboxEntry): WriteBatch;
|
|
129
|
+
/** How many client ids a call's creates take (the runner generates them). */
|
|
130
|
+
export declare function createsOf(name: string, args: unknown): number;
|
|
131
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type LifecyclePhase = `stopped` | `foreground` | `background`;
|
|
2
|
+
export interface LifecycleState {
|
|
3
|
+
phase: LifecyclePhase;
|
|
4
|
+
screen: string | null;
|
|
5
|
+
params: Record<string, string> | null;
|
|
6
|
+
}
|
|
7
|
+
export type LifecycleEvent = {
|
|
8
|
+
type: `launch`;
|
|
9
|
+
} | {
|
|
10
|
+
type: `foreground`;
|
|
11
|
+
} | {
|
|
12
|
+
type: `background`;
|
|
13
|
+
} | {
|
|
14
|
+
type: `terminate`;
|
|
15
|
+
} | {
|
|
16
|
+
type: `online`;
|
|
17
|
+
} | {
|
|
18
|
+
type: `deepLink`;
|
|
19
|
+
screen?: string | null;
|
|
20
|
+
params?: Record<string, unknown> | null;
|
|
21
|
+
} | {
|
|
22
|
+
type: `notificationTap`;
|
|
23
|
+
app: string;
|
|
24
|
+
screen?: string | null;
|
|
25
|
+
params?: Record<string, unknown> | null;
|
|
26
|
+
};
|
|
27
|
+
export type LifecycleEffect = {
|
|
28
|
+
effect: `open`;
|
|
29
|
+
screen: string;
|
|
30
|
+
params: Record<string, string>;
|
|
31
|
+
} | {
|
|
32
|
+
effect: `flush`;
|
|
33
|
+
} | {
|
|
34
|
+
effect: `sources`;
|
|
35
|
+
live: boolean;
|
|
36
|
+
} | {
|
|
37
|
+
effect: `automations`;
|
|
38
|
+
on: boolean;
|
|
39
|
+
} | {
|
|
40
|
+
effect: `persist`;
|
|
41
|
+
screen: string;
|
|
42
|
+
params: Record<string, string>;
|
|
43
|
+
} | {
|
|
44
|
+
effect: `refused`;
|
|
45
|
+
reason: string;
|
|
46
|
+
};
|
|
47
|
+
export interface LifecyclePackage {
|
|
48
|
+
id: string;
|
|
49
|
+
screens?: unknown;
|
|
50
|
+
}
|
|
51
|
+
export interface LifecycleContext {
|
|
52
|
+
pkg: LifecyclePackage;
|
|
53
|
+
/** The screen the instance persisted last (null = none). */
|
|
54
|
+
lastScreen: {
|
|
55
|
+
screen: string;
|
|
56
|
+
params: Record<string, unknown>;
|
|
57
|
+
} | null;
|
|
58
|
+
}
|
|
59
|
+
export declare const STOPPED: LifecycleState;
|
|
60
|
+
/** One lifecycle event → the next state and its effects, in order. */
|
|
61
|
+
export declare function lifecycleStep(state: LifecycleState, event: LifecycleEvent, cx: LifecycleContext): {
|
|
62
|
+
state: LifecycleState;
|
|
63
|
+
effects: LifecycleEffect[];
|
|
64
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { outboxFlush, outboxOutcome, outboxPendingLabel, outboxPrune, outboxReflected, outboxRequest, outboxRows, outboxVerb, outboxWrites, type OutboxCall, type OutboxEntry, type OutboxOutcome, type OutboxResult, type OutboxWrite, } from "../../domain-contract/src/app-records.js";
|
|
2
|
+
/** A host with a sync provider queues every app write; one without writes through. */
|
|
3
|
+
export declare const outboxMode: (hasSync: boolean) => `queue` | `direct`;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type PdfBlock = {
|
|
2
|
+
heading: string;
|
|
3
|
+
} | {
|
|
4
|
+
text: string;
|
|
5
|
+
} | {
|
|
6
|
+
image: string;
|
|
7
|
+
caption?: string;
|
|
8
|
+
} | {
|
|
9
|
+
pageBreak: true;
|
|
10
|
+
};
|
|
11
|
+
export interface PdfArguments {
|
|
12
|
+
title: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
blocks: readonly PdfBlock[];
|
|
15
|
+
}
|
|
16
|
+
export type PdfResult = {
|
|
17
|
+
bytes: Uint8Array;
|
|
18
|
+
pages: number;
|
|
19
|
+
} | {
|
|
20
|
+
error: string;
|
|
21
|
+
};
|
|
22
|
+
/** A paragraph per `\n`, words on runs of spaces, greedy; a too-wide word breaks at its longest fitting prefix. */
|
|
23
|
+
export declare function wrapLines(text: string, font: `F1` | `F2`, size: number): number[][];
|
|
24
|
+
/** A number rounded to 2 decimals, shortest form (`12`, `12.5`, `-0.25`). */
|
|
25
|
+
export declare function pdfNumber(x: number): string;
|
|
26
|
+
interface PdfImage {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
dict: string;
|
|
30
|
+
data: Uint8Array;
|
|
31
|
+
}
|
|
32
|
+
/** A JPEG or a supported PNG → its XObject, else null. */
|
|
33
|
+
export declare function pdfImage(bytes: Uint8Array): PdfImage | null;
|
|
34
|
+
/** Lays out and writes the document. `getBlob` resolves an app file id. */
|
|
35
|
+
export declare function renderPdf(args: PdfArguments, getBlob: (id: string) => Promise<Uint8Array | null>): Promise<PdfResult>;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type RecordOp, type RecordOwnership, type RecordPolicy, type RecordViewer } from "@exponential_app/eui/host";
|
|
2
|
+
import fixture from "../fixtures/providers.json" with { type: "json" };
|
|
3
|
+
export type ProviderKey = keyof typeof fixture.providers;
|
|
4
|
+
export type NetworkPolicy = `off` | `upstreamsOnly` | `any`;
|
|
5
|
+
export type IdentityKind = `member` | `local` | `peer`;
|
|
6
|
+
export type AgentProviderId = `acp` | `localModel` | `remoteSession`;
|
|
7
|
+
export declare const PROVIDER_KEYS: ProviderKey[];
|
|
8
|
+
export declare const FORBIDDEN_HOST_KEYS: readonly string[];
|
|
9
|
+
export declare const NETWORK_POLICIES: readonly NetworkPolicy[];
|
|
10
|
+
export declare const IDENTITY_KINDS: readonly IdentityKind[];
|
|
11
|
+
export declare const AGENT_PROVIDERS: readonly AgentProviderId[];
|
|
12
|
+
export interface HostConfigIssue {
|
|
13
|
+
key: string;
|
|
14
|
+
code: `missing` | `forbidden` | `unknown` | `invalid` | `duplicateAgent` | `duplicateCapability` | `invalidCapability`;
|
|
15
|
+
}
|
|
16
|
+
/** Every problem with a host config: providers in order, then forbidden/unknown keys sorted. */
|
|
17
|
+
export declare function validateHostConfig(config: Record<string, unknown>): HostConfigIssue[];
|
|
18
|
+
export type EngineIdentity = {
|
|
19
|
+
kind: `member`;
|
|
20
|
+
userId: string;
|
|
21
|
+
role: string | null;
|
|
22
|
+
access?: `none` | `read` | `write`;
|
|
23
|
+
} | {
|
|
24
|
+
kind: `local`;
|
|
25
|
+
deviceId: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: `peer`;
|
|
28
|
+
key: string;
|
|
29
|
+
};
|
|
30
|
+
/** The records viewer of an identity: local = the one owner of everything ("me"). */
|
|
31
|
+
export declare function engineViewer(identity: EngineIdentity): Required<RecordViewer>;
|
|
32
|
+
/** Why the viewer of `identity` may not `op` (null = allowed). */
|
|
33
|
+
export declare const engineRecordRefusal: (identity: EngineIdentity, policy: RecordPolicy, op: RecordOp, row?: RecordOwnership | null) => string | null;
|
|
34
|
+
/** May the instance reach `target` under `policy`? `declared` = the package declares the upstream (or the origin). */
|
|
35
|
+
export declare function networkAllows(policy: NetworkPolicy, target: `upstream` | `sync` | `http`, declared: boolean): {
|
|
36
|
+
allowed: boolean;
|
|
37
|
+
reason: string | null;
|
|
38
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { SurfaceComponent } from "./consent.js";
|
|
2
|
+
import type { NetworkPolicy } from "./providers.js";
|
|
3
|
+
export declare const RUNNER_COPY: {
|
|
4
|
+
permissions: string;
|
|
5
|
+
failed: {
|
|
6
|
+
title: string;
|
|
7
|
+
missing: string;
|
|
8
|
+
config: string;
|
|
9
|
+
signature: string;
|
|
10
|
+
invalid: string;
|
|
11
|
+
busy: string;
|
|
12
|
+
};
|
|
13
|
+
refusals: {
|
|
14
|
+
consentDenied: string;
|
|
15
|
+
consentDismissed: string;
|
|
16
|
+
consentNeeded: string;
|
|
17
|
+
notDeclared: string;
|
|
18
|
+
originNotDeclared: string;
|
|
19
|
+
unavailable: string;
|
|
20
|
+
offline: string;
|
|
21
|
+
network: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export declare const RUNNER_BUNDLE: {
|
|
25
|
+
dir: string;
|
|
26
|
+
files: {
|
|
27
|
+
package: string;
|
|
28
|
+
config: string;
|
|
29
|
+
};
|
|
30
|
+
locations: {
|
|
31
|
+
macos: string;
|
|
32
|
+
windows: string;
|
|
33
|
+
linux: string;
|
|
34
|
+
android: string;
|
|
35
|
+
ios: string;
|
|
36
|
+
web: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export declare const RUNNER_SHELL: {
|
|
40
|
+
sidebarWidth: number;
|
|
41
|
+
titleLevel: string;
|
|
42
|
+
permissionsIcon: string;
|
|
43
|
+
failureIcon: string;
|
|
44
|
+
};
|
|
45
|
+
export type FormFactor = `wide` | `compact`;
|
|
46
|
+
export type RunnerFailure = `missing` | `config` | `signature` | `invalid` | `busy`;
|
|
47
|
+
/** A bundle's `runner.json`, validated. */
|
|
48
|
+
export interface RunnerConfig {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
version: string;
|
|
52
|
+
network: NetworkPolicy;
|
|
53
|
+
}
|
|
54
|
+
export interface RunnerConfigIssue {
|
|
55
|
+
key: string;
|
|
56
|
+
code: string;
|
|
57
|
+
}
|
|
58
|
+
/** `runner.json` → the config (absent optional keys = their default) and its issues, in key order then the extra keys sorted. */
|
|
59
|
+
export declare function runnerConfig(input: unknown): {
|
|
60
|
+
config: RunnerConfig | null;
|
|
61
|
+
issues: RunnerConfigIssue[];
|
|
62
|
+
};
|
|
63
|
+
type Pkg = Record<string, unknown> & {
|
|
64
|
+
name?: unknown;
|
|
65
|
+
templates?: unknown;
|
|
66
|
+
screens?: unknown;
|
|
67
|
+
capabilities?: unknown;
|
|
68
|
+
};
|
|
69
|
+
/** Does the package declare an `ask` scope (the shell then offers Permissions)? */
|
|
70
|
+
export declare function runnerHasPermissions(pkg: Pkg): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* The package the runner's painter installs: every screen's template wrapped
|
|
73
|
+
* in the shell for `formFactor`. A package without screens gets one, its first
|
|
74
|
+
* template. The Engine keeps the ORIGINAL package (its signature, its grants);
|
|
75
|
+
* only the painter sees this one.
|
|
76
|
+
*/
|
|
77
|
+
export declare function runnerPackage(pkg: Pkg, formFactor: FormFactor): Pkg;
|
|
78
|
+
/** What the runner paints instead of the app when its bundle cannot load. */
|
|
79
|
+
export declare function runnerFailure(kind: RunnerFailure): SurfaceComponent[];
|
|
80
|
+
/** The failed-action toast (a refused call, a refused link): surface `toast`; a broker reason code reads as `copy.refusals`. */
|
|
81
|
+
export declare function runnerToast(message: string): SurfaceComponent[];
|
|
82
|
+
export {};
|