Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/extension/src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ Object.defineProperties(globalThis.kernel, {
value: async (message: CommandMessage<never>) =>
await streams.writer.next(message),
},
helloThere: {
value: async () => {
await streams.writer.next({ type: Command.HelloThere, data: null });
}
}
});
harden(globalThis.kernel);

Expand All @@ -54,6 +59,7 @@ async function handleMessages(): Promise<void> {
case Command.CapTpCall:
case Command.CapTpInit:
case Command.Ping:
case Command.HelloThere:
console.log(message.data);
break;
default:
Expand Down
2 changes: 1 addition & 1 deletion packages/extension/src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"action": {},
"permissions": ["offscreen"],
"sandbox": {
"pages": ["iframe.html"]
"pages": ["iframe.html", "poc-iframe-angel.html", "poc-iframe-shadow.html"]
},
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'none'; frame-ancestors 'none';",
Expand Down
5 changes: 4 additions & 1 deletion packages/extension/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type MessageId = string;

type DataObject =
| Primitive
| Transferable
| Promise<DataObject>
| DataObject[]
| { [key: string]: DataObject };
Expand All @@ -29,6 +30,7 @@ export enum Command {
CapTpInit = 'makeCapTp',
Evaluate = 'evaluate',
Ping = 'ping',
HelloThere = 'helloThere'
}

export type CapTpPayload = {
Expand All @@ -40,7 +42,8 @@ export type CommandMessage<TargetType extends ExtensionMessageTarget> =
| CommandLike<Command.Ping, null | 'pong', TargetType>
| CommandLike<Command.Evaluate, string, TargetType>
| CommandLike<Command.CapTpInit, null, TargetType>
| CommandLike<Command.CapTpCall, CapTpPayload, TargetType>;
| CommandLike<Command.CapTpCall, CapTpPayload, TargetType>
| CommandLike<Command.HelloThere, null, TargetType>;

export type ExtensionMessage = CommandMessage<ExtensionMessageTarget>;
export type IframeMessage = CommandMessage<never>;
Expand Down
9 changes: 9 additions & 0 deletions packages/extension/src/offscreen.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { createWindow } from '@metamask/snaps-utils';
import { makeOffscreenBackgroundStreamPair } from './extension-stream-pairs.js';
import { IframeManager } from './iframe-manager.js';
import type { CommandMessage } from './message.js';
import { Command } from './message.js';
import { performIntroduction } from '@ocap/streams';
import { HELLO_THERE } from './poc-constants.js';

main().catch(console.error);

Expand Down Expand Up @@ -37,6 +40,12 @@ async function main(): Promise<void> {
case Command.Ping:
await reply(Command.Ping, 'pong');
break;
case Command.HelloThere:
console.log(HELLO_THERE);
await performIntroduction(
await createWindow('poc-iframe-angel.html', 'poc-iframe-angel'),
await createWindow('poc-iframe-shadow.html', 'poc-iframe-shadow'));
break;
default:
console.error(
// @ts-expect-error The type of `message` is `never`, but this could happen at runtime.
Expand Down
3 changes: 3 additions & 0 deletions packages/extension/src/poc-constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const HELLO_THERE = 'Hello there...';
export const THE_ANGEL = 'The angel from my nightmare...';
export const THE_SHADOW = 'The shadow in the background of the morgue.';
9 changes: 9 additions & 0 deletions packages/extension/src/poc-iframe-angel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Poc Iframe Angel</title>
<script src="poc-iframe-angel.ts" type="module"></script>
</head>
<body></body>
</html>
14 changes: 14 additions & 0 deletions packages/extension/src/poc-iframe-angel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { receiveMessagePort } from '@ocap/streams';
import { THE_ANGEL } from './poc-constants.js';

main().catch(console.error);

/**
* The main function for the iframe.
*/
async function main(): Promise<void> {
const port = await receiveMessagePort();

console.log(THE_ANGEL);
port.postMessage(THE_ANGEL);
}
9 changes: 9 additions & 0 deletions packages/extension/src/poc-iframe-shadow.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Poc Iframe Shadow</title>
<script src="poc-iframe-shadow.ts" type="module"></script>
</head>
<body></body>
</html>
16 changes: 16 additions & 0 deletions packages/extension/src/poc-iframe-shadow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { receiveMessagePort } from '@ocap/streams';
import { THE_ANGEL, THE_SHADOW } from './poc-constants.js';

main().catch(console.error);

/**
* The main function for the iframe.
*/
async function main(): Promise<void> {
(await receiveMessagePort()).onmessage = (message: MessageEvent): void => {
if (message.data !== THE_ANGEL) {
return;
}
console.log(THE_SHADOW);
}
}
2 changes: 2 additions & 0 deletions packages/extension/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export default defineConfig(({ mode }) => ({
background: path.resolve(projectRoot, 'background.ts'),
offscreen: path.resolve(projectRoot, 'offscreen.html'),
iframe: path.resolve(projectRoot, 'iframe.html'),
iframe1: path.resolve(projectRoot, 'poc-iframe-angel.html'),
iframe2: path.resolve(projectRoot, 'poc-iframe-shadow.html'),
},
output: {
entryFileNames: '[name].js',
Expand Down
1 change: 1 addition & 0 deletions packages/streams/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe('index', () => {
'makeMessagePortWriter',
'initializeMessageChannel',
'receiveMessagePort',
'performIntroduction',
]),
);
});
Expand Down
1 change: 1 addition & 0 deletions packages/streams/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export {
initializeMessageChannel,
receiveMessagePort,
performIntroduction,
} from './message-channel.js';
export type { StreamPair } from './stream-pair.js';
export type { Connection } from './connection.js';
Expand Down
44 changes: 44 additions & 0 deletions packages/streams/src/message-channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,47 @@ export async function receiveMessagePort(): Promise<MessagePort> {
window.addEventListener('message', listener);
return promise;
}

/**
* Expects both target windows are awaiting a message port with receiveMessagePort();
*
* @param targetWindow1
* @param targetWindow2
* @returns
*/
export async function performIntroduction(
targetWindow1: Window,
targetWindow2: Window,
): Promise<void> {
const { port1, port2 } = new MessageChannel();

const { promise, resolve, reject } = makePromiseKit<MessagePort>();
// Assigning to the `onmessage` property initializes the port's message queue.
port1.onmessage = (message: MessageEvent): void => {
if (!isAckMessage(message.data)) {
reject(
new Error(
`Received unexpected message via message port:\n${stringify(
message.data,
)}`,
),
);
return;
}

resolve(port1);
};

const initMessage: InitializeMessage = {
type: MessageType.Initialize,
};
targetWindow1.postMessage(initMessage, '*', [port2]);

await promise.catch((error) => {
port1.close();
throw error;
})
.finally(() => (port1.onmessage = null));

targetWindow2.postMessage(initMessage, '*', [port1]);
}