Defining Services

There are several different ways to define a proxy service.

Class

Define a class whose methods are available in other JS contexts:

import { openDB, IDBPDatabase } from 'idb';
import { defineServiceProxy } from '@webext-core/proxy-service';

export class TodosRepo {
  constructor(private db: Promise<IDBPDatabase>) {}

  async getAll(): Promise<Todo[]> {
    return (await this.db).getAll('todos');
  }
}

export const [registerTodosRepo, getTodosRepo] = defineServiceProxy<TodosRepo>('TodosRepo');
// Register
const db = openDB('todos');
registerTodosRepo((idb: Promise<IDBPDatabase>) => new TodosRepo(idb), db);
// Get an instance
const todosRepo = getTodosRepo();
const todos = await todosRepo.getAll();

Object

Objects can be used as services as well. All functions defined on the object are available in other contexts.

import { openDB, IDBPDatabase } from 'idb';
import { defineServiceProxy } from '@webext-core/proxy-service';

export const [registerTodosRepo, getTodosRepo] = defineServiceProxy<TodosRepo>('TodosRepo');
// Register
const db = openDB('todos');
await registerTodosRepo(
  (db: Promise<IDBPDatabase>) => ({
    async getAll(): Promise<Todo[]> {
      return (await this.db).getAll('todos');
    },
  }),
  db,
);
// Get an instance
const todosRepo = getTodosRepo();
const todos = await todosRepo.getAll();

Function

If you only need to define a single function, you can!

import { openDB, IDBPDatabase } from 'idb';
import { defineServiceProxy } from '@webext-core/proxy-service';

export async function getAllTodos(db: Promise<IDBPDatabase>) {
  return (await db).getAll('todos');
}

export const [registerGetAllTodos, getGetAllTodos] =
  defineServiceProxy<typeof getAllTodos>('TodosRepo');
// Register
const db = openDB('todos');
await registerGetAllTodos((db: Promise<IDBPDatabase>) => getAllTodos, db);
// Get an instance
const getAllTodos = getGetAllTodos();
const todos = await getAllTodos();

Nested Objects

If you need to register "deep" objects containing multiple services, you can do that as well. You can use classes, objects, and functions at any level.

import { openDB, IDBPDatabase } from 'idb';
import { defineServiceProxy } from '@webext-core/proxy-service';

export class TodosRepo {
  constructor(private db: Promise<IDBPDatabase>) {}

  async getAll(): Promise<Todo[]> {
    return (await this.db).getAll('todos');
  }
}

export const createAuthorsRepo = (db: Promise<IDBPDatabase>) => ({
  async getOne(id: string): Promise<Todo[]> {
    return (await this.db).getAll('authors', id);
  },
});

export const [registerApi, getApi] = defineServiceProxy<TodosRepo>('Api');
// Register
const db = openDB('todos');
await registerApi((db: Promise<IDBPDatabase>) => {
  return {
    todos: new TodosRepo(db),
    authors: reateAuthorsRepo(db),
  };
}, db);
// Get an instance
const api = getApi();
const todos = await api.todos.getAll();
const firstAuthor = await api.authors.getOne(todos.authorId);