MCPcopy Index your code
hub / github.com/deriegle/express-hotwire

github.com/deriegle/express-hotwire @v0.3.2

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.3.2 ↗ · + Follow
32 symbols 55 edges 9 files 0 documented · 0%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Express library for working with Hotwire (HTML over the wire)

This project was built to provide tooling for working with the new @hotwired/turbo package built by Basecamp for their NEW MAGIC used with hey.com. I wanted to try building similar tooling in express as an example for how this can implemented in other languages, but also to help me learn how it works under the hood.

Using the library

  1. Add the express-hotwire package to your project

Using npm

npm install express-hotwire

Using yarn

yarn add express-hotwire
  1. Use the middleware with your app
const express = require('express');
const expressHotwire = require('express-hotwire');

const app = express();

app.use(expressHotwire());
  1. Render your turbo stream responses using the res.turboStream object.
app.post('/messages', async (req, res) => {
  const { content } = req.fields;

  // create message and save in database/memory/etc
  const message = create(content);

  // Make sure the first argument matches the HTML element id that you want to append a child to
  await res.turboStream.append('messages', {
    partial: 'messages/show', // This should be inside your views directory as views/messages/show.ejs
    locals: {
      // Add any variables needed to render the partial
      message,
    },
  });
});

Turbo Stream Messages and Actions

We provide helpful methods for all the actions listed in the hotwire.dev docs.

// The contents of the partial will be appended to the element with DOM ID "messages".
res.turboStream.append('messages', {
  partial: 'messages/show',
  locals: {
    message: { id: 1, content: 'Hi' },
  },
});

// The contents of the partial will be prepended to the element with the DOM ID "messages".
res.turboStream.prepend('messages', {
  partial: 'messages/show',
  locals: {
    message: { id: 1, content: 'Hi' },
  },
});

// The contents of the partial will replace the existing element with the DOM ID "message_1".
res.turboStream.replace('message_1', {
  partial: 'messages/show',
  locals: {
    message: { id: 1, content: 'Hi' },
  },
});

// The contents of the partial will update the element with DOM ID "unread_count".
res.turboStream.update('unread_count', {
  partial: 'messages/show',
  locals: {
    message: { id: 1, content: 'Hi' },
  },
});

// The element with DOM ID "message_1" will be removed.
res.turboStream.remove('message_1');

Sending Multiple TurboStreams

Sometimes you want to return multiple turbo streams from a request handler. You can use the res.turboStream.multiple function to do that. You have access to all the same turboStream methods in the callback as defined above.

Note: You cannot call turboStream.multiple from within the callback. We don't support nested calls to .multiple

await res.turboStream.multiple((turboStream) => [
  turboStream.append('messages', {
    partial: 'messages/show',
    locals: {
      message: { id: 1, content: 'Hi' },
    },
  }),
  turboStream.prepend('messages', {
    partial: 'messages/show',
    locals: {
      message: { id: 1, content: 'Hi' },
    },
  }),
  turboStream.replace('message_1', {
    partial: 'messages/show',
    locals: {
      message: { id: 1, content: 'Hi' },
    },
  }),
  turboStream.update('unread_count', {
    partial: 'messages/show',
    locals: {
      message: { id: 1, content: 'Hi' },
    },
  }),
  turboStream.remove('message_1'),
]);

Extension points exported contracts — how you extend this code

Response (Interface)
(no doc)
src/index.ts
PartialStreamOptions (Interface)
(no doc)
src/lib/hotwire-middleware.ts
ContentStreamOptions (Interface)
(no doc)
src/lib/hotwire-middleware.ts

Core symbols most depended-on inside this repo

middleware
called by 14
src/lib/hotwire-middleware.ts
streamActionHandler
called by 5
src/lib/hotwire-middleware.ts
findById
called by 4
example/src/services/room-service.js
all
called by 3
example/src/services/room-service.js
_findIndex
called by 2
example/src/services/message-service.js
createTurboStream
called by 2
src/lib/hotwire-middleware.ts
getNextId
called by 1
example/src/services/message-service.js
updateById
called by 1
example/src/services/room-service.js

Shape

Method 13
Function 9
Class 4
Enum 3
Interface 3

Languages

TypeScript100%

Modules by API surface

src/lib/hotwire-middleware.ts13 symbols
example/src/services/message-service.js9 symbols
example/src/services/room-service.js8 symbols
src/lib/__tests__/hotwire-middleware.test.ts1 symbols
src/index.ts1 symbols

For agents

$ claude mcp add express-hotwire \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact