@egen-civitas/esm-platform 1.1.0 → 1.2.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.
@@ -0,0 +1,4 @@
1
+ export { createBridgeClient } from './client.js';
2
+ export type { BridgeClient, BridgeClientOptions, CallOptions, HostInfo } from './client.js';
3
+ export { DEFAULT_TIMEOUT_MS, HOST_PROTOCOL_NAME, MAX_MESSAGE_LENGTH, SUPPORTED_PROTOCOL, isSupportedProtocolVersion, parseHostMessage, } from './protocol.js';
4
+ export type { HostBridge, HostEvent, HostFailure, HostMessage, HostRequest, HostSuccess } from './protocol.js';
@@ -0,0 +1,2 @@
1
+ export { createBridgeClient } from './client.js';
2
+ export { DEFAULT_TIMEOUT_MS, HOST_PROTOCOL_NAME, MAX_MESSAGE_LENGTH, SUPPORTED_PROTOCOL, isSupportedProtocolVersion, parseHostMessage, } from './protocol.js';
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Protocole Host ↔ Shell, version 1 — voir docs/EGEN-FRAMEWORK-DEV.md, annexe 1.
3
+ * Transport : chaînes JSON UTF-8 via `window.egenHostBridge`.
4
+ */
5
+ /** Valeur du champ `p` de chaque message : tout message sans elle est ignoré. */
6
+ export declare const HOST_PROTOCOL_NAME = "egen-host";
7
+ /** Versions du protocole que CE client sait parler. Un Host hors de cette plage est `INCOMPATIBLE`. */
8
+ export declare const SUPPORTED_PROTOCOL: {
9
+ readonly min: 1;
10
+ readonly max: 1;
11
+ };
12
+ /**
13
+ * Taille maximale d'un message JSON, en caractères (proposition de la doc, à valider sur appareil). Au-delà, le Host
14
+ * doit fournir une référence de fichier (`FileHandle`) plutôt qu'un binaire inline.
15
+ */
16
+ export declare const MAX_MESSAGE_LENGTH: number;
17
+ /** Délai par défaut d'un appel avant `TIMEOUT`. */
18
+ export declare const DEFAULT_TIMEOUT_MS = 30000;
19
+ /**
20
+ * Contrat de pont que le Host injecte AVANT tout script de la page : `window.egenHostBridge`.
21
+ * Le framework ne connaît rien d'autre du natif (règles R2 / N2).
22
+ */
23
+ export interface HostBridge {
24
+ /** web → host : un message JSON. */
25
+ send(json: string): void;
26
+ /** host → web : le Host appelle `callback` avec un message JSON. Appelé UNE fois par le client. */
27
+ subscribe(callback: (json: string) => void): void;
28
+ }
29
+ export interface HostRequest {
30
+ p: typeof HOST_PROTOCOL_NAME;
31
+ v: number;
32
+ id: string;
33
+ ns: string;
34
+ m: string;
35
+ a?: unknown;
36
+ }
37
+ export interface HostSuccess {
38
+ p: typeof HOST_PROTOCOL_NAME;
39
+ v: number;
40
+ id: string;
41
+ ok: true;
42
+ r?: unknown;
43
+ }
44
+ export interface HostFailure {
45
+ p: typeof HOST_PROTOCOL_NAME;
46
+ v: number;
47
+ id: string;
48
+ ok: false;
49
+ /** Contenu NON fiable : validé par le client avant d'être converti en `PlatformError`. */
50
+ e: {
51
+ code?: unknown;
52
+ message?: unknown;
53
+ retryable?: unknown;
54
+ };
55
+ }
56
+ export interface HostEvent {
57
+ p: typeof HOST_PROTOCOL_NAME;
58
+ v: number;
59
+ ev: string;
60
+ d?: unknown;
61
+ }
62
+ export type HostMessage = HostSuccess | HostFailure | HostEvent;
63
+ export declare const KNOWN_ERROR_CODES: ReadonlySet<string>;
64
+ export declare function isSupportedProtocolVersion(version: unknown): version is number;
65
+ /**
66
+ * Décode un message du Host. Retourne `null` pour tout ce qui n'est pas un message du protocole : entrée non
67
+ * textuelle, trop longue, JSON invalide, autre valeur de `p`, forme inconnue. Ne lève JAMAIS et n'évalue rien.
68
+ *
69
+ * Le champ `v` n'est PAS filtré ici : le client doit pouvoir répondre « incompatible » à un appel en attente plutôt
70
+ * que de le laisser expirer.
71
+ */
72
+ export declare function parseHostMessage(raw: unknown): HostMessage | null;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Protocole Host ↔ Shell, version 1 — voir docs/EGEN-FRAMEWORK-DEV.md, annexe 1.
3
+ * Transport : chaînes JSON UTF-8 via `window.egenHostBridge`.
4
+ */
5
+ /** Valeur du champ `p` de chaque message : tout message sans elle est ignoré. */
6
+ export const HOST_PROTOCOL_NAME = 'egen-host';
7
+ /** Versions du protocole que CE client sait parler. Un Host hors de cette plage est `INCOMPATIBLE`. */
8
+ export const SUPPORTED_PROTOCOL = { min: 1, max: 1 };
9
+ /**
10
+ * Taille maximale d'un message JSON, en caractères (proposition de la doc, à valider sur appareil). Au-delà, le Host
11
+ * doit fournir une référence de fichier (`FileHandle`) plutôt qu'un binaire inline.
12
+ */
13
+ export const MAX_MESSAGE_LENGTH = 256 * 1024;
14
+ /** Délai par défaut d'un appel avant `TIMEOUT`. */
15
+ export const DEFAULT_TIMEOUT_MS = 30000;
16
+ export const KNOWN_ERROR_CODES = new Set([
17
+ 'UNAVAILABLE',
18
+ 'DENIED',
19
+ 'CANCELLED',
20
+ 'INVALID_ARGS',
21
+ 'TIMEOUT',
22
+ 'INCOMPATIBLE',
23
+ 'HOST_ERROR',
24
+ ]);
25
+ export function isSupportedProtocolVersion(version) {
26
+ return (Number.isInteger(version) &&
27
+ version >= SUPPORTED_PROTOCOL.min &&
28
+ version <= SUPPORTED_PROTOCOL.max);
29
+ }
30
+ /**
31
+ * Décode un message du Host. Retourne `null` pour tout ce qui n'est pas un message du protocole : entrée non
32
+ * textuelle, trop longue, JSON invalide, autre valeur de `p`, forme inconnue. Ne lève JAMAIS et n'évalue rien.
33
+ *
34
+ * Le champ `v` n'est PAS filtré ici : le client doit pouvoir répondre « incompatible » à un appel en attente plutôt
35
+ * que de le laisser expirer.
36
+ */
37
+ export function parseHostMessage(raw) {
38
+ if (typeof raw !== 'string' || raw.length === 0 || raw.length > MAX_MESSAGE_LENGTH) {
39
+ return null;
40
+ }
41
+ let value;
42
+ try {
43
+ value = JSON.parse(raw);
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
49
+ return null;
50
+ }
51
+ const message = value;
52
+ if (message.p !== HOST_PROTOCOL_NAME || typeof message.v !== 'number') {
53
+ return null;
54
+ }
55
+ if (typeof message.id === 'string' && typeof message.ok === 'boolean') {
56
+ if (message.ok) {
57
+ return { p: HOST_PROTOCOL_NAME, v: message.v, id: message.id, ok: true, r: message.r };
58
+ }
59
+ const e = typeof message.e === 'object' && message.e !== null && !Array.isArray(message.e) ? message.e : {};
60
+ return { p: HOST_PROTOCOL_NAME, v: message.v, id: message.id, ok: false, e };
61
+ }
62
+ if (typeof message.ev === 'string') {
63
+ return { p: HOST_PROTOCOL_NAME, v: message.v, ev: message.ev, d: message.d };
64
+ }
65
+ return null;
66
+ }
@@ -0,0 +1,215 @@
1
+ function _define_property(obj, key, value) {
2
+ if (key in obj) {
3
+ Object.defineProperty(obj, key, {
4
+ value: value,
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true
8
+ });
9
+ } else {
10
+ obj[key] = value;
11
+ }
12
+ return obj;
13
+ }
14
+ function _object_spread(target) {
15
+ for(var i = 1; i < arguments.length; i++){
16
+ var source = arguments[i] != null ? arguments[i] : {};
17
+ var ownKeys = Object.keys(source);
18
+ if (typeof Object.getOwnPropertySymbols === "function") {
19
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
20
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
21
+ }));
22
+ }
23
+ ownKeys.forEach(function(key) {
24
+ _define_property(target, key, source[key]);
25
+ });
26
+ }
27
+ return target;
28
+ }
29
+ import { describe, expect, it } from 'vitest';
30
+ import { MAX_MESSAGE_LENGTH, isSupportedProtocolVersion, parseHostMessage } from './protocol';
31
+ var msg = function msg(extra) {
32
+ return JSON.stringify(_object_spread({
33
+ p: 'egen-host',
34
+ v: 1
35
+ }, extra));
36
+ };
37
+ describe('isSupportedProtocolVersion', function() {
38
+ it('accepte la v1 uniquement', function() {
39
+ expect(isSupportedProtocolVersion(1)).toBe(true);
40
+ expect(isSupportedProtocolVersion(0)).toBe(false);
41
+ expect(isSupportedProtocolVersion(2)).toBe(false);
42
+ expect(isSupportedProtocolVersion(1.5)).toBe(false);
43
+ expect(isSupportedProtocolVersion('1')).toBe(false);
44
+ });
45
+ });
46
+ describe('parseHostMessage', function() {
47
+ it('décode une réponse de succès', function() {
48
+ expect(parseHostMessage(msg({
49
+ id: 'a',
50
+ ok: true,
51
+ r: 42
52
+ }))).toEqual({
53
+ p: 'egen-host',
54
+ v: 1,
55
+ id: 'a',
56
+ ok: true,
57
+ r: 42
58
+ });
59
+ });
60
+ it("décode une réponse d'échec et normalise un `e` absent en objet vide", function() {
61
+ expect(parseHostMessage(msg({
62
+ id: 'a',
63
+ ok: false,
64
+ e: {
65
+ code: 'DENIED'
66
+ }
67
+ }))).toMatchObject({
68
+ ok: false,
69
+ e: {
70
+ code: 'DENIED'
71
+ }
72
+ });
73
+ expect(parseHostMessage(msg({
74
+ id: 'a',
75
+ ok: false
76
+ }))).toMatchObject({
77
+ ok: false,
78
+ e: {}
79
+ });
80
+ expect(parseHostMessage(msg({
81
+ id: 'a',
82
+ ok: false,
83
+ e: 'x'
84
+ }))).toMatchObject({
85
+ ok: false,
86
+ e: {}
87
+ });
88
+ });
89
+ it('décode un événement', function() {
90
+ expect(parseHostMessage(msg({
91
+ ev: 'lifecycle.resume',
92
+ d: {
93
+ a: 1
94
+ }
95
+ }))).toEqual({
96
+ p: 'egen-host',
97
+ v: 1,
98
+ ev: 'lifecycle.resume',
99
+ d: {
100
+ a: 1
101
+ }
102
+ });
103
+ });
104
+ it('ne filtre pas la version (le client répond « incompatible » plutôt que de laisser expirer)', function() {
105
+ expect(parseHostMessage(JSON.stringify({
106
+ p: 'egen-host',
107
+ v: 9,
108
+ id: 'a',
109
+ ok: true
110
+ }))).toMatchObject({
111
+ v: 9
112
+ });
113
+ });
114
+ it.each([
115
+ [
116
+ 'non textuel',
117
+ 42
118
+ ],
119
+ [
120
+ 'objet',
121
+ {}
122
+ ],
123
+ [
124
+ 'null',
125
+ null
126
+ ],
127
+ [
128
+ 'chaîne vide',
129
+ ''
130
+ ],
131
+ [
132
+ 'JSON invalide',
133
+ '{pas du json'
134
+ ],
135
+ [
136
+ 'tableau',
137
+ '[]'
138
+ ],
139
+ [
140
+ 'nombre JSON',
141
+ '12'
142
+ ],
143
+ [
144
+ 'sans p',
145
+ JSON.stringify({
146
+ v: 1,
147
+ id: 'a',
148
+ ok: true
149
+ })
150
+ ],
151
+ [
152
+ 'mauvais p',
153
+ JSON.stringify({
154
+ p: 'autre',
155
+ v: 1,
156
+ id: 'a',
157
+ ok: true
158
+ })
159
+ ],
160
+ [
161
+ 'v non numérique',
162
+ JSON.stringify({
163
+ p: 'egen-host',
164
+ v: '1',
165
+ id: 'a',
166
+ ok: true
167
+ })
168
+ ],
169
+ [
170
+ 'ni réponse ni événement',
171
+ msg({
172
+ foo: 1
173
+ })
174
+ ],
175
+ [
176
+ 'id non textuel',
177
+ msg({
178
+ id: 5,
179
+ ok: true
180
+ })
181
+ ],
182
+ [
183
+ 'ok non booléen',
184
+ msg({
185
+ id: 'a',
186
+ ok: 'oui'
187
+ })
188
+ ],
189
+ [
190
+ 'ev non textuel',
191
+ msg({
192
+ ev: 5
193
+ })
194
+ ]
195
+ ])('ignore : %s', function(_label, raw) {
196
+ expect(parseHostMessage(raw)).toBeNull();
197
+ });
198
+ it('ignore un message trop long', function() {
199
+ expect(parseHostMessage(msg({
200
+ id: 'a',
201
+ ok: true,
202
+ r: 'x'.repeat(MAX_MESSAGE_LENGTH)
203
+ }))).toBeNull();
204
+ });
205
+ it("n'évalue rien : un contenu qui ressemble à du code reste une donnée", function() {
206
+ var parsed = parseHostMessage(msg({
207
+ id: 'a',
208
+ ok: true,
209
+ r: 'alert(1)//</script>'
210
+ }));
211
+ expect(parsed).toMatchObject({
212
+ r: 'alert(1)//</script>'
213
+ });
214
+ });
215
+ });
@@ -1,14 +1,17 @@
1
1
  import type { CapabilityName } from '@egen-civitas/esm-globals';
