@agentshouse/app-bridge 0.1.0-alpha.10 → 0.1.0-alpha.12

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The renderer-side client of the agents.house App bridge. An App served by House
4
4
  receives one message port before its own scripts run; this package is that
5
- port's one listener. It carries eight families:
5
+ port's one listener. It carries nine families:
6
6
 
7
7
  - **Navigation** - the part of the shell's URL below the App's path, with its
8
8
  query and fragment. The shell delivers it when the App starts and whenever the
@@ -58,11 +58,22 @@ port's one listener. It carries eight families:
58
58
  refusal is House's `{ error: { code } }`, `app_release_not_found` for an
59
59
  App with no release; a read House does not answer, or one that outlived
60
60
  the browser's signed-in User, is `null`.
61
+ - **App messages** - `messages(listener)` hands the listener each message
62
+ another holder of this App sends to this User's running copies, as `from`,
63
+ the sender's User id, and `body`, the JSON value they sent, until the
64
+ function it returns is called. App code sends one through the Runtime's
65
+ `call('apps/messages/send', { to, body })` with the recipient's User id and
66
+ a body of at most 32 KiB of JSON; House fills in the App and relays it only
67
+ to copies running now, storing nothing. The panel sends none.
61
68
  - **App screenshot read** - given an App reference, `readScreenshot(app)`
62
69
  answers the image this browser captured of that App's screen the first time
63
70
  it ran its current release, as a PNG `Blob` at most 1200 pixels wide, or
64
71
  `null` when this browser holds none. The image stays in the browser; a Site
65
72
  holds none.
73
+ - **Site screenshot read** - given one of the User's Site identifiers,
74
+ `readSiteScreenshot(site)` answers the image House captured of that Site
75
+ after its latest release, as a JPEG `Blob`, or `null` when House holds none
76
+ or does not answer. A Site's own renderer reads none.
66
77
 
67
78
  The package carries no credential handling and no Runtime family. It surfaces
68
79
  the dedicated Runtime port the worker transfers over the bridge as a plain
@@ -124,6 +135,8 @@ records in `consents` each
124
135
  choice leaves, records in `tabs` each `setTab` the shell would take and ignores
125
136
  any other, answers a release code read from the `sources` it was given, or
126
137
  `null`, answers `readScreenshot` from the `screenshots` it was given by App
127
- reference, answers every `install()` `'manual'`, as a browser with no install
138
+ reference and `readSiteScreenshot` from the `siteScreenshots` it was given by
139
+ Site identifier, answers every `install()` `'manual'`, as a browser with no install
128
140
  prompt does, answers every `notifications()` `'unavailable'`, as a browser
