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

trpc-electric-sql

v0.1.1

Published

Call server functions natively in your ElectricSQL app with tRPC

Downloads

13

Readme

trpc-electric-sql

tRPC integration for ElectricSQL: ElectricSQL-native RPC calls

For when you're building with ElectricSQL but you want to run code on a server.

See the monorepo README for a longer writeup on why this library exists.

Install

npm install trpc-electric-sql

Example app

https://github.com/KyleAMathews/trpc-crdt/tree/main/examples/electric-sql

Usage

This integration with ElectricSQL serializes tRPC calls via an electrified trpc_calls table.

Add this table definition to your Postgres instance:

CREATE TABLE IF NOT EXISTS trpc_calls (
    id UUID PRIMARY KEY NOT NULL,
    createdAt TIMESTAMPTZ NOT NULL,
    elapsedMs INTEGER,
    path TEXT NOT NULL,
    input TEXT,
    type TEXT NOT NULL,
    state TEXT NOT NULL,
    clientId TEXT NOT NULL,
    response TEXT
);

ALTER TABLE trpc_calls ENABLE ELECTRIC;

Once DDLX support lands, we'll be able to restrict updates to trpc_calls rows to the server and the original creator.

You can then setup your browser/server code similar to the following.

Browser

import { createTRPCProxyClient } from "@trpc/client"
import { link, createElectricRef } from "trpc-electric-sql/link"
import { Electric, schema } from "../src/generated/client"
import { ElectricDatabase, electrify } from "electric-sql/wa-sqlite"
import { genUUID, uniqueTabId } from "electric-sql/util"
import { authToken } from "../auth"

const electricRef = createElectricRef<Electric>()
const trpc = createTRPCProxyClient<AppRouter>({
  links: [
    link({
      electricRef,
      clientId: genUUID(),
    }),
  ],
})

const init = async () => {
  const token = authToken()
  const config = {
    auth: {
      token: token,
    },
  }

  const { tabId } = uniqueTabId()
  const tabScopedDbName = `electric-${tabId}.db`

  const conn = await ElectricDatabase.init(tabScopedDbName, ``)
  const electric = await electrify(conn, schema, config)

  const [shape, usersShape] = await Promise.all([
    electric.db.trpc_calls.sync(),
    electric.db.users.sync(),
  ])
  await Promise.all([shape.synced, usersShape.synced])

  electricRef.value = electric
  setElectric(electric)

  // Tell server to create a new user.
  await trpc.userCreate.mutate({id: `1`, name: `Kyle Mathews`})

  // The new user, written by the server, is now available in the local sqlite db:
  const user = await electric.db.users.findUnique({where: { id: `1` }})
}

init()

Server

import { adapter } from "trpc-electric-sql/adapter"
import { initTRPC, TRPCError } from "@trpc/server"
import { z } from "zod"

const t = initTRPC.create()
const router = t.router
const publicProcedure = t.procedure

const appRouter = router({
  userCreate: publicProcedure
    .input(z.object({ name: z.string(), id: z.string() }))
    .mutation(async (opts) => {
      const {
        input,
        ctx: {
          transact,
          electric: { db },
        },
      } = opts
      const user = { ..input }

      // Writes in the transact function gets applied at same time the trpc call
      // is finished.
      transact(() => {
        db.users.create({
          data: user,
        })
      })
    })
})

async function setupTRPC() {
  const config = {
    auth: {
      token: authToken(),
    },
    url: process.env.ELECTRIC_URL,
  }

  // Create the better-sqlite3 database connection.
  const conn = new Database(`local-data.db`)
  conn.pragma(`journal_mode = WAL`)

  // Instantiate your electric client.
  const electric = await electrify(conn, schema, config)
  const { db } = electric
  const [shape, usersShape] = await Promise.all([
    electric.db.trpc_calls.sync(),
    electric.db.users.sync(),
  ])
  await Promise.all([shape.synced, usersShape.synced])

  adapter({
    context: { electric },
    appRouter,
  })
}

setupTRPC()