1. Application
  2. Working with the ToDesktop API

Application

Working with the ToDesktop API


ToDesktop provides core APIs for interacting with ToDesktop applications.

ToDesktop SDK

The @todesktop/client-core packages exposes useful functions for directly interacting with your todesktop app. You can install @todesktop/client-core in the codebase of the web app that you’re converting into a desktop app:

        npm install @todesktop/client-core

      

Using the SDK is as simple as importing the desired functionality for use in your desktop app.

        import { platform, notification } from '@todesktop/client-core';

if (platform.todesktop.isDesktopApp()) {
  notification.create({ title: 'Desktop App Notificiation' });
}

      

platform.todesktop.isDesktopApp will evaluate to true if the function is invoked within the context of a desktop app. notification.create will then create a native notification alert.

Seperate Desktop Logic from Web App Logic

If you only have a small amount of desktop-specific code then it is fine to keep that functionality in the same file as your web app's javascript. However, if you have a lot of desktop-specific code then we recommend separating all of your desktop specific logic into a separate javascript file. This will ensure that the javascript for your web app is as small as possible.

You can add your desktop-specific javascript into a separate file and import it when your app is being run as a desktop app. Here's a simple way to do this:

        <script type="module">
  if (window.todesktop) {
    import('some-module.mjs');
  }
</script>

      

How It Works

When your desktop application is first loaded, ToDesktop exposes a window.todesktop object which provides information about the device as well as methods that provide extra features.

Functionality from @todesktop/client-core communicates with this window.todesktop object, but also provides safeguards to ensure backwards and forwards compatibility. For example, @todesktop/client-core may expose functionality which requires a certain desktop app runtime. If it detects that desktop app runtime is not suitable, it will log a warning in the browser instead of throwing an error.

INFO

In other words, prefer using @todesktop/client-core over the window.todesktop object directly. Additionally, @todesktop/client-core is strongly-typed which provides for a better developer experience.

Version 1.0.0 Breaking Changes

With version 1.0.0 of @todesktop/client-core now released, please make note of the following breaking changes:

Updated signature when unsubscribing from listeners

Previously, creating listeners involved managing an eventId and passing it to an off invocation:

        const eventId = await electronUpdater.on('update-available', () => {
  // ...
});
// unsubscribing from update available events
await electronUpdater.off('update-available', { eventId });

      

Now, every on invocation will return a unsubscribe function. You can then execute this function to unsubscribe from the listener (note that unsubscribe is a function that returns a Promise and can thus be awaited):

        const unsubscribe = await nativeWindow.on('enter-full-screen', () => {
  console.log('enter full screen');
});
// successfully unsubscribes
await unsubscribe();

      

Naturally, this means we've removed off and removeEventListener from our namespace objects:

        await nativeWindow.off(...) // ❌
await nativeWindow.removeEventListener(...) // ❌

      

For the sake of completeness, we've also removed addEventListener as the on function is now preferred:

        await nativeWindow.addEventListener(...) // ❌
await nativeWindow.on(...) // ✅

      

New object namespace

For version 1.0.0, we're exposing a new object namespace. The object namespace allows you to programmatically control resources that you have defined in the ToDesktop Builder interface. For now, we're including support for controlling trays. See the following for an example:

ToDesktop Builder interface which showcases the currently-selected tray.
        import { object, tray } from '@todesktop/client-core';

const trayIdFromToDesktopBuilder = 'JWJ3pS82Oe-6IA7beIAhm';

const trayRef = await object.retrieve({ id: trayIdFromToDesktopBuilder });
await tray.setTitle({ ref: trayRef, title: 'Title' });

const title = await tray.getTitle({ ref: trayRef });
console.log(title); // Title

      

You can find a full recipe here.

releaseMemoryBindings moved to object namespace

Finally, we've moved releaseMemoryBindings from the performance namespace to the object namespace. This is particularly useful if you're managing a lot of object references and want to optimize performance.

Before:

        import { performance } from "@todesktop/client-core";

const objectRef = ...
await performance.releaseMemoryBindings(objectRef);

      

After:

        import { object } from "@todesktop/client-core";

const objectRef = ...
await object.releaseMemoryBindings(objectRef);