This package provides a way to use services in all your wonderful web components, vanilla components, framework components, and more.
This is a work in progress. There will be many breaking changes and API changes.
- Run 
npm i wc-services - Add 
<service-provider></service-provider>on the main page of your application. Generally, putting it at the top of yourindex.htmlis fine, or at the root of your framework mount point. 
To create a service, extend the Service class:
export default MyService extends Service {
    ...
}In your services, to let components know if there's been a state change you will need to call this.notify():
export default MyService extends Service {
    text = "foo";
    changeText() {
        this.text = "bar";
        this.notify();
    }
}To make properties feel reactive, it's recommended to call notify when a property is set. Here is an example:
export default MyService extends Service {
    _text = "foo";
    get text() {
        return text;
    }
    set text(val) {
        this.text = val;
        this.notify();
    }
    changeText() {
        // Don't need to notify, as any setting calls `this.notify()`
        this.text = "bar";
    }
}A convenience decorator @reactive cuts down on the boilerplate if you have decorators available:
export default MyService extends Service {
    @reactive text = "foo";
    changeText() {
        this.text = "bar";
    }
}NOTE: You must have
"useDefineForClassFields": false,set in your typescript configuration for this decorator to work
The lazyService function accepts four parameters
host: any- the host that is calling for the serviceclass: Constructor- The class definition for the service you want to getproperty: ProperyKey- The property on the host that the store should be saved tonotify: () => void- An callback called when the service updates
For example, in a vanilla web component, it may look like this:
export default MyComponent extends HTMLElement {
    constructor() {
        super();
        lazyService(this, "myService", MyService, () => this.update());
        // This property is now available as `this.myService`
    }
    update() {
        // called when myService notifies that state has changed
    }
}For a Lit component, there is a ReactiveController implemented. This reactive controller handles unsubscribing to the service and unsubscribing the component when disconnected:
import { ServiceConsumer } from 'wc-services/lit';
export default MyComponent extends LitElement {
    constructor() {
        super();
        new ServiceConsumer(this, "myService", MyService);
    }
    // for Typescript
    declare myService: MyService;
    render() {
        //...
    }
}For ergonomics, in Lit we have a decorator:
import { service } "wc-services/lit";
export default MyComponent extends LitElement {
    @service(MyService)
    declare myService: MyService;
    render() {
        //...
    }
}If you need services to use other services, this is fine. For now, the way to make sure service services react is to use the callback () => this.notify():
export default MyService extends Service {
    constructor() {
        super();
        lazyService(this, "otherService", OtherService);
    }
    text = "foo";
    changeText() {
        this.text = "bar";
        this.notify();
    }
}Note that lazyService is aware when it's being attached to a service and doesn't need to be provided a notify function.
Right now reactivity notifications are scheduled and multiple notifications are deduped. Also, to avoid circular dependency issues, services are lazily retrieved when they are accessed.
Services are meant to be long lived and should persist through the life of an application.
The service provider class allows us to set up services without including the custom element on the page. This is useful in tests. It also provides some methods to set up mocks for services and a way to reset services. Example to come.