npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@microsoft/servicehub-framework

v4.2.102

Published

The distributed ServiceHub Framework

Downloads

228

Readme

NodeJS ServiceHub Framework

This NPM package provides a way to proffer and consume brokered services. It is used in Visual Studio-related products to exchange services within and across processes and even across machines.

Learn about the brokered services essentials, how to provide a brokered service, and how to consume a brokered service.

Usage

Given an instance of IServiceBroker, you can request a service (such as a simple calculator service) like this:

const proxy = await serviceBroker.getProxy<ICalculatorService>(CalculatorDescriptor);
try {
    if (proxy) {
        const sum = await proxy.add(3, 5);
        assert(sum == 8);
    }
} finally {
    proxy?.dispose();
}

Important points to remember:

  1. Always be defensive by checking for an null result from the call for a service.
  2. Always dispose the proxy when you're done with it to avoid leaking resources. These proxies do not get garbage collected automatically on account of the I/O resource they require.

Let's do something real. Visual Studio 16.6 includes a VersionInfoService that exposes the VS and Live Share versions on the host. You can call that service from VS Code like this:

import * as isb from '@microsoft/servicehub-framework';
import * as vsls from 'vsls';

const VersionInfoService = new isb.ServiceJsonRpcDescriptor(
    isb.ServiceMoniker.create('Microsoft.VisualStudio.Shell.VersionInfoService', '1.0'),
    isb.Formatters.Utf8,
    isb.MessageDelimiters.HttpLikeHeaders);

interface IVersionInfoService {
    GetVersionInformationAsync(cancellationToken?: vscode.CancellationToken): Promise<VersionInformation>;
}

interface VersionInformation {
    visualStudioVersion: string;
    liveShareVersion: string;
}

const ls = await vsls.getApi();
const serviceBroker = await ls.services.getRemoteServiceBroker();
const proxy = await serviceBroker?.getProxy<IVersionInfoService>(VersionInfoService);
try {
    if (proxy) {
        const versionInfo = await proxy.GetVersionInformationAsync();
        console.log(`VS version: ${versionInfo.visualStudioVersion}`);
    }
} finally {
    proxy?.dispose();
}

Brokered Service Container

A process that wishes to offer its own brokered services need a container. If your javascript process does not already have a container, the following is for you.

Here is the simplest possible, self-contained executable sample (in TypeScript). The sample demonstrates definition and implementation of a service, registers it and proffers it with a ServiceRpcDescriptor and service factory into the container, and finally consumes it via an IServiceBroker.

import assert from 'assert'
import CancellationToken from 'cancellationtoken'
import {
    Formatters,
    MessageDelimiters,
    ServiceJsonRpcDescriptor,
    ServiceMoniker,
    ServiceRpcDescriptor,
    GlobalBrokeredServiceContainer,
    ServiceAudience,
    ServiceRegistration,
} from '@microsoft/servicehub-framework'

interface IService {
    readonly moniker: ServiceMoniker
    readonly descriptor: ServiceRpcDescriptor
    readonly registration: ServiceRegistration
}

class Services {
    static calculator: Readonly<IService> = Services.defineLocal('calc')

    private static defineLocal(
        name: string,
        version?: string
    ): Readonly<IService> {
        const moniker = { name, version }
        const descriptor = new ServiceJsonRpcDescriptor(
            moniker,
            Formatters.MessagePack,
            MessageDelimiters.BigEndianInt32LengthHeader
        )
        const registration = new ServiceRegistration(
            ServiceAudience.local,
            false
        )
        return Object.freeze({ moniker, descriptor, registration })
    }
}

interface ICalculator {
    add(
        a: number,
        b: number,
        cancellationToken?: CancellationToken
    ): Promise<number>
}

class Calculator implements ICalculator {
    public add(
        a: number,
        b: number,
        cancellationToken?: CancellationToken
    ): Promise<number> {
        return Promise.resolve(a + b)
    }
}

let container: GlobalBrokeredServiceContainer
beforeAll(function () {
    container = new GlobalBrokeredServiceContainer()
    container.register([Services.calculator])
    container.profferServiceFactory(
        Services.calculator.descriptor,
        (mk, options, sb, ct) => Promise.resolve(new Calculator())
    )
})

it('self-contained sample', async function () {
    const sb = container.getFullAccessServiceBroker()
    const calc = await sb.getProxy<ICalculator>(Services.calculator.descriptor)
    assert(calc)
    const sum = await calc.add(3, 5)
    assert(sum === 8)
})

Note that in a real world application, the preceding code would typically be divided into many files, and may even span packages and processes.

Contributing

Check out our CONTRIBUTING.md file.