@ateam-ai-mobile/plugin-runtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1129 -0
- package/dist/index.d.ts +1129 -0
- package/dist/index.js +2388 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2369 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +31 -0
- package/src/api/plugins.ts +257 -0
- package/src/bridge/native.ts +266 -0
- package/src/bridge/types.ts +268 -0
- package/src/bundles/bundleManager.ts +396 -0
- package/src/bundles/storage.ts +68 -0
- package/src/hooks/usePlugin.ts +185 -0
- package/src/hooks/useRemotePlugins.ts +97 -0
- package/src/host.ts +117 -0
- package/src/index.ts +79 -0
- package/src/registry/SurfaceDispatcher.tsx +66 -0
- package/src/registry/store.ts +131 -0
- package/src/registry/types.ts +60 -0
- package/src/sdk/components.ts +370 -0
- package/src/sdk/index.ts +76 -0
- package/src/sdk/primitives.ts +22 -0
- package/src/sdk/registration.ts +52 -0
- package/src/sdk/types.ts +315 -0
- package/src/sdk/useApi.ts +78 -0
- package/src/sdk/usePluginTheme.ts +86 -0
- package/src/surfaces/AdaOrb.tsx +318 -0
- package/src/surfaces/SurfaceCard.tsx +137 -0
- package/src/surfaces/SurfaceDrawer.tsx +216 -0
- package/src/surfaces/SurfaceFullscreen.tsx +207 -0
- package/src/utils/sha256.ts +85 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1129 @@
|
|
|
1
|
+
import React$1, { MutableRefObject, ReactNode, ComponentType } from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import * as zustand from 'zustand';
|
|
4
|
+
import * as react_native from 'react-native';
|
|
5
|
+
import { View, TextInput } from 'react-native';
|
|
6
|
+
export { ActivityIndicator, Animated, FlatList, Image, Modal, Platform, Pressable, RefreshControl, ScrollView, SectionList, StyleSheet, Switch, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @adas/plugin-sdk — Type definitions
|
|
10
|
+
*
|
|
11
|
+
* This is the developer contract for native mobile plugins.
|
|
12
|
+
* Both UI and service plugins use these interfaces.
|
|
13
|
+
*/
|
|
14
|
+
interface PluginContext {
|
|
15
|
+
tenant: string;
|
|
16
|
+
pluginId: string;
|
|
17
|
+
connectorId?: string;
|
|
18
|
+
user?: {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
roles: string[];
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface PluginBridge {
|
|
25
|
+
/** Wait for host initialization */
|
|
26
|
+
onInit(cb: (ctx: PluginContext) => void): void;
|
|
27
|
+
/** Call an MCP tool on any connector */
|
|
28
|
+
mcpCall(tool: string, args: any, connectorId?: string): Promise<any>;
|
|
29
|
+
/** Raw JSON-RPC to /mcp endpoint */
|
|
30
|
+
mcpFetch(body: any): Promise<any>;
|
|
31
|
+
/** Send a command to the host */
|
|
32
|
+
sendCommand(type: string, payload: any): void;
|
|
33
|
+
/** Listen for commands from the host */
|
|
34
|
+
onCommand(cb: (type: string, payload: any) => void): () => void;
|
|
35
|
+
/** Close this plugin and return to chat */
|
|
36
|
+
close(): void;
|
|
37
|
+
/** Post a message into the user's chat thread, exactly as if the user
|
|
38
|
+
* typed it. Use for confirmed user actions (e.g. "Connect Gmail" with
|
|
39
|
+
* an approval modal) that should kick off a flow the orchestrator
|
|
40
|
+
* already knows how to handle. Pair with `close()` to land the user on
|
|
41
|
+
* the chat screen so they see Ada working on it. */
|
|
42
|
+
sendMessage(text: string): void;
|
|
43
|
+
/** Pre-fill the chat composer with `text` without sending. The user lands
|
|
44
|
+
* on chat with the text already typed and the input focused, so they can
|
|
45
|
+
* edit/review before tapping send. Use for "draft a message about X"
|
|
46
|
+
* flows where you want the user to review before committing. Pair with
|
|
47
|
+
* `close()` to dismiss the plugin surface. */
|
|
48
|
+
prepareMessage(text: string): void;
|
|
49
|
+
}
|
|
50
|
+
interface CameraAPI {
|
|
51
|
+
takePhoto(opts?: {
|
|
52
|
+
quality?: number;
|
|
53
|
+
facing?: 'front' | 'back';
|
|
54
|
+
}): Promise<{
|
|
55
|
+
uri: string;
|
|
56
|
+
width: number;
|
|
57
|
+
height: number;
|
|
58
|
+
}>;
|
|
59
|
+
scanBarcode(opts?: {
|
|
60
|
+
formats?: string[];
|
|
61
|
+
}): Promise<{
|
|
62
|
+
data: string;
|
|
63
|
+
format: string;
|
|
64
|
+
}>;
|
|
65
|
+
pickImage(opts?: {
|
|
66
|
+
multiple?: boolean;
|
|
67
|
+
}): Promise<{
|
|
68
|
+
uri: string;
|
|
69
|
+
}[]>;
|
|
70
|
+
}
|
|
71
|
+
interface LocationAPI {
|
|
72
|
+
getCurrent(opts?: {
|
|
73
|
+
accuracy?: 'low' | 'high';
|
|
74
|
+
}): Promise<{
|
|
75
|
+
latitude: number;
|
|
76
|
+
longitude: number;
|
|
77
|
+
altitude?: number;
|
|
78
|
+
}>;
|
|
79
|
+
watchPosition(cb: (pos: {
|
|
80
|
+
latitude: number;
|
|
81
|
+
longitude: number;
|
|
82
|
+
}) => void): () => void;
|
|
83
|
+
}
|
|
84
|
+
interface StorageAPI {
|
|
85
|
+
get(key: string): Promise<string | null>;
|
|
86
|
+
set(key: string, value: string): Promise<void>;
|
|
87
|
+
delete(key: string): Promise<void>;
|
|
88
|
+
db: {
|
|
89
|
+
execute(sql: string, params?: any[]): Promise<{
|
|
90
|
+
rows: any[];
|
|
91
|
+
changes: number;
|
|
92
|
+
}>;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
interface BiometricsAPI {
|
|
96
|
+
isAvailable(): Promise<boolean>;
|
|
97
|
+
authenticate(opts: {
|
|
98
|
+
reason: string;
|
|
99
|
+
}): Promise<{
|
|
100
|
+
success: boolean;
|
|
101
|
+
}>;
|
|
102
|
+
}
|
|
103
|
+
interface NotificationsAPI {
|
|
104
|
+
schedule(opts: {
|
|
105
|
+
title: string;
|
|
106
|
+
body: string;
|
|
107
|
+
trigger: {
|
|
108
|
+
seconds?: number;
|
|
109
|
+
date?: string;
|
|
110
|
+
};
|
|
111
|
+
}): Promise<string>;
|
|
112
|
+
cancel(id: string): Promise<void>;
|
|
113
|
+
onReceived(cb: (notification: {
|
|
114
|
+
id: string;
|
|
115
|
+
title: string;
|
|
116
|
+
body: string;
|
|
117
|
+
data?: any;
|
|
118
|
+
}) => void): () => void;
|
|
119
|
+
}
|
|
120
|
+
interface HapticsAPI {
|
|
121
|
+
impact(style: 'light' | 'medium' | 'heavy'): void;
|
|
122
|
+
notification(type: 'success' | 'warning' | 'error'): void;
|
|
123
|
+
selection(): void;
|
|
124
|
+
}
|
|
125
|
+
interface ConnectivityAPI {
|
|
126
|
+
isOnline(): boolean;
|
|
127
|
+
onChange(cb: (online: boolean) => void): () => void;
|
|
128
|
+
}
|
|
129
|
+
interface FileSystemAPI {
|
|
130
|
+
readFile(path: string): Promise<string>;
|
|
131
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
132
|
+
pickDocument(opts?: {
|
|
133
|
+
types?: string[];
|
|
134
|
+
}): Promise<{
|
|
135
|
+
uri: string;
|
|
136
|
+
name: string;
|
|
137
|
+
size: number;
|
|
138
|
+
}>;
|
|
139
|
+
}
|
|
140
|
+
interface WebViewCookie {
|
|
141
|
+
name: string;
|
|
142
|
+
value: string;
|
|
143
|
+
domain?: string;
|
|
144
|
+
path?: string;
|
|
145
|
+
expires?: number;
|
|
146
|
+
httpOnly?: boolean;
|
|
147
|
+
secure?: boolean;
|
|
148
|
+
sameSite?: 'Lax' | 'Strict' | 'None';
|
|
149
|
+
}
|
|
150
|
+
interface CookiesAPI {
|
|
151
|
+
/** Get all cookies attached to a URL's effective domain. */
|
|
152
|
+
get(url: string): Promise<WebViewCookie[]>;
|
|
153
|
+
/** Clear cookies for a domain (e.g. to force re-login). */
|
|
154
|
+
clear(url: string): Promise<{
|
|
155
|
+
ok: boolean;
|
|
156
|
+
}>;
|
|
157
|
+
}
|
|
158
|
+
interface SharingAPI {
|
|
159
|
+
/** Is the share sheet available on this device? */
|
|
160
|
+
isAvailable(): Promise<boolean>;
|
|
161
|
+
/** Share a local file URI via the OS share sheet. */
|
|
162
|
+
shareFile(fileUri: string, opts?: {
|
|
163
|
+
mimeType?: string;
|
|
164
|
+
UTI?: string;
|
|
165
|
+
dialogTitle?: string;
|
|
166
|
+
}): Promise<{
|
|
167
|
+
ok: boolean;
|
|
168
|
+
error?: string;
|
|
169
|
+
}>;
|
|
170
|
+
}
|
|
171
|
+
interface ScannerAPI {
|
|
172
|
+
/** Prompt the user for camera permission. */
|
|
173
|
+
requestPermissions(): Promise<{
|
|
174
|
+
granted: boolean;
|
|
175
|
+
status: string;
|
|
176
|
+
}>;
|
|
177
|
+
}
|
|
178
|
+
interface NfcNdefRecord {
|
|
179
|
+
type: string;
|
|
180
|
+
payload: string;
|
|
181
|
+
}
|
|
182
|
+
interface NfcAPI {
|
|
183
|
+
/** Is NFC hardware present? */
|
|
184
|
+
isSupported(): Promise<boolean>;
|
|
185
|
+
/** Is NFC turned on? (Android has a toggle; iOS always enabled when supported.) */
|
|
186
|
+
isEnabled(): Promise<boolean>;
|
|
187
|
+
/** Read the next NFC tag presented to the device within the timeout. */
|
|
188
|
+
readOnce(timeoutMs?: number): Promise<{
|
|
189
|
+
ok: boolean;
|
|
190
|
+
tagId?: string;
|
|
191
|
+
records?: NfcNdefRecord[];
|
|
192
|
+
error?: string;
|
|
193
|
+
}>;
|
|
194
|
+
}
|
|
195
|
+
interface BiometricsAPIv2 {
|
|
196
|
+
/** What can this device do right now? */
|
|
197
|
+
capabilities(): Promise<{
|
|
198
|
+
hasHardware: boolean;
|
|
199
|
+
isEnrolled: boolean;
|
|
200
|
+
supportedTypes: Array<'fingerprint' | 'face' | 'iris'>;
|
|
201
|
+
}>;
|
|
202
|
+
/** Prompt the user. Resolves { success } or { success:false, error }. */
|
|
203
|
+
authenticate(opts: {
|
|
204
|
+
reason: string;
|
|
205
|
+
cancelLabel?: string;
|
|
206
|
+
fallbackToPasscode?: boolean;
|
|
207
|
+
}): Promise<{
|
|
208
|
+
success: boolean;
|
|
209
|
+
error?: string;
|
|
210
|
+
}>;
|
|
211
|
+
}
|
|
212
|
+
interface PluginNative {
|
|
213
|
+
camera: CameraAPI;
|
|
214
|
+
location: LocationAPI;
|
|
215
|
+
storage: StorageAPI;
|
|
216
|
+
/** @deprecated use `biometricsV2` for the native-backed API. This stub
|
|
217
|
+
* remains for backwards compatibility. */
|
|
218
|
+
biometrics: BiometricsAPI;
|
|
219
|
+
biometricsV2: BiometricsAPIv2;
|
|
220
|
+
notifications: NotificationsAPI;
|
|
221
|
+
haptics: HapticsAPI;
|
|
222
|
+
connectivity: ConnectivityAPI;
|
|
223
|
+
fileSystem: FileSystemAPI;
|
|
224
|
+
cookies: CookiesAPI;
|
|
225
|
+
sharing: SharingAPI;
|
|
226
|
+
scanner: ScannerAPI;
|
|
227
|
+
nfc: NfcAPI;
|
|
228
|
+
}
|
|
229
|
+
interface NativeCapabilities$1 {
|
|
230
|
+
camera?: boolean;
|
|
231
|
+
location?: boolean;
|
|
232
|
+
biometrics?: boolean;
|
|
233
|
+
offline?: boolean;
|
|
234
|
+
backgroundTasks?: boolean;
|
|
235
|
+
fileSystem?: boolean;
|
|
236
|
+
notifications?: boolean;
|
|
237
|
+
bluetooth?: boolean;
|
|
238
|
+
haptics?: boolean;
|
|
239
|
+
/** Read the platform cookie jar after a WebView login flow. */
|
|
240
|
+
cookies?: boolean;
|
|
241
|
+
/** Render a native WebView (the plugin uses react-native-webview directly). */
|
|
242
|
+
webview?: boolean;
|
|
243
|
+
/** Native share sheet. */
|
|
244
|
+
sharing?: boolean;
|
|
245
|
+
/** Camera-based QR / barcode scanning. */
|
|
246
|
+
scanner?: boolean;
|
|
247
|
+
/** NFC tag reading (iOS entitlement + Android permission required). */
|
|
248
|
+
nfc?: boolean;
|
|
249
|
+
/** Real biometric auth (Face ID / Touch ID / fingerprint). */
|
|
250
|
+
biometricsV2?: boolean;
|
|
251
|
+
}
|
|
252
|
+
interface PluginHooks$1 {
|
|
253
|
+
onAppStart?: boolean;
|
|
254
|
+
onPushReceived?: boolean;
|
|
255
|
+
onConnectivity?: boolean;
|
|
256
|
+
onForeground?: boolean;
|
|
257
|
+
onBackground?: boolean;
|
|
258
|
+
}
|
|
259
|
+
interface ThemeTokens {
|
|
260
|
+
colors: {
|
|
261
|
+
bg: string;
|
|
262
|
+
surface: string;
|
|
263
|
+
surfaceAlt: string;
|
|
264
|
+
input: string;
|
|
265
|
+
border: string;
|
|
266
|
+
text: string;
|
|
267
|
+
textSecondary: string;
|
|
268
|
+
textMuted: string;
|
|
269
|
+
accent: string;
|
|
270
|
+
accentSoft: string;
|
|
271
|
+
success: string;
|
|
272
|
+
successSoft: string;
|
|
273
|
+
warning: string;
|
|
274
|
+
warningSoft: string;
|
|
275
|
+
error: string;
|
|
276
|
+
errorSoft: string;
|
|
277
|
+
purple: string;
|
|
278
|
+
purpleSoft: string;
|
|
279
|
+
};
|
|
280
|
+
spacing: {
|
|
281
|
+
xs: number;
|
|
282
|
+
sm: number;
|
|
283
|
+
md: number;
|
|
284
|
+
lg: number;
|
|
285
|
+
xl: number;
|
|
286
|
+
xxl: number;
|
|
287
|
+
};
|
|
288
|
+
fontSize: {
|
|
289
|
+
xs: number;
|
|
290
|
+
sm: number;
|
|
291
|
+
md: number;
|
|
292
|
+
lg: number;
|
|
293
|
+
xl: number;
|
|
294
|
+
};
|
|
295
|
+
borderRadius: {
|
|
296
|
+
sm: number;
|
|
297
|
+
md: number;
|
|
298
|
+
lg: number;
|
|
299
|
+
full: number;
|
|
300
|
+
};
|
|
301
|
+
isDark: boolean;
|
|
302
|
+
}
|
|
303
|
+
interface PluginProps {
|
|
304
|
+
bridge: PluginBridge;
|
|
305
|
+
native: PluginNative;
|
|
306
|
+
theme: ThemeTokens;
|
|
307
|
+
context: PluginContext;
|
|
308
|
+
/** Engine-supplied props from `sys.focusUiPlugin(pluginId, props)`.
|
|
309
|
+
* Plugins read these on first mount to support flows like "open with the
|
|
310
|
+
* add modal pre-shown" or "prefill text X". Undefined when the plugin was
|
|
311
|
+
* opened by the user (no props from engine). */
|
|
312
|
+
props?: any;
|
|
313
|
+
}
|
|
314
|
+
type RenderMode = {
|
|
315
|
+
mode: 'iframe';
|
|
316
|
+
iframeUrl: string;
|
|
317
|
+
external?: boolean;
|
|
318
|
+
} | {
|
|
319
|
+
mode: 'react-native';
|
|
320
|
+
component: string;
|
|
321
|
+
bundleId?: string;
|
|
322
|
+
bundleUrl?: string;
|
|
323
|
+
} | {
|
|
324
|
+
mode: 'adaptive';
|
|
325
|
+
iframe: {
|
|
326
|
+
iframeUrl: string;
|
|
327
|
+
external?: boolean;
|
|
328
|
+
};
|
|
329
|
+
reactNative: {
|
|
330
|
+
component: string;
|
|
331
|
+
bundleId?: string;
|
|
332
|
+
bundleUrl?: string;
|
|
333
|
+
};
|
|
334
|
+
};
|
|
335
|
+
interface PluginManifest$1 {
|
|
336
|
+
id: string;
|
|
337
|
+
name: string;
|
|
338
|
+
version: string;
|
|
339
|
+
description?: string;
|
|
340
|
+
type?: 'ui' | 'service' | 'hybrid';
|
|
341
|
+
render?: RenderMode;
|
|
342
|
+
native?: NativeCapabilities$1;
|
|
343
|
+
hooks?: PluginHooks$1;
|
|
344
|
+
channels?: string[] | {
|
|
345
|
+
events: string[];
|
|
346
|
+
actions: string[];
|
|
347
|
+
};
|
|
348
|
+
capabilities?: Record<string, unknown>;
|
|
349
|
+
_source?: string;
|
|
350
|
+
_connectorId?: string;
|
|
351
|
+
_mcpEndpoint?: string;
|
|
352
|
+
}
|
|
353
|
+
interface RegisteredUIPlugin {
|
|
354
|
+
id: string;
|
|
355
|
+
type: 'ui' | 'hybrid';
|
|
356
|
+
capabilities?: NativeCapabilities$1;
|
|
357
|
+
Component: React.FC<PluginProps>;
|
|
358
|
+
}
|
|
359
|
+
interface RegisteredServicePlugin {
|
|
360
|
+
id: string;
|
|
361
|
+
type: 'service';
|
|
362
|
+
capabilities?: NativeCapabilities$1;
|
|
363
|
+
hooks?: PluginHooks$1;
|
|
364
|
+
onStart: (props: Omit<PluginProps, 'theme'>) => Promise<void> | void;
|
|
365
|
+
onStop?: () => Promise<void> | void;
|
|
366
|
+
}
|
|
367
|
+
type RegisteredPlugin = RegisteredUIPlugin | RegisteredServicePlugin;
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Plugin registration API.
|
|
371
|
+
* Solution developers use these to register their plugins.
|
|
372
|
+
*/
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Register a UI or hybrid plugin (has a visual component).
|
|
376
|
+
*/
|
|
377
|
+
declare function register(id: string, config: {
|
|
378
|
+
type?: 'ui' | 'hybrid';
|
|
379
|
+
capabilities?: NativeCapabilities$1;
|
|
380
|
+
Component: React.FC<PluginProps>;
|
|
381
|
+
}): RegisteredUIPlugin;
|
|
382
|
+
/**
|
|
383
|
+
* Register a headless service plugin (no UI).
|
|
384
|
+
*/
|
|
385
|
+
declare function registerService(id: string, config: {
|
|
386
|
+
capabilities?: NativeCapabilities$1;
|
|
387
|
+
hooks?: PluginHooks$1;
|
|
388
|
+
onStart: (props: Omit<PluginProps, 'theme'>) => Promise<void> | void;
|
|
389
|
+
onStop?: () => Promise<void> | void;
|
|
390
|
+
}): RegisteredServicePlugin;
|
|
391
|
+
|
|
392
|
+
interface CardProps {
|
|
393
|
+
theme: ThemeTokens;
|
|
394
|
+
children: React$1.ReactNode;
|
|
395
|
+
style?: any;
|
|
396
|
+
onPress?: () => void;
|
|
397
|
+
}
|
|
398
|
+
declare function Card({ theme, children, style, onPress }: CardProps): React$1.FunctionComponentElement<react_native.PressableProps & React$1.RefAttributes<View>> | React$1.CElement<react_native.ViewProps, View>;
|
|
399
|
+
interface BadgeProps {
|
|
400
|
+
theme: ThemeTokens;
|
|
401
|
+
label: string;
|
|
402
|
+
color?: 'accent' | 'success' | 'warning' | 'error' | 'purple';
|
|
403
|
+
style?: any;
|
|
404
|
+
}
|
|
405
|
+
declare function Badge({ theme, label, color, style }: BadgeProps): React$1.CElement<react_native.ViewProps, View>;
|
|
406
|
+
interface TabBarProps {
|
|
407
|
+
theme: ThemeTokens;
|
|
408
|
+
tabs: string[];
|
|
409
|
+
activeTab: string;
|
|
410
|
+
onTabChange: (tab: string) => void;
|
|
411
|
+
style?: any;
|
|
412
|
+
}
|
|
413
|
+
declare function TabBar({ theme, tabs, activeTab, onTabChange, style }: TabBarProps): React$1.CElement<react_native.ViewProps, View>;
|
|
414
|
+
interface ListItemProps {
|
|
415
|
+
theme: ThemeTokens;
|
|
416
|
+
title: string;
|
|
417
|
+
subtitle?: string;
|
|
418
|
+
right?: React$1.ReactNode;
|
|
419
|
+
onPress?: () => void;
|
|
420
|
+
style?: any;
|
|
421
|
+
}
|
|
422
|
+
declare function ListItem({ theme, title, subtitle, right, onPress, style }: ListItemProps): React$1.FunctionComponentElement<react_native.PressableProps & React$1.RefAttributes<View>> | React$1.CElement<react_native.ViewProps, View>;
|
|
423
|
+
interface SearchBarProps {
|
|
424
|
+
theme: ThemeTokens;
|
|
425
|
+
value: string;
|
|
426
|
+
onChangeText: (text: string) => void;
|
|
427
|
+
placeholder?: string;
|
|
428
|
+
style?: any;
|
|
429
|
+
}
|
|
430
|
+
declare function SearchBar({ theme, value, onChangeText, placeholder, style }: SearchBarProps): React$1.CElement<react_native.TextInputProps, TextInput>;
|
|
431
|
+
interface EmptyStateProps {
|
|
432
|
+
theme: ThemeTokens;
|
|
433
|
+
title: string;
|
|
434
|
+
subtitle?: string;
|
|
435
|
+
style?: any;
|
|
436
|
+
}
|
|
437
|
+
declare function EmptyState({ theme, title, subtitle, style }: EmptyStateProps): React$1.CElement<react_native.ViewProps, View>;
|
|
438
|
+
interface ErrorStateProps {
|
|
439
|
+
theme: ThemeTokens;
|
|
440
|
+
message: string;
|
|
441
|
+
onRetry?: () => void;
|
|
442
|
+
style?: any;
|
|
443
|
+
}
|
|
444
|
+
declare function ErrorState({ theme, message, onRetry, style }: ErrorStateProps): React$1.CElement<react_native.ViewProps, View>;
|
|
445
|
+
interface LoadingStateProps {
|
|
446
|
+
theme: ThemeTokens;
|
|
447
|
+
message?: string;
|
|
448
|
+
style?: any;
|
|
449
|
+
}
|
|
450
|
+
declare function LoadingState({ theme, message, style }: LoadingStateProps): React$1.CElement<react_native.ViewProps, View>;
|
|
451
|
+
interface ActionButtonProps {
|
|
452
|
+
theme: ThemeTokens;
|
|
453
|
+
label?: string;
|
|
454
|
+
icon?: React$1.ReactNode;
|
|
455
|
+
onPress: () => void;
|
|
456
|
+
style?: any;
|
|
457
|
+
}
|
|
458
|
+
declare function ActionButton({ theme, label, icon, onPress, style }: ActionButtonProps): React$1.FunctionComponentElement<react_native.PressableProps & React$1.RefAttributes<View>>;
|
|
459
|
+
|
|
460
|
+
type ThemeColors = ThemeTokens['colors'];
|
|
461
|
+
/** Override the plugin theme (host brand). Call once at startup — mounted
|
|
462
|
+
* plugins re-render with the new tokens. */
|
|
463
|
+
declare function setPluginThemeColors(colors: Partial<ThemeColors>, opts?: {
|
|
464
|
+
isDark?: boolean;
|
|
465
|
+
}): void;
|
|
466
|
+
declare function usePluginTheme(): ThemeTokens;
|
|
467
|
+
|
|
468
|
+
interface PluginApi {
|
|
469
|
+
(connectorId: string, tool: string, args?: Record<string, any>): Promise<any>;
|
|
470
|
+
call(connectorOrTool: string, toolOrArgs?: string | Record<string, any>, argsOrConnector?: Record<string, any> | string): Promise<any>;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Create a simple API function to call connector tools.
|
|
474
|
+
*/
|
|
475
|
+
declare function useApi(bridge: PluginBridge): PluginApi;
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* @adas/plugin-sdk namespace — everything a PLUGIN author imports.
|
|
479
|
+
* Remote bundles resolve `require('@adas/plugin-sdk')` to exactly this
|
|
480
|
+
* module via the bundle manager's require shim.
|
|
481
|
+
*/
|
|
482
|
+
|
|
483
|
+
declare const PluginSDK: {
|
|
484
|
+
readonly register: typeof register;
|
|
485
|
+
readonly registerService: typeof registerService;
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Host integration points — the DI seams that keep this package free of
|
|
490
|
+
* Expo imports. The host app (or @ateam-ai-mobile/expo) plugs in concrete providers
|
|
491
|
+
* once at startup; everything here has a safe no-op/in-memory default so
|
|
492
|
+
* a bare host works with zero configuration.
|
|
493
|
+
*/
|
|
494
|
+
|
|
495
|
+
/** Register a haptics implementation (e.g. expo-haptics via @ateam-ai-mobile/expo). */
|
|
496
|
+
declare function setHapticsProvider(haptics: HapticsAPI | null): void;
|
|
497
|
+
/** No-op safe accessor — surfaces call this for tap feedback. */
|
|
498
|
+
declare function getHaptics(): HapticsAPI | null;
|
|
499
|
+
/** Install the device-capabilities implementation plugins receive as
|
|
500
|
+
* `props.native`. The host owns the native modules. */
|
|
501
|
+
declare function setPluginNativeProvider(native: PluginNative): void;
|
|
502
|
+
declare function getPluginNative(): PluginNative;
|
|
503
|
+
type PluginResolver = RegisteredPlugin | (() => Promise<RegisteredPlugin | null>);
|
|
504
|
+
declare function registerNativePlugin(id: string, plugin: PluginResolver): void;
|
|
505
|
+
declare function unregisterNativePlugin(id: string): void;
|
|
506
|
+
declare const nativePluginRegistry: {
|
|
507
|
+
has(id: string): boolean;
|
|
508
|
+
get(id: string): Promise<RegisteredPlugin | null>;
|
|
509
|
+
};
|
|
510
|
+
declare function registerBundleModules(modules: Record<string, any>): void;
|
|
511
|
+
|
|
512
|
+
declare class BundleManager {
|
|
513
|
+
/** In-memory module cache: bundleUrl → evaluated module.exports */
|
|
514
|
+
private modules;
|
|
515
|
+
/** In-flight download deduplication: bundleUrl → Promise */
|
|
516
|
+
private inflight;
|
|
517
|
+
/**
|
|
518
|
+
* Load a plugin component. Returns the RegisteredUIPlugin object.
|
|
519
|
+
* Handles: in-memory cache → disk cache → download → evaluate → extract.
|
|
520
|
+
*
|
|
521
|
+
* `expectedHash` (SHA-256 hex from cp.getContextPlugin manifest) MUST be
|
|
522
|
+
* provided for any bundle the user has not previously verified — without
|
|
523
|
+
* it, a tampered bundle is `eval`'d as JS with full RN runtime + every
|
|
524
|
+
* native capability the manifest declares.
|
|
525
|
+
*/
|
|
526
|
+
load(pluginId: string, bundleUrl: string, version: string, expectedHash?: string): Promise<RegisteredUIPlugin>;
|
|
527
|
+
/**
|
|
528
|
+
* Prewarm: load every plugin bundle in the background after app boot, so a
|
|
529
|
+
* later open is instant (in-memory hit) instead of round-tripping the
|
|
530
|
+
* network. Errors are swallowed per-plugin — one bad bundle shouldn't
|
|
531
|
+
* block others. Concurrency capped at 3.
|
|
532
|
+
*/
|
|
533
|
+
prewarmAll(items: Array<{
|
|
534
|
+
pluginId: string;
|
|
535
|
+
bundleUrl: string;
|
|
536
|
+
version: string;
|
|
537
|
+
bundleHash?: string;
|
|
538
|
+
}>): Promise<void>;
|
|
539
|
+
/**
|
|
540
|
+
* Clear all caches (in-memory + storage).
|
|
541
|
+
*/
|
|
542
|
+
clearAll(): Promise<void>;
|
|
543
|
+
/**
|
|
544
|
+
* Clear cache for a specific plugin/bundle.
|
|
545
|
+
*/
|
|
546
|
+
clearPlugin(pluginId: string): Promise<void>;
|
|
547
|
+
private loadModule;
|
|
548
|
+
/**
|
|
549
|
+
* Download + integrity-verify a bundle. Refuses to return when:
|
|
550
|
+
* - manifest hash and computed hash disagree
|
|
551
|
+
* - server's `X-Bundle-SHA256` disagrees with manifest hash
|
|
552
|
+
* - no expected hash AND no server hash header (cannot prove the bundle
|
|
553
|
+
* wasn't tampered with — fail closed rather than trust the wire).
|
|
554
|
+
*/
|
|
555
|
+
private download;
|
|
556
|
+
private evaluate;
|
|
557
|
+
/**
|
|
558
|
+
* Find a plugin component in a loaded module.
|
|
559
|
+
* Handles: default export, direct key match, multi-plugin .id match.
|
|
560
|
+
*/
|
|
561
|
+
private getComponentFromMemory;
|
|
562
|
+
private describeModule;
|
|
563
|
+
}
|
|
564
|
+
/** Singleton — shared across all plugin renderers */
|
|
565
|
+
declare const bundleManager: BundleManager;
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Bundle disk-cache adapter. The bundle manager persists downloaded plugin
|
|
569
|
+
* bundles through this interface so the package stays free of Expo/RN
|
|
570
|
+
* storage imports. @ateam-ai-mobile/expo ships a file-system implementation; the
|
|
571
|
+
* default is in-memory (bundles re-download per app session — correct,
|
|
572
|
+
* just slower on cold start).
|
|
573
|
+
*/
|
|
574
|
+
interface BundleCacheEntry {
|
|
575
|
+
localPath: string;
|
|
576
|
+
version: string;
|
|
577
|
+
timestamp: number;
|
|
578
|
+
bundleUrl: string;
|
|
579
|
+
/** SHA-256 (hex, lowercase) of the cached bundle bytes — integrity proof */
|
|
580
|
+
bundleHash?: string;
|
|
581
|
+
}
|
|
582
|
+
interface BundleStorage {
|
|
583
|
+
loadIndex(): Promise<Record<string, BundleCacheEntry>>;
|
|
584
|
+
saveIndex(index: Record<string, BundleCacheEntry>): Promise<void>;
|
|
585
|
+
/** Read a cached bundle. Returns null when missing/unreadable. */
|
|
586
|
+
readBundle(localPath: string): Promise<string | null>;
|
|
587
|
+
/** Persist a bundle; returns the localPath to record in the index.
|
|
588
|
+
* `key` is a filesystem-safe name derived from the bundle URL+version. */
|
|
589
|
+
writeBundle(key: string, content: string): Promise<string>;
|
|
590
|
+
deleteBundle(localPath: string): Promise<void>;
|
|
591
|
+
/** Wipe everything (index + bundles). */
|
|
592
|
+
clearAll(): Promise<void>;
|
|
593
|
+
}
|
|
594
|
+
/** Default storage: keeps bundles for the lifetime of the JS context only. */
|
|
595
|
+
declare class MemoryBundleStorage implements BundleStorage {
|
|
596
|
+
private index;
|
|
597
|
+
private files;
|
|
598
|
+
loadIndex(): Promise<Record<string, BundleCacheEntry>>;
|
|
599
|
+
saveIndex(index: Record<string, BundleCacheEntry>): Promise<void>;
|
|
600
|
+
readBundle(localPath: string): Promise<string | null>;
|
|
601
|
+
writeBundle(key: string, content: string): Promise<string>;
|
|
602
|
+
deleteBundle(localPath: string): Promise<void>;
|
|
603
|
+
clearAll(): Promise<void>;
|
|
604
|
+
}
|
|
605
|
+
/** Install a persistent storage implementation (call before first plugin load). */
|
|
606
|
+
declare function setBundleStorage(storage: BundleStorage): void;
|
|
607
|
+
|
|
608
|
+
declare function useNativeBridge(pluginId: string, connectorId?: string, commandBufferRef?: MutableRefObject<any[]>): PluginBridge;
|
|
609
|
+
/**
|
|
610
|
+
* Non-hook version for service plugins (no React lifecycle).
|
|
611
|
+
*/
|
|
612
|
+
declare function createNativeBridge(pluginId: string, connectorId?: string): PluginBridge;
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Native Bridge SDK Types
|
|
616
|
+
*
|
|
617
|
+
* TypeScript interfaces for the bridge API exposed to dynamic connectors.
|
|
618
|
+
* Connectors use these types to interact with device capabilities.
|
|
619
|
+
*/
|
|
620
|
+
interface CalendarEvent {
|
|
621
|
+
id: string;
|
|
622
|
+
title: string;
|
|
623
|
+
date: string;
|
|
624
|
+
start: string;
|
|
625
|
+
end: string;
|
|
626
|
+
location: string;
|
|
627
|
+
attendees: string[];
|
|
628
|
+
notes: string;
|
|
629
|
+
}
|
|
630
|
+
interface CalendarTodayResult {
|
|
631
|
+
date: string;
|
|
632
|
+
day_of_week: string;
|
|
633
|
+
events: CalendarEvent[];
|
|
634
|
+
count: number;
|
|
635
|
+
}
|
|
636
|
+
interface CalendarUpcomingResult {
|
|
637
|
+
from: string;
|
|
638
|
+
days_ahead: number;
|
|
639
|
+
events: CalendarEvent[];
|
|
640
|
+
count: number;
|
|
641
|
+
}
|
|
642
|
+
interface CalendarCreateParams {
|
|
643
|
+
title: string;
|
|
644
|
+
date: string;
|
|
645
|
+
start_time: string;
|
|
646
|
+
end_time?: string;
|
|
647
|
+
location?: string;
|
|
648
|
+
attendees?: string[];
|
|
649
|
+
notes?: string;
|
|
650
|
+
}
|
|
651
|
+
interface CalendarCreateResult {
|
|
652
|
+
event_id: string;
|
|
653
|
+
}
|
|
654
|
+
interface CalendarRescheduleParams {
|
|
655
|
+
event_id: string;
|
|
656
|
+
new_date?: string;
|
|
657
|
+
new_start_time?: string;
|
|
658
|
+
new_end_time?: string;
|
|
659
|
+
}
|
|
660
|
+
interface Contact {
|
|
661
|
+
id: string;
|
|
662
|
+
name: string;
|
|
663
|
+
phone: string | null;
|
|
664
|
+
email: string | null;
|
|
665
|
+
relationship: string;
|
|
666
|
+
birthday: string | null;
|
|
667
|
+
notes: string;
|
|
668
|
+
}
|
|
669
|
+
interface ContactSearchResult {
|
|
670
|
+
contacts: Contact[];
|
|
671
|
+
count: number;
|
|
672
|
+
}
|
|
673
|
+
interface Birthday {
|
|
674
|
+
name: string;
|
|
675
|
+
relationship: string;
|
|
676
|
+
birthday: string;
|
|
677
|
+
days_until: number;
|
|
678
|
+
is_today: boolean;
|
|
679
|
+
}
|
|
680
|
+
interface BirthdayResult {
|
|
681
|
+
birthdays: Birthday[];
|
|
682
|
+
count: number;
|
|
683
|
+
}
|
|
684
|
+
interface LocationResult {
|
|
685
|
+
lat: number;
|
|
686
|
+
lng: number;
|
|
687
|
+
place: string;
|
|
688
|
+
address: string;
|
|
689
|
+
type: string;
|
|
690
|
+
timestamp: string;
|
|
691
|
+
}
|
|
692
|
+
interface BatteryStatus {
|
|
693
|
+
ok: true;
|
|
694
|
+
timestamp: string;
|
|
695
|
+
battery: {
|
|
696
|
+
level: number;
|
|
697
|
+
state: 'charging' | 'unplugged' | 'full';
|
|
698
|
+
low_power_mode: boolean;
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
interface NetworkStatus {
|
|
702
|
+
type: 'wifi' | 'cellular' | 'none';
|
|
703
|
+
is_connected: boolean;
|
|
704
|
+
wifi_name?: string;
|
|
705
|
+
timestamp: string;
|
|
706
|
+
}
|
|
707
|
+
interface Notification {
|
|
708
|
+
id: string;
|
|
709
|
+
app: string;
|
|
710
|
+
title: string;
|
|
711
|
+
body: string;
|
|
712
|
+
timestamp: string;
|
|
713
|
+
sender: string | null;
|
|
714
|
+
priority: 'high' | 'medium' | 'low';
|
|
715
|
+
read: boolean;
|
|
716
|
+
}
|
|
717
|
+
interface NotificationListResult {
|
|
718
|
+
notifications: Notification[];
|
|
719
|
+
total: number;
|
|
720
|
+
unread: number;
|
|
721
|
+
}
|
|
722
|
+
interface SMSSendResult {
|
|
723
|
+
ok: boolean;
|
|
724
|
+
status: 'sent' | 'unknown' | 'cancelled';
|
|
725
|
+
}
|
|
726
|
+
interface MapsNavigateResult {
|
|
727
|
+
ok: boolean;
|
|
728
|
+
status: 'navigating' | 'error';
|
|
729
|
+
}
|
|
730
|
+
interface HttpResponse {
|
|
731
|
+
ok: boolean;
|
|
732
|
+
status: number;
|
|
733
|
+
data: any;
|
|
734
|
+
headers: Record<string, string>;
|
|
735
|
+
}
|
|
736
|
+
type PermissionState = 'granted' | 'denied' | 'not_requested';
|
|
737
|
+
interface DeviceInfo {
|
|
738
|
+
os: 'ios' | 'android';
|
|
739
|
+
version: string;
|
|
740
|
+
}
|
|
741
|
+
interface Bridge {
|
|
742
|
+
calendar: {
|
|
743
|
+
getToday(): Promise<CalendarTodayResult>;
|
|
744
|
+
getUpcoming(days?: number): Promise<CalendarUpcomingResult>;
|
|
745
|
+
create(event: CalendarCreateParams): Promise<CalendarCreateResult>;
|
|
746
|
+
reschedule(params: CalendarRescheduleParams): Promise<{
|
|
747
|
+
ok: boolean;
|
|
748
|
+
}>;
|
|
749
|
+
cancel(event_id: string): Promise<{
|
|
750
|
+
ok: boolean;
|
|
751
|
+
}>;
|
|
752
|
+
};
|
|
753
|
+
contacts: {
|
|
754
|
+
search(query: string): Promise<ContactSearchResult>;
|
|
755
|
+
get(idOrName: string): Promise<Contact | null>;
|
|
756
|
+
getAll(): Promise<ContactSearchResult>;
|
|
757
|
+
birthdays(days?: number): Promise<BirthdayResult>;
|
|
758
|
+
};
|
|
759
|
+
location: {
|
|
760
|
+
getCurrent(): Promise<LocationResult>;
|
|
761
|
+
};
|
|
762
|
+
battery: {
|
|
763
|
+
getStatus(): Promise<BatteryStatus>;
|
|
764
|
+
};
|
|
765
|
+
network: {
|
|
766
|
+
getStatus(): Promise<NetworkStatus>;
|
|
767
|
+
};
|
|
768
|
+
notifications: {
|
|
769
|
+
list(): Promise<NotificationListResult>;
|
|
770
|
+
};
|
|
771
|
+
sms: {
|
|
772
|
+
isAvailable(): Promise<boolean>;
|
|
773
|
+
send(phone: string, message: string): Promise<SMSSendResult>;
|
|
774
|
+
};
|
|
775
|
+
maps: {
|
|
776
|
+
navigate(destination: string, mode?: 'driving' | 'transit' | 'walking'): Promise<MapsNavigateResult>;
|
|
777
|
+
};
|
|
778
|
+
http: {
|
|
779
|
+
get(url: string, headers?: Record<string, string>): Promise<HttpResponse>;
|
|
780
|
+
post(url: string, body: any, headers?: Record<string, string>): Promise<HttpResponse>;
|
|
781
|
+
put(url: string, body: any, headers?: Record<string, string>): Promise<HttpResponse>;
|
|
782
|
+
delete(url: string, body?: any, headers?: Record<string, string>): Promise<HttpResponse>;
|
|
783
|
+
};
|
|
784
|
+
storage: {
|
|
785
|
+
get(key: string): Promise<string | null>;
|
|
786
|
+
set(key: string, value: string): Promise<void>;
|
|
787
|
+
delete(key: string): Promise<void>;
|
|
788
|
+
keys(): Promise<string[]>;
|
|
789
|
+
};
|
|
790
|
+
permissions: {
|
|
791
|
+
check(capability: string): Promise<PermissionState>;
|
|
792
|
+
request(capability: string): Promise<boolean>;
|
|
793
|
+
getAll(): Promise<Record<string, PermissionState>>;
|
|
794
|
+
};
|
|
795
|
+
device: {
|
|
796
|
+
getDeviceId(): string;
|
|
797
|
+
getPlatform(): DeviceInfo;
|
|
798
|
+
};
|
|
799
|
+
log: {
|
|
800
|
+
info(message: string, data?: any): void;
|
|
801
|
+
warn(message: string, data?: any): void;
|
|
802
|
+
error(message: string, data?: any): void;
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
interface PluginManifestLike {
|
|
807
|
+
version?: string;
|
|
808
|
+
name?: string;
|
|
809
|
+
render?: any;
|
|
810
|
+
_connectorId?: string;
|
|
811
|
+
}
|
|
812
|
+
interface UsePluginResult {
|
|
813
|
+
plugin: RegisteredUIPlugin | null;
|
|
814
|
+
loading: boolean;
|
|
815
|
+
error: string | null;
|
|
816
|
+
bundleMissing: boolean;
|
|
817
|
+
}
|
|
818
|
+
declare function usePlugin(pluginId: string, manifest: PluginManifestLike): UsePluginResult;
|
|
819
|
+
|
|
820
|
+
interface RemotePlugin {
|
|
821
|
+
id: string;
|
|
822
|
+
name: string;
|
|
823
|
+
version: string;
|
|
824
|
+
manifest: PluginManifest$1;
|
|
825
|
+
source: 'remote' | 'local';
|
|
826
|
+
}
|
|
827
|
+
interface UseRemotePluginsResult {
|
|
828
|
+
plugins: RemotePlugin[];
|
|
829
|
+
loading: boolean;
|
|
830
|
+
error: string | null;
|
|
831
|
+
refreshing: boolean;
|
|
832
|
+
refresh: () => Promise<void>;
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Fetches available UI plugins from A-Team Core for the current solution.
|
|
836
|
+
* Uses apiFetch which auto-injects JWT + tenant headers.
|
|
837
|
+
*/
|
|
838
|
+
declare function useRemotePlugins(solutionId?: string): UseRemotePluginsResult;
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Summary returned by cp.listContextPlugins — no `render` field.
|
|
842
|
+
* Used for the plugin grid (name, icon, description).
|
|
843
|
+
*/
|
|
844
|
+
interface PluginSurfaceMeta {
|
|
845
|
+
type: 'drawer' | 'card' | 'fullscreen' | 'header' | 'ambient' | 'nudge';
|
|
846
|
+
visibility?: 'always' | 'user' | 'engine';
|
|
847
|
+
trigger?: {
|
|
848
|
+
from?: string;
|
|
849
|
+
gesture?: string;
|
|
850
|
+
};
|
|
851
|
+
icon?: string;
|
|
852
|
+
title?: string;
|
|
853
|
+
subtitle?: string;
|
|
854
|
+
privacy?: boolean;
|
|
855
|
+
prompt?: string;
|
|
856
|
+
}
|
|
857
|
+
interface PluginSummary {
|
|
858
|
+
id: string;
|
|
859
|
+
name: string;
|
|
860
|
+
version: string;
|
|
861
|
+
description?: string;
|
|
862
|
+
_source?: string;
|
|
863
|
+
_connectorId?: string;
|
|
864
|
+
/** Declarative surface placement — added by the surface-SDK migration */
|
|
865
|
+
surface?: PluginSurfaceMeta;
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Native capability flags (declared in manifest).
|
|
869
|
+
*/
|
|
870
|
+
interface NativeCapabilities {
|
|
871
|
+
camera?: boolean;
|
|
872
|
+
location?: boolean;
|
|
873
|
+
biometrics?: boolean;
|
|
874
|
+
offline?: boolean;
|
|
875
|
+
backgroundTasks?: boolean;
|
|
876
|
+
fileSystem?: boolean;
|
|
877
|
+
notifications?: boolean;
|
|
878
|
+
bluetooth?: boolean;
|
|
879
|
+
haptics?: boolean;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Lifecycle hooks for service/hybrid plugins.
|
|
883
|
+
*/
|
|
884
|
+
interface PluginHooks {
|
|
885
|
+
onAppStart?: boolean;
|
|
886
|
+
onPushReceived?: boolean;
|
|
887
|
+
onConnectivity?: boolean;
|
|
888
|
+
onForeground?: boolean;
|
|
889
|
+
onBackground?: boolean;
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Render mode — polymorphic.
|
|
893
|
+
* - 'iframe': existing WebView (backward compat)
|
|
894
|
+
* - 'react-native': native RN component only
|
|
895
|
+
* - 'adaptive': both web and native, host picks best
|
|
896
|
+
*/
|
|
897
|
+
type PluginRenderMode = {
|
|
898
|
+
mode: 'iframe';
|
|
899
|
+
iframeUrl: string;
|
|
900
|
+
bundleUrl?: string;
|
|
901
|
+
bundleHash?: string;
|
|
902
|
+
external?: boolean;
|
|
903
|
+
} | {
|
|
904
|
+
mode: 'react-native';
|
|
905
|
+
component: string;
|
|
906
|
+
bundleUrl?: string;
|
|
907
|
+
bundleHash?: string;
|
|
908
|
+
bundleId?: string;
|
|
909
|
+
} | {
|
|
910
|
+
mode: 'adaptive';
|
|
911
|
+
iframe: {
|
|
912
|
+
iframeUrl: string;
|
|
913
|
+
external?: boolean;
|
|
914
|
+
};
|
|
915
|
+
reactNative: {
|
|
916
|
+
component: string;
|
|
917
|
+
bundleUrl?: string;
|
|
918
|
+
bundleHash?: string;
|
|
919
|
+
bundleId?: string;
|
|
920
|
+
};
|
|
921
|
+
};
|
|
922
|
+
/**
|
|
923
|
+
* Full manifest returned by cp.getContextPlugin.
|
|
924
|
+
* Extended to support native mobile plugins alongside existing web plugins.
|
|
925
|
+
*/
|
|
926
|
+
interface PluginManifest extends PluginSummary {
|
|
927
|
+
type?: 'ui' | 'service' | 'hybrid';
|
|
928
|
+
render: PluginRenderMode;
|
|
929
|
+
native?: NativeCapabilities;
|
|
930
|
+
hooks?: PluginHooks;
|
|
931
|
+
channels?: string[] | {
|
|
932
|
+
events: string[];
|
|
933
|
+
actions: string[];
|
|
934
|
+
};
|
|
935
|
+
capabilities?: Record<string, unknown>;
|
|
936
|
+
_mcpEndpoint?: string;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Determine if a manifest supports native rendering.
|
|
940
|
+
*/
|
|
941
|
+
declare function supportsNative(manifest: PluginManifest): boolean;
|
|
942
|
+
/**
|
|
943
|
+
* Get the native component ID from a manifest (if it has native support).
|
|
944
|
+
*/
|
|
945
|
+
declare function getNativeComponentId(manifest: PluginManifest): string | null;
|
|
946
|
+
/**
|
|
947
|
+
* Get the native bundle URL from a manifest (if it has native support).
|
|
948
|
+
*/
|
|
949
|
+
declare function getNativeBundleUrl(manifest: PluginManifest): string | null;
|
|
950
|
+
/**
|
|
951
|
+
* Get the SHA-256 integrity hash for a native bundle, if the server provided one.
|
|
952
|
+
* Used post-download to verify the bundle bytes weren't tampered in transit
|
|
953
|
+
* — a MITM-replaced bundle gets `eval`'d as RN code with full capability access.
|
|
954
|
+
*/
|
|
955
|
+
declare function getNativeBundleHash(manifest: PluginManifest): string | null;
|
|
956
|
+
/**
|
|
957
|
+
* Check if a manifest can be rendered as a WebView (iframe or adaptive with iframe).
|
|
958
|
+
*/
|
|
959
|
+
declare function supportsWebView(manifest: PluginManifest): boolean;
|
|
960
|
+
/**
|
|
961
|
+
* List all available UI plugins via MCP JSON-RPC.
|
|
962
|
+
* Returns summary data only (no render field).
|
|
963
|
+
* Protocol: cp.listContextPlugins → core plugins + MCP connector plugins.
|
|
964
|
+
*/
|
|
965
|
+
declare function listPlugins(): Promise<PluginSummary[]>;
|
|
966
|
+
/**
|
|
967
|
+
* Get a specific plugin's FULL manifest (with render.iframeUrl).
|
|
968
|
+
* Protocol: cp.getContextPlugin({ id }) → resolves iframeUrl for core/MCP/external.
|
|
969
|
+
*
|
|
970
|
+
* IMPORTANT: The backend parameter is `id`, not `pluginId`.
|
|
971
|
+
*/
|
|
972
|
+
declare function getPlugin(pluginId: string): Promise<PluginManifest | null>;
|
|
973
|
+
/**
|
|
974
|
+
* Resolve plugin iframe URL to a full URL for WebView.
|
|
975
|
+
* Matches the web frontend's PluginHost.jsx logic:
|
|
976
|
+
* - External (absolute http): append ?tenant=
|
|
977
|
+
* - MCP plugin (/mcp-ui/...): inject tenant into path → /mcp-ui/{tenant}/{connectorId}/...
|
|
978
|
+
* - Core plugin (/assets/...): prepend getCoreApiUrl()
|
|
979
|
+
*/
|
|
980
|
+
declare function resolvePluginUrl(manifest: PluginManifest, tenant?: string): string;
|
|
981
|
+
|
|
982
|
+
interface SurfaceDrawerProps {
|
|
983
|
+
visible: boolean;
|
|
984
|
+
onClose: () => void;
|
|
985
|
+
title: string;
|
|
986
|
+
subtitle?: string;
|
|
987
|
+
/** Show the lock + "Only you can see this" privacy pill under the title */
|
|
988
|
+
privacy?: boolean;
|
|
989
|
+
/** Show the small Ada orb in the header (default: true) */
|
|
990
|
+
showOrb?: boolean;
|
|
991
|
+
/** Sheet height ratio of screen (default: 0.85) */
|
|
992
|
+
heightRatio?: number;
|
|
993
|
+
children: ReactNode;
|
|
994
|
+
}
|
|
995
|
+
declare function SurfaceDrawer({ visible, onClose, title, subtitle, privacy, showOrb, heightRatio, children, }: SurfaceDrawerProps): react_jsx_runtime.JSX.Element | null;
|
|
996
|
+
|
|
997
|
+
interface SurfaceCardProps {
|
|
998
|
+
/** Emoji or short string icon shown on the left */
|
|
999
|
+
icon?: string;
|
|
1000
|
+
/** Card headline (e.g. "Today's plate") */
|
|
1001
|
+
title: string;
|
|
1002
|
+
/** Optional secondary line below title */
|
|
1003
|
+
subtitle?: string;
|
|
1004
|
+
/** Tap handler. Fires haptic before invoking. */
|
|
1005
|
+
onPress?: () => void;
|
|
1006
|
+
/** Long-press handler. Fires a heavier haptic. Used by user widgets for
|
|
1007
|
+
* the Delete / (later) Hide / Rename context menu. */
|
|
1008
|
+
onLongPress?: () => void;
|
|
1009
|
+
/** Whether to show the ›-style trailing arrow (default: true if onPress) */
|
|
1010
|
+
showArrow?: boolean;
|
|
1011
|
+
/** Optional preview content rendered below the title block */
|
|
1012
|
+
children?: ReactNode;
|
|
1013
|
+
}
|
|
1014
|
+
declare function SurfaceCard({ icon, title, subtitle, onPress, onLongPress, showArrow, children, }: SurfaceCardProps): react_jsx_runtime.JSX.Element;
|
|
1015
|
+
|
|
1016
|
+
interface SurfaceFullscreenProps {
|
|
1017
|
+
visible: boolean;
|
|
1018
|
+
onClose: () => void;
|
|
1019
|
+
/** Status text shown under the wordmark */
|
|
1020
|
+
status?: string;
|
|
1021
|
+
/** Optional hero element above body (typically an AdaOrb) */
|
|
1022
|
+
hero?: ReactNode;
|
|
1023
|
+
/** Body content */
|
|
1024
|
+
children?: ReactNode;
|
|
1025
|
+
/** Whether to show the small "ada" wordmark (default: true) */
|
|
1026
|
+
showWordmark?: boolean;
|
|
1027
|
+
/** Built-in close icon flavor or a custom node. Default: 'x' */
|
|
1028
|
+
closeIcon?: 'x' | 'hangup' | ReactNode;
|
|
1029
|
+
/** Label under the close button (default: "Close") */
|
|
1030
|
+
closeLabel?: string;
|
|
1031
|
+
}
|
|
1032
|
+
declare function SurfaceFullscreen({ visible, onClose, status, hero, children, showWordmark, closeIcon, closeLabel, }: SurfaceFullscreenProps): react_jsx_runtime.JSX.Element | null;
|
|
1033
|
+
|
|
1034
|
+
type AdaOrbState = 'idle' | 'listening' | 'thinking' | 'speaking';
|
|
1035
|
+
interface AdaOrbProps {
|
|
1036
|
+
size?: number;
|
|
1037
|
+
state?: AdaOrbState;
|
|
1038
|
+
/** Show the "iA" wordmark inside the orb. Suppressed below 60px because
|
|
1039
|
+
* glyphs become unreadable at avatar/chevron sizes — render as a plain
|
|
1040
|
+
* orb there. Default true. */
|
|
1041
|
+
inscription?: boolean;
|
|
1042
|
+
}
|
|
1043
|
+
declare function AdaOrb({ size, state, inscription }: AdaOrbProps): react_jsx_runtime.JSX.Element;
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* Surface manifest types — the contract a plugin declares to live inside
|
|
1047
|
+
* the Ada host shell.
|
|
1048
|
+
*
|
|
1049
|
+
* Future: this maps directly onto the platform-side `surface` field on
|
|
1050
|
+
* plugin manifests. While that schema is in flight, the mobile shell
|
|
1051
|
+
* registers built-in surfaces locally (see bootstrap.tsx).
|
|
1052
|
+
*/
|
|
1053
|
+
|
|
1054
|
+
type SurfaceType = 'drawer' | 'card' | 'fullscreen' | 'header' | 'ambient' | 'nudge';
|
|
1055
|
+
type SurfaceVisibility = 'always' | 'user' | 'engine';
|
|
1056
|
+
/** Where in the host's chrome the plugin lives. Generic, host-agnostic role.
|
|
1057
|
+
* - `featured`: signature surface — host shows it prominently (e.g. pinned card on home).
|
|
1058
|
+
* - `menu`: lives as a row in the host's navigation menu (side menu / hamburger).
|
|
1059
|
+
* - undefined: regular plugin — host puts it in the default plugin list / picker. */
|
|
1060
|
+
type SurfacePlacement = 'featured' | 'menu';
|
|
1061
|
+
interface SurfaceManifestBase {
|
|
1062
|
+
/** Stable plugin/surface id. e.g. "mcp:memory:drawer" */
|
|
1063
|
+
id: string;
|
|
1064
|
+
type: SurfaceType;
|
|
1065
|
+
visibility: SurfaceVisibility;
|
|
1066
|
+
/** Optional: where in host chrome to render. Omit = default plugin list. */
|
|
1067
|
+
placement?: SurfacePlacement;
|
|
1068
|
+
/** Short emoji or symbol — shown on cards / header pills */
|
|
1069
|
+
icon?: string;
|
|
1070
|
+
title: string;
|
|
1071
|
+
subtitle?: string;
|
|
1072
|
+
/** Marks plugins that handle sensitive data (host shows lock pill) */
|
|
1073
|
+
privacy?: boolean;
|
|
1074
|
+
}
|
|
1075
|
+
/** A surface that mounts a host component when active (drawer, fullscreen) */
|
|
1076
|
+
interface MountSurfaceManifest extends SurfaceManifestBase {
|
|
1077
|
+
type: 'drawer' | 'fullscreen';
|
|
1078
|
+
/** React component the dispatcher mounts when this surface is active.
|
|
1079
|
+
* Receives `dismiss` to close itself, plus optional `props` forwarded
|
|
1080
|
+
* from `sys.focusUiPlugin(id, props)`. */
|
|
1081
|
+
Component: ComponentType<{
|
|
1082
|
+
dismiss: () => void;
|
|
1083
|
+
props?: any;
|
|
1084
|
+
}>;
|
|
1085
|
+
}
|
|
1086
|
+
/** A surface that renders inline (card list / header / ambient) */
|
|
1087
|
+
interface InlineSurfaceManifest extends SurfaceManifestBase {
|
|
1088
|
+
type: 'card' | 'header' | 'ambient' | 'nudge';
|
|
1089
|
+
/** For cards: chat prompt to send when tapped */
|
|
1090
|
+
prompt?: string;
|
|
1091
|
+
/** Custom tap handler. Overrides `prompt` if present. */
|
|
1092
|
+
onPress?: () => void;
|
|
1093
|
+
}
|
|
1094
|
+
type SurfaceManifest = MountSurfaceManifest | InlineSurfaceManifest;
|
|
1095
|
+
|
|
1096
|
+
interface SurfaceState {
|
|
1097
|
+
manifests: Record<string, SurfaceManifest>;
|
|
1098
|
+
activeDrawer: string | null;
|
|
1099
|
+
activeFullscreen: string | null;
|
|
1100
|
+
/** Props passed by the engine when summoning a surface via sys.focusUiPlugin.
|
|
1101
|
+
* Keyed by surface id; cleared on hide. Plugins read these on first mount. */
|
|
1102
|
+
activeProps: Record<string, any>;
|
|
1103
|
+
/** Increments on every `show()` call. Used as a React `key` so the Surface
|
|
1104
|
+
* Component remounts even if the same surface is shown again — guarantees
|
|
1105
|
+
* the plugin's data-fetching effects re-run, so the user always sees fresh
|
|
1106
|
+
* data when they open a drawer. */
|
|
1107
|
+
mountKey: number;
|
|
1108
|
+
register: (manifest: SurfaceManifest) => void;
|
|
1109
|
+
unregister: (id: string) => void;
|
|
1110
|
+
/** Open a surface in its declared container. Props (optional) are forwarded
|
|
1111
|
+
* to the mounted plugin on first render. */
|
|
1112
|
+
show: (id: string, props?: any) => void;
|
|
1113
|
+
/** Close the surface with the given id (or whatever is active for the matching type) */
|
|
1114
|
+
hide: (id?: string) => void;
|
|
1115
|
+
/** All registered manifests, optionally filtered.
|
|
1116
|
+
* `placement: 'unset'` selects only plugins WITHOUT a placement (default list). */
|
|
1117
|
+
list: (filter?: {
|
|
1118
|
+
type?: SurfaceType;
|
|
1119
|
+
visibility?: SurfaceVisibility[];
|
|
1120
|
+
placement?: SurfacePlacement | 'unset';
|
|
1121
|
+
}) => SurfaceManifest[];
|
|
1122
|
+
}
|
|
1123
|
+
declare const useSurfaceStore: zustand.UseBoundStore<zustand.StoreApi<SurfaceState>>;
|
|
1124
|
+
declare function isMountSurface(m: SurfaceManifest): m is MountSurfaceManifest;
|
|
1125
|
+
declare function isInlineSurface(m: SurfaceManifest): m is InlineSurfaceManifest;
|
|
1126
|
+
|
|
1127
|
+
declare function SurfaceDispatcher(): react_jsx_runtime.JSX.Element;
|
|
1128
|
+
|
|
1129
|
+
export { ActionButton, AdaOrb, type AdaOrbState, Badge, type BiometricsAPI, type BiometricsAPIv2, type Bridge, type BundleCacheEntry, type BundleStorage, type CameraAPI, Card, type ConnectivityAPI, type CookiesAPI, EmptyState, ErrorState, type FileSystemAPI, type HapticsAPI, type InlineSurfaceManifest, ListItem, LoadingState, type LocationAPI, MemoryBundleStorage, type MountSurfaceManifest, type NativeCapabilities$1 as NativeCapabilities, type NfcAPI, type NotificationsAPI, type PluginManifest as PlatformPluginManifest, type PluginBridge, type PluginContext, type PluginHooks$1 as PluginHooks, type PluginManifest$1 as PluginManifest, type PluginNative, type PluginProps, PluginSDK, type PluginSummary, type PluginSurfaceMeta, type RegisteredPlugin, type RegisteredServicePlugin, type RegisteredUIPlugin, type RemotePlugin, type RenderMode, type ScannerAPI, SearchBar, type SharingAPI, type StorageAPI, SurfaceCard, type SurfaceCardProps, SurfaceDispatcher, SurfaceDrawer, type SurfaceDrawerProps, SurfaceFullscreen, type SurfaceFullscreenProps, type SurfaceManifest, type SurfacePlacement, type SurfaceType, type SurfaceVisibility, TabBar, type ThemeTokens, bundleManager, createNativeBridge, getHaptics, getNativeBundleHash, getNativeBundleUrl, getNativeComponentId, getPlugin, getPluginNative, isInlineSurface, isMountSurface, listPlugins, nativePluginRegistry, register, registerBundleModules, registerNativePlugin, registerService, resolvePluginUrl, setBundleStorage, setHapticsProvider, setPluginNativeProvider, setPluginThemeColors, supportsNative, supportsWebView, unregisterNativePlugin, useApi, useNativeBridge, usePlugin, usePluginTheme, useRemotePlugins, useSurfaceStore };
|