Skip to content

Expose createProxy #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 24, 2025
Merged
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
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,74 @@ For further information please consult the Jupyter documentation:
- Creating an extension: https://jupyterlab.readthedocs.io/en/stable/extension/extension_dev.html
- Adding commands to the command registry: https://jupyterlab.readthedocs.io/en/stable/extension/extension_points.html#commands

### Registering Callbacks

If you would like to register a callback to be executed when a particular event occurs in the JupyterLab, you can make use of the `createProxy` function from the `jupyter-iframe-commands-host` package. This function allows you to create a proxy to be passed to the IFrame as a command `args`, so it can be invoked in a JupyterLab command.

On the host, define the callback function:

```js
import { createBridge, createProxy } from 'jupyter-iframe-commands-host';

const commandBridge = createBridge({ iframeId: 'jupyterlab' });

const kernelStatus = async ({ displayName, isBusy }) => {
console.log('Received kernel status update from the iframe');
console.log('Display Name:', displayName);
console.log('Is Busy:', isBusy);
};

await commandBridge.execute('kernel-status', createProxy({ kernelStatus }));
```

In your custom JupyterLab extension, you can define a command:

```ts
const demoPlugin: JupyterFrontEndPlugin<void> = {
id: 'jupyter-iframe-commands:demo-callback',
autoStart: true,
description: 'Using host callbacks',
requires: [ILabStatus, INotebookTracker],
activate: async (
app: JupyterFrontEnd,
labStatus: ILabStatus,
tracker: INotebookTracker
) => {
const { commands } = app;

commands.addCommand('kernel-status', {
label: 'Kernel Status',
execute: args => {
const kernelStatus = args['kernelStatus'] as unknown as (
args?: any
) => void;

labStatus.busySignal.connect(async () => {
const kernelSpec =
await tracker.currentWidget?.sessionContext?.session?.kernel?.spec;
const displayName = kernelSpec
? kernelSpec.display_name
: 'Loading...';
kernelStatus({ displayName, isBusy: labStatus.isBusy });
});
}
});
}
};
```

> [!WARNING]
> The returned value of `createProxy` must be passed as the `args` of the command so the underlying proxy can properly be transferred by Comlink. `createProxy` can proxy an entire object, so you can pass multiple callbacks and other data as well at once. For example:
>
> ```js
> const proxy = createProxy({
> kernelStatus,
> anotherCallback,
> someData: { foo: 'bar' }
> });
> await commandBridge.execute('kernel-status', proxy);
> ```

## Demos

### Local Demo
Expand Down
13 changes: 12 additions & 1 deletion packages/host/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) TileDB, Inc.
// Distributed under the terms of the Modified BSD License.
import { windowEndpoint, wrap } from 'comlink';
import { windowEndpoint, wrap, proxy, ProxyOrClone } from 'comlink';

import { ICommandBridgeRemote } from 'jupyter-iframe-commands';
/**
* A bridge to expose actions on JupyterLab commands.
Expand All @@ -22,3 +23,13 @@ export function createBridge({ iframeId }: { iframeId: string }) {

return wrap<ICommandBridgeRemote>(windowEndpoint(iframe.contentWindow));
}

/**
* Creates a proxy for the given object.
*
* @param args - The object to create a proxy for.
* @returns A proxy for the given object.
*/
export function createProxy(args: any): ProxyOrClone<any> {
return proxy(args);
}
7 changes: 6 additions & 1 deletion packages/host/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,10 @@
"outDir": "lib",
"rootDir": "src"
},
"include": ["src/**/*"]
"include": ["src/**/*"],
"references": [
{
"path": "../extension"
}
]
}
Loading