@ateam-ai-mobile/plugin-runtime 0.1.0 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai-mobile/plugin-runtime",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "ADAS plugin runtime for React Native hosts \u2014 plugin SDK, bundle pipeline with integrity verification, host bridge, surfaces. No Expo dependencies.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,7 +9,7 @@
9
9
  "build": "tsup"
10
10
  },
11
11
  "dependencies": {
12
- "@ateam-ai-mobile/core": "0.1.0",
12
+ "@ateam-ai-mobile/core": "0.1.1",
13
13
  "zustand": "^5.0.0"
14
14
  },
15
15
  "peerDependencies": {
@@ -27,7 +27,7 @@ function buildContext(pluginId: string, connectorId?: string): PluginContext {
27
27
  tenant: getTenant(),
28
28
  pluginId,
29
29
  connectorId,
30
- user: user ? { id: user.actorId || '', name: user.name || '', roles: [] } : undefined,
30
+ user: user ? { id: user.actorId || '', name: user.name || '', roles: user.roles || [] } : undefined,
31
31
  };
32
32
  }
33
33
 
@@ -17,6 +17,11 @@ import {
17
17
  import * as ReactNative from 'react-native';
18
18
  import { apiFetchRaw } from '@ateam-ai-mobile/core';
19
19
  import * as PluginSDKModule from '../sdk';
20
+ import SurfaceDrawer from '../surfaces/SurfaceDrawer';
21
+ import SurfaceCard from '../surfaces/SurfaceCard';
22
+ import SurfaceFullscreen from '../surfaces/SurfaceFullscreen';
23
+ import { useSurfaceStore } from '../registry/store';
24
+ import SurfaceDispatcher from '../registry/SurfaceDispatcher';
20
25
  import { resolveBundleModule } from '../host';
21
26
  import { sha256Hex } from '../utils/sha256';
22
27
  import { getBundleStorage, type BundleCacheEntry } from './storage';
@@ -51,9 +56,17 @@ const ReactShim: any = {
51
56
  Suspense: React.Suspense,
52
57
  };
53
58
 
54
- // Freeze PluginSDK shim to prevent bundle monkey-patching of register()
59
+ // Freeze PluginSDK shim to prevent bundle monkey-patching of register().
60
+ // Surface containers + registry ride along — the reference app's original
61
+ // shim exposed the FULL plugin-sdk index, and bundles built against it may
62
+ // import SurfaceDrawer/useSurfaceStore/etc. from '@adas/plugin-sdk'.
55
63
  const PluginSDKShim = Object.freeze({
56
64
  ...PluginSDKModule,
65
+ SurfaceDrawer,
66
+ SurfaceCard,
67
+ SurfaceFullscreen,
68
+ useSurfaceStore,
69
+ SurfaceDispatcher,
57
70
  PluginSDK: Object.freeze({
58
71
  ...PluginSDKModule.PluginSDK,
59
72
  register: PluginSDKModule.PluginSDK.register,
package/src/host.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * a bare host works with zero configuration.
6
6
  */
7
7
 
8
- import type { HapticsAPI, PluginNative } from './sdk/types';
8
+ import type { HapticsAPI, NativeCapabilities, PluginNative } from './sdk/types';
9
9
  import type { RegisteredPlugin } from './sdk/types';
10
10
 
11
11
  // ── Haptics ────────────────────────────────────────────────────────────────
@@ -62,6 +62,50 @@ export function getPluginNative(): PluginNative {
62
62
  return _pluginNative;
63
63
  }
64
64
 
65
+ /** Blocked-capability proxy: any call warns and is ignored (no throw) —
66
+ * matches the reference app's behaviour for undeclared capabilities. */
67
+ function blocked(api: string): any {
68
+ return new Proxy({}, {
69
+ get: (_t, method) => {
70
+ if (typeof method !== 'string') return undefined;
71
+ return () => {
72
+ console.warn(`[adas] native.${api}.${method} blocked — capability '${api}' not declared in the plugin manifest`);
73
+ };
74
+ },
75
+ });
76
+ }
77
+
78
+ /**
79
+ * Gate a PluginNative by the capabilities a plugin's manifest declares.
80
+ * Undeclared capabilities become warn-and-ignore proxies, so a plugin can
81
+ * only touch device APIs it asked for (per-plugin security model, preserved
82
+ * from the reference app). Connectivity is always allowed.
83
+ *
84
+ * Flag mapping mirrors the manifest contract: `storage` is gated by
85
+ * `offline` (offline data ⇒ local storage).
86
+ */
87
+ export function gatePluginNative(
88
+ native: PluginNative,
89
+ declared?: NativeCapabilities,
90
+ ): PluginNative {
91
+ const caps = declared || {};
92
+ return {
93
+ camera: caps.camera ? native.camera : blocked('camera'),
94
+ location: caps.location ? native.location : blocked('location'),
95
+ storage: caps.offline ? native.storage : blocked('storage'),
96
+ biometrics: caps.biometrics ? native.biometrics : blocked('biometrics'),
97
+ biometricsV2: caps.biometricsV2 ? native.biometricsV2 : blocked('biometricsV2'),
98
+ notifications: caps.notifications ? native.notifications : blocked('notifications'),
99
+ haptics: caps.haptics ? native.haptics : blocked('haptics'),
100
+ connectivity: native.connectivity,
101
+ fileSystem: caps.fileSystem ? native.fileSystem : blocked('fileSystem'),
102
+ cookies: caps.cookies ? native.cookies : blocked('cookies'),
103
+ sharing: caps.sharing ? native.sharing : blocked('sharing'),
104
+ scanner: caps.scanner ? native.scanner : blocked('scanner'),
105
+ nfc: caps.nfc ? native.nfc : blocked('nfc'),
106
+ };
107
+ }
108
+
65
109
  // ── Native (host-bundled) plugin registry ─────────────────────────────────
66
110
  // Plugins compiled into the host binary (dev plugins, first-party panels).
67
111
  // usePlugin checks this registry before hitting the remote bundle pipeline.
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ export {
22
22
  getHaptics,
23
23
  setPluginNativeProvider,
24
24
  getPluginNative,
25
+ gatePluginNative,
25
26
  registerNativePlugin,
26
27
  unregisterNativePlugin,
27
28
  nativePluginRegistry,
@@ -7,6 +7,7 @@
7
7
  * once at startup to override.
8
8
  */
9
9
  import { useMemo, useSyncExternalStore } from 'react';
10
+ import { useColorScheme } from 'react-native';
10
11
  import { ada, spacing, fontSize, borderRadius } from '@ateam-ai-mobile/core';
11
12
  import type { ThemeTokens } from './types';
12
13
 
@@ -37,7 +38,9 @@ const adaColors: ThemeColors = {
37
38
  };
38
39
 
39
40
  let _colors: ThemeColors = adaColors;
40
- let _isDark = false;
41
+ // null = host hasn't pinned it → track the device color scheme live
42
+ // (parity with the reference app, whose isDark followed useColorScheme()).
43
+ let _isDark: boolean | null = null;
41
44
  const _subscribers = new Set<() => void>();
42
45
 
43
46
  /** Override the plugin theme (host brand). Call once at startup — mounted
@@ -55,7 +58,9 @@ function subscribe(fn: () => void): () => void {
55
58
 
56
59
  export function usePluginTheme(): ThemeTokens {
57
60
  const colors = useSyncExternalStore(subscribe, () => _colors);
58
- const isDark = useSyncExternalStore(subscribe, () => _isDark);
61
+ const hostIsDark = useSyncExternalStore(subscribe, () => _isDark);
62
+ const scheme = useColorScheme();
63
+ const isDark = hostIsDark ?? scheme === 'dark';
59
64
 
60
65
  // Memoize so plugins don't re-render on every host render.
61
66
  return useMemo(() => ({