129
- without push does, settles every `setBadge`, and attaches a Runtime port.
141
+ without push does, settles every `setBadge`, delivers each App message
142
+ `message({ from, body })` plays, and attaches a Runtime port.
@@ -1,4 +1,4 @@
1
- import type { HouseBridgePort, HouseGaChoice, HouseMessagePort, HouseSourceDownload, HouseSourceRefusal, HouseSourceTop, HouseStatus, HouseTab } from './wire.js';
1
+ import type { HouseAppMessage, HouseBridgePort, HouseGaChoice, HouseMessagePort, HouseSourceDownload, HouseSourceRefusal, HouseSourceTop, HouseStatus, HouseTab } from './wire.js';
2
2
  export declare class HouseCeremonyRefused extends Error {
3
3
  readonly path: string | null;
4
4
  constructor(path: string | null);
@@ -30,8 +30,10 @@ export interface HouseBridge {
30
30
  sourceTop(app: string, release?: string): Promise<HouseSourceTop | HouseSourceRefusal | null>;
31
31
  sourceDownload(app: string, release?: string): Promise<HouseSourceDownload | HouseSourceRefusal | null>;
32
32
  readScreenshot(app: string): Promise<Blob | null>;
33
+ readSiteScreenshot(site: string): Promise<Blob | null>;
33
34
  status(): HouseStatus | null;
34
35
  onStatus(listener: (status: HouseStatus) => void): () => void;
36
+ messages(listener: (message: HouseAppMessage) => void): () => void;
35
37
  gaConsent(choice: HouseGaChoice): void;
36
38
  }
37
39
  export declare function connectHouseBridge(source?: Promise<HouseBridgePort>): HouseBridge;
@@ -59,6 +59,7 @@ export function connectHouseBridge(source = heldBridge()) {
59
59
  let nextScreenshot = 0;
60
60
  const addressListeners = new Set();
61
61
  const statusListeners = new Set();
62
+ const messageListeners = new Set();
62
63
  let outbox = [];
63
64
  let held = null;
64
65
  let address = null;
@@ -85,6 +86,12 @@ export function connectHouseBridge(source = heldBridge()) {
85
86
  listener(status);
86
87
  return;
87
88
  }
89
+ if (data.house === 'app-message') {
90
+ const { from, body } = data;
91
+ for (const listener of messageListeners)
92
+ listener({ from, body });
93
+ return;
94
+ }
88
95
  if (data.house === 'address') {
89
96
  address = String(data.address);
90
97
  if (data.navigated === true)
@@ -172,6 +179,13 @@ export function connectHouseBridge(source = heldBridge()) {
172
179
  send({ house, id, app, release });
173
180
  return pending.promise;
174
181
  }
182
+ function screenshot(house, asked) {
183
+ const pending = settled();
184
+ const id = ++nextScreenshot;
185
+ screenshots.set(id, pending.settle);
186
+ send({ house, id, ...asked });
187
+ return pending.promise;
188
+ }
175
189
  function navigate(mode, asked) {
176
190
  const pending = settled();
177
191
  navigations.push({ address: asked, settle: pending.settle });
@@ -239,11 +253,10 @@ export function connectHouseBridge(source = heldBridge()) {
239
253
  return readSource('source-download', app, release);
240
254
  },
241
255
  readScreenshot(app) {
242
- const pending = settled();
243
- const id = ++nextScreenshot;
244
- screenshots.set(id, pending.settle);
245
- send({ house: 'screenshot-read', id, app });
246
- return pending.promise;
256
+ return screenshot('screenshot-read', { app });
257
+ },
258
+ readSiteScreenshot(site) {
259
+ return screenshot('site-screenshot-read', { site });
247
260
  },
248
261
  status() {
249
262
  return status;
@@ -254,6 +267,12 @@ export function connectHouseBridge(source = heldBridge()) {
254
267
  statusListeners.delete(listener);
255
268
  };
256
269
  },
270
+ messages(listener) {
271
+ messageListeners.add(listener);
272
+ return () => {
273
+ messageListeners.delete(listener);
274
+ };
275
+ },
257
276
  gaConsent(choice) {
258
277
  send({ house: 'ga/consent', choice });
259
278
  },
@@ -1,3 +1,3 @@
1
1
  export { connectHouseBridge, HouseCeremonyRefused, HouseNavigationRefused, type HouseBridge, type HouseImageCopy, } from './bridge.js';
2
2
  export { HOUSE_ADDRESS_MAX_CHARS } from './wire.js';
3
- export type { HouseBridgeEvent, HouseBridgePort, HouseCredentialState, HouseGa, HouseGaChoice, HouseMessagePort, HouseNavigationMode, HouseSourceDownload, HouseSourceFile, HouseSourceRefusal, HouseSourceTop, HouseStatus, HouseSyncState, } from './wire.js';
3
+ export type { HouseAppMessage, HouseBridgeEvent, HouseBridgePort, HouseCredentialState, HouseGa, HouseGaChoice, HouseMessagePort, HouseNavigationMode, HouseSourceDownload, HouseSourceFile, HouseSourceRefusal, HouseSourceTop, HouseStatus, HouseSyncState, } from './wire.js';
@@ -1,5 +1,5 @@
1
1
  import type { HouseImageCopy } from './bridge.js';
2
- import type { HouseBridgePort, HouseGaChoice, HouseMessagePort, HouseNavigationMode, HouseSourceDownload, HouseSourceTop, HouseStatus, HouseTab } from './wire.js';
2
+ import type { HouseAppMessage, HouseBridgePort, HouseGaChoice, HouseMessagePort, HouseNavigationMode, HouseSourceDownload, HouseSourceTop, HouseStatus, HouseTab } from './wire.js';
3
3
  export interface HouseBridgeNavigation {
4
4
  readonly mode: HouseNavigationMode;
5
5
  readonly address: string;
@@ -13,6 +13,7 @@ export interface HouseBridgeTestHost {
13
13
  address(): string;
14
14
  open(address: string): void;
15
15
  publish(status: HouseStatus): void;
16
+ message(message: HouseAppMessage): void;
16
17
  attachRuntime(runtime: HouseMessagePort): void;
17
18
  }
18
19
  export interface HouseBridgeTestHostOptions {
@@ -26,5 +27,6 @@ export interface HouseBridgeTestHostOptions {
26
27
  readonly download: HouseSourceDownload;
27
28
  }[];
28
29
  readonly screenshots?: Readonly<Record<string, Blob>>;
30
+ readonly siteScreenshots?: Readonly<Record<string, Blob>>;
29
31
  }
30
32
  export declare function createHouseBridgeTestHost(options?: HouseBridgeTestHostOptions): HouseBridgeTestHost;
@@ -123,6 +123,11 @@ export function createHouseBridgeTestHost(options = {}) {
123
123
  const held = typeof asked.app === 'string' ? options.screenshots?.[asked.app] : undefined;
124
124
  deliver({ house: 'screenshot', id: asked.id, image: held ?? null });
125
125
  }
126
+ else if (data.house === 'site-screenshot-read') {
127
+ const asked = data;
128
+ const held = typeof asked.site === 'string' ? options.siteScreenshots?.[asked.site] : undefined;
129
+ deliver({ house: 'screenshot', id: asked.id, image: held ?? null });
130
+ }
126
131
  }
127
132
  const port = {
128
133
  postMessage(message) {
@@ -158,6 +163,9 @@ export function createHouseBridgeTestHost(options = {}) {
158
163
  arrive(appAddressOf('/', asked), false);
159
164
  },
160
165
  publish,
166
+ message(message) {
167
+ deliver({ house: 'app-message', from: message.from, body: message.body });
168
+ },
161
169
  attachRuntime(runtime) {
162
170
  deliver({ house: 'runtime' }, [runtime]);
163
171
  },
@@ -65,5 +65,9 @@ export interface HouseSourceRefusal {
65
65
  };
66
66
  }
67
67
  export type HouseTab = TabChange;
68
+ export interface HouseAppMessage {
69
+ readonly from: string;
70
+ readonly body: unknown;
71
+ }
68
72
  export declare const HOUSE_ADDRESS_MAX_CHARS = 1000;
69
73
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agentshouse/app-bridge",
3
- "version": "0.1.0-alpha.10",
4
- "description": "Renderer-side client of the agents.house App bridge: navigation, the tab title and icon, ceremonies, installation, notifications and the icon badge, status, Site image reads, App release code and App screenshot reads, with an in-page test host.",
3
+ "version": "0.1.0-alpha.12",
4
+ "description": "Renderer-side client of the agents.house App bridge: navigation, the tab title and icon, ceremonies, installation, notifications and the icon badge, status, Site image reads, App release code, App and Site screenshot reads, and App messages, with an in-page test host.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
7
7
  "sideEffects": false,