2
- import type { Platform, PlatformEnvironment } from './types.js';
3
- /** Les capacités d'une plateforme, indexées par leur nom (`CapabilityName` = clés de `Platform`). */
4
- export type CapabilityMap = Pick<Platform, CapabilityName>;
2
+ import type { CapabilityInterfaces, Platform, PlatformEnvironment } from './types.js';
3
+ /** Les capacités d'une plateforme, indexées par leur nom (clés de `CapabilityInterfaces`). */
4
+ export type CapabilityMap = {
5
+ [K in keyof CapabilityInterfaces]: CapabilityInterfaces[K];
6
+ };
5
7
  /** Implémentations (éventuellement partielles) fournies par un adaptateur ; ce qui manque reste `UNAVAILABLE`. */
6
8
  export type CapabilityOverrides = {
7
- [K in CapabilityName]?: Partial<CapabilityMap[K]>;
9
+ [K in keyof CapabilityInterfaces]?: Partial<CapabilityInterfaces[K]>;
8
10
  };
9
11
  /**
10
- * Toutes les capacités, sous forme d'objets dont chaque méthode échoue en `UNAVAILABLE`. Une capacité absente EXISTE
11
- * donc toujours comme objet (règle C2) ; c'est `has()` qui dit si elle est réellement fournie.
12
+ * Toutes les capacités DU REGISTRE, sous forme d'objets dont chaque méthode échoue en `UNAVAILABLE`. Une capacité
13
+ * absente EXISTE donc toujours comme objet (règle C2) ; c'est `has()` qui dit si elle est réellement fournie.
14
+ * Dérivé de `registry.ts` : ajouter une capacité au registre l'ajoute ici sans rien modifier.
12
15
  */
13
16
  export declare function createUnavailableCapabilities(): CapabilityMap;
14
17
  export interface AssemblePlatformOptions {
@@ -17,10 +20,15 @@ export interface AssemblePlatformOptions {
17
20
  capabilities?: CapabilityOverrides;
18
21
  /** Appelée à CHAQUE lecture de `platform.ready` (évite un rejet non observé si personne ne l'attend). */
19
22
  ready: () => Promise<void>;
23
+ /**
24
+ * Filtre dynamique en plus de la présence d'un adaptateur : une capacité n'est disponible que si elle est fournie
25
+ * ET que ce prédicat l'accepte (natif : le Host l'a annoncée au handshake). Défaut : toujours vrai.
26
+ */
27
+ available?: (capability: CapabilityName) => boolean;
20
28
  }
21
29
  /**
22
30
  * Assemble un objet `Platform` : les capacités fournies remplacent celles indisponibles, et `has()` n'est vrai que pour
23
31
  * elles. Point unique de construction, partagé par `getPlatform()`, les adaptateurs (C4, C5) et les mocks (C9) : ils
24
32
  * ne peuvent donc pas diverger du contrat.
25
33
  */
26
- export declare function assemblePlatform({ environment, capabilities, ready }: AssemblePlatformOptions): Platform;
34
+ export declare function assemblePlatform({ environment, capabilities, ready, available, }: AssemblePlatformOptions): Platform;
@@ -1,4 +1,5 @@
1
1
  import { unavailable } from './errors.js';
2
+ import { getCapabilityDefinition, listCapabilityNames } from './registry.js';
2
3
  /** Méthode asynchrone d'une capacité absente : REJETTE `UNAVAILABLE` (jamais de `null` ambigu). */
3
4
  const rejecting = (capability, method) => () => Promise.reject(unavailable(capability, method));
4
5
  /**
@@ -9,52 +10,27 @@ const throwing = (capability, method) => () => {
9
10
  throw unavailable(capability, method);
10
11
  };
11
12
  /**
12
- * Toutes les capacités, sous forme d'objets dont chaque méthode échoue en `UNAVAILABLE`. Une capacité absente EXISTE
13
- * donc toujours comme objet (règle C2) ; c'est `has()` qui dit si elle est réellement fournie.
13
+ * Toutes les capacités DU REGISTRE, sous forme d'objets dont chaque méthode échoue en `UNAVAILABLE`. Une capacité
14
+ * absente EXISTE donc toujours comme objet (règle C2) ; c'est `has()` qui dit si elle est réellement fournie.
15
+ * Dérivé de `registry.ts` : ajouter une capacité au registre l'ajoute ici sans rien modifier.
14
16
  */
15
17
  export function createUnavailableCapabilities() {
16
- return {
17
- session: {
18
- getAuthorization: rejecting('session', 'getAuthorization'),
19
- setTokens: rejecting('session', 'setTokens'),
20
- refresh: rejecting('session', 'refresh'),
21
- clear: rejecting('session', 'clear'),
22
- },
23
- secureStorage: {
24
- get: rejecting('secureStorage', 'get'),
25
- set: rejecting('secureStorage', 'set'),
26
- remove: rejecting('secureStorage', 'remove'),
27
- },
28
- openExternal: { open: rejecting('openExternal', 'open') },
29
- lifecycle: {
30
- onResume: throwing('lifecycle', 'onResume'),
31
- onPause: throwing('lifecycle', 'onPause'),
32
- },
33
- permissions: {
34
- check: rejecting('permissions', 'check'),
35
- request: rejecting('permissions', 'request'),
36
- },
37
- files: {
38
- select: rejecting('files', 'select'),
39
- download: rejecting('files', 'download'),
40
- },
41
- camera: { capture: rejecting('camera', 'capture') },
42
- push: {
43
- register: rejecting('push', 'register'),
44
- onMessage: throwing('push', 'onMessage'),
45
- },
46
- biometric: {
47
- isAvailable: rejecting('biometric', 'isAvailable'),
48
- authenticate: rejecting('biometric', 'authenticate'),
49
- },
50
- };
18
+ const capabilities = {};
19
+ for (const name of listCapabilityNames()) {
20
+ const methods = getCapabilityDefinition(name)?.methods ?? {};
21
+ capabilities[name] = Object.fromEntries(Object.entries(methods).map(([method, kind]) => [
22
+ method,
23
+ kind === 'subscribe' ? throwing(name, method) : rejecting(name, method),
24
+ ]));
25
+ }
26
+ return capabilities;
51
27
  }
52
28
  /**
53
29
  * Assemble un objet `Platform` : les capacités fournies remplacent celles indisponibles, et `has()` n'est vrai que pour
54
30
  * elles. Point unique de construction, partagé par `getPlatform()`, les adaptateurs (C4, C5) et les mocks (C9) : ils
55
31
  * ne peuvent donc pas diverger du contrat.
56
32
  */
57
- export function assemblePlatform({ environment, capabilities = {}, ready }) {
33
+ export function assemblePlatform({ environment, capabilities = {}, ready, available, }) {
58
34
  const base = createUnavailableCapabilities();
59
35
  const provided = new Set(Object.keys(capabilities));
60
36
  const merged = {};
@@ -66,7 +42,7 @@ export function assemblePlatform({ environment, capabilities = {}, ready }) {
66
42
  get ready() {
67
43
  return ready();
68
44
  },
69
- has: (capability) => provided.has(capability),
45
+ has: (capability) => provided.has(capability) && (available?.(capability) ?? true),
70
46
  ...merged,
71
47
  };
72
48
  }
package/dist/detect.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { HostBridge } from './bridge/protocol.js';
1
2
  import type { PlatformEnvironment } from './types.js';
2
3
  /**
3
4
  * Environnement d'exécution courant. Source UNIQUE : `window.egenTarget`, posé au build.
@@ -9,10 +10,16 @@ export declare function getPlatformEnvironment(): PlatformEnvironment;
9
10
  /** `true` en Android/iOS. */
10
11
  export declare function isNativePlatform(): boolean;
11
12
  /**
12
- * `true` si le Host a injecté un pont conforme au contrat (`window.egenHostBridge = { send, subscribe }`, tâche C5).
13
- * Ne vérifie que la FORME du pont : le handshake (version, capacités) est fait par le client de pont (C5).
13
+ * Le pont injecté par le Host (`window.egenHostBridge = { send, subscribe }`), ou `null` s'il est absent ou non
14
+ * conforme. Ne vérifie que la FORME du pont : le handshake (version, capacités) est fait par le client de pont.
14
15
  * Jamais de détection par User-Agent ni par bibliothèque d'enveloppe (N4).
15
16
  *
16
17
  * @category Platform
17
18
  */
19
+ export declare function getHostBridge(): HostBridge | null;
20
+ /**
21
+ * `true` si le Host a injecté un pont conforme au contrat.
22
+ *
23
+ * @category Platform
24
+ */
18
25
  export declare function hasHostBridge(): boolean;
package/dist/detect.js CHANGED
@@ -13,16 +13,26 @@ export function isNativePlatform() {
13
13
  return isNativeTarget();
14
14
  }
15
15
  /**
16
- * `true` si le Host a injecté un pont conforme au contrat (`window.egenHostBridge = { send, subscribe }`, tâche C5).
17
- * Ne vérifie que la FORME du pont : le handshake (version, capacités) est fait par le client de pont (C5).
16
+ * Le pont injecté par le Host (`window.egenHostBridge = { send, subscribe }`), ou `null` s'il est absent ou non
17
+ * conforme. Ne vérifie que la FORME du pont : le handshake (version, capacités) est fait par le client de pont.
18
18
  * Jamais de détection par User-Agent ni par bibliothèque d'enveloppe (N4).
19
19
  *
20
20
  * @category Platform
21
21
  */
22
- export function hasHostBridge() {
22
+ export function getHostBridge() {
23
23
  if (typeof window === 'undefined') {
24
- return false;
24
+ return null;
25
25
  }
26
26
  const bridge = window.egenHostBridge;
27
- return !!bridge && typeof bridge.send === 'function' && typeof bridge.subscribe === 'function';
27
+ return bridge && typeof bridge.send === 'function' && typeof bridge.subscribe === 'function'
28
+ ? bridge
29
+ : null;
30
+ }
31
+ /**
32
+ * `true` si le Host a injecté un pont conforme au contrat.
33
+ *
34
+ * @category Platform
35
+ */
36
+ export function hasHostBridge() {
37
+ return getHostBridge() !== null;
28
38
  }
package/dist/index.d.ts CHANGED
@@ -2,3 +2,5 @@ export * from './types.js';
2
2
  export * from './errors.js';
3
3
  export * from './detect.js';
4
4
  export { getPlatform, registerPlatformCapabilities } from './platform.js';
5
+ export { getHostInfo } from './native.js';
6
+ export * from './bridge/index.js';
package/dist/index.js CHANGED
@@ -10,3 +10,5 @@ export * from './types.js';
10
10
  export * from './errors.js';
11
11
  export * from './detect.js';
12
12
  export { getPlatform, registerPlatformCapabilities } from './platform.js';
13
+ export { getHostInfo } from './native.js';
14
+ export * from './bridge/index.js';