Subscriptions 
There's more to an API than sending and fetching data. Integro makes it a piece of 🍰 to allow the client to subscribe to events.
Server setup 
Subscriptions use web sockets. As a result, the server requires a tiny bit more code to setup than using integro without subscriptions. The client side does not need any extra setup.
import { createSubscriptionController } from 'integro';
import { createServer } from 'node:http'; // or 'node:https'
import { app } from './app';
const { createWebSocketServer, handleRequest } = createSubscriptionController(app);
createServer(handleRequest)
  .on('upgrade', createWebSocketServer)
  .listen(8000);import { serve } from 'bun';
import { createSubscriptionController } from 'integro';
import { app } from './app.js';
const { handleRequest, websocketHandlers } = createSubscriptionController(app);
Bun.serve({
  port: await getPort(),
  fetch: (req, server) => server.upgrade(req) ? undefined : handleRequest(req),
  websocket: websocketHandlers
});import { app } from './app';
import { createSubscriptionController } from 'integro';
import express from 'express';
const { createWebSocketServer, handleRequest } = createSubscriptionController(app);
express()
  .use(handleRequest)
  .listen(8000)
  .on('upgrade', createWebSocketServer);Simple subscriptions 
Use the included createSubject() function to create a typesafe
type Article = { author: string; content: string };
const app = {
  articles: {
    create: async (article: Article) => {
      await db.save(article);
      // Notify subscribers
      app.creation$.send(article);
    },
    creation$: createSubject<Article>(),
  },
};const api = createClient<App>('https://example.com/api');
api.articles.creation$.subscribe(console.log);
// -> { author: 'Me', content: '...' }
api.articles.create({ author: 'Me', content: '...' });With unwrap 
Subscriptions can be used with unwrap, just like normal requests. However, there are two important things to note:
- The context object will not contain a requestobject because subscriptions are made via web sockets. Instead, theauthparameter (passed tocreateClient) can be used for authentication.
- createSubjectshould not be called inside the- unwrapfunction. Doing so would make the subject scoped to the function body and we wouldn't be able to invoke it from elsewhere in the app.
type Article = { author: string; content: string };
const articleCreation$ = createSubject<Article>();
const app = {
  articles: unwrap(({ auth }) => {
    if (auth !== 'user.auth.token') throw new Error('Unauthenticated!')
    return {
      create: async (article: Article) => {
        await db.save(article);
        // Notify subscribers
        articleCreation$.send(article);
      },
      creation$: articleCreation$,
    };
  }),
};const api = createClient<App>('https://example.com/api', { auth: 'user.auth.token' });
api.articles.creation$.subscribe(console.log);
// -> { author: 'Me', content: '...' }
api.articles.create({ author: 'Me', content: '...' });With parameters 
In addition to all-or-nothing subscriptions, you can create parameterized subscriptions for filtering, altering, or authenticating the subscription messages.
Subjects provide .filter() and .map() methods to make it easy to create a new subject based on an existing one.
type Article = { author: string; content: string };
const articleCreation$ = createSubject<Article>();
const articleList$ = createSubject<Article>();
const app = {
  articles: {
    create: async (article: Article) => {
      await db.save(article);
      const list = await db.getAll()
      // Notify subscribers
      articleCreation$.send(article);
      articleList$.send(list);
    },
    creation$: {
      // Create an object with a subscribe function instead of a full subject
      subscribe: (author: string) =>
        articleCreation$.filter((article) => article.author === author).subscribe,
    },
    list$: {
      // Create an object with a subscribe function instead of a full subject
      subscribe: (author: string) =>
        articleList$.map((list) => list.filter((article) => article.author === author)).subscribe,
    },
  },
};const api = createClient<App>('https://example.com/api');
api.articles.creation$.subscribe('Alice', console.log);
// -> { author: 'Alice', content: 'Article 2' }
// -> { author: 'Alice', content: 'Article 4' }
api.articles.list$.subscribe('Alice', console.log);
// -> []
// -> []
// -> [{ author: 'Alice', content: 'Article 2' }]
// -> [{ author: 'Alice', content: 'Article 2' }]
// -> [{ author: 'Alice', content: 'Article 2' }, { author: 'Alice', content: 'Article 4' }]
api.articles.create({ author: 'Me', content: 'Article 3' });
api.articles.create({ author: 'Timmy', content: 'Article 1' });
api.articles.create({ author: 'Alice', content: 'Article 2' });
api.articles.create({ author: 'Me', content: 'Article 3' });
api.articles.create({ author: 'Alice', content: 'Article 4' });