Metadata-Version: 2.4
Name: ephaptic
Version: 0.5.0
Summary: The Python client/server package for ephaptic.
Author-email: uukelele <robustrobot11@gmail.com>
License: MIT License
        
        Copyright (c) 2025 ephaptic
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Docs, https://ephaptic.github.io/ephaptic
Project-URL: Homepage, https://github.com/ephaptic/ephaptic
Project-URL: Source, https://github.com/ephaptic/ephaptic
Project-URL: Repository, https://github.com/ephaptic/ephaptic
Project-URL: Issues, https://github.com/ephaptic/ephaptic/issues
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: msgpack>=1.0.0
Requires-Dist: websockets>=12.0
Requires-Dist: pydantic>=2.0
Requires-Dist: typer>=0.20.0
Requires-Dist: python-dotenv
Requires-Dist: watchfiles
Requires-Dist: redis
Requires-Dist: docstring-parser
Provides-Extra: server
Requires-Dist: fastapi; extra == "server"
Requires-Dist: uvicorn; extra == "server"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-asyncio; extra == "test"
Requires-Dist: fastapi; extra == "test"
Requires-Dist: uvicorn; extra == "test"
Requires-Dist: httpx; extra == "test"
Requires-Dist: quart; extra == "test"
Dynamic: license-file

<div align="center">
    <a href="https://github.com/ephaptic/ephaptic">
        <picture>
            <img src="https://raw.githubusercontent.com/ephaptic/ephaptic/refs/heads/main/.github/assets/logo.png" alt="ephaptic logo" height="200">
            <!-- <img src="https://avatars.githubusercontent.com/u/248199226?s=256" alt="ephaptic logo" height="200> -->
        </picture>
    </a>
<br>
<h1>ephaptic</h1>
<br>
<a href="https://github.com/ephaptic/ephaptic/blob/main/LICENSE"><img alt="GitHub License" src="https://img.shields.io/github/license/ephaptic/ephaptic?style=for-the-badge&labelColor=%23222222" /></a> <img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/ephaptic/ephaptic/publish-js.yml?style=for-the-badge&label=NPM%20Build%20Status&labelColor=%23222222" /> <img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/ephaptic/ephaptic/publish-python.yml?style=for-the-badge&label=PyPI%20Build%20Status&labelColor=%23222222" /> <img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/ephaptic/ephaptic/tests.yml?style=for-the-badge&label=tests&labelColor=%23222222" /> <a href="https://pypi.org/project/ephaptic/"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/ephaptic?style=for-the-badge&labelColor=%23222222" /></a> <a href="https://www.npmjs.com/package/@ephaptic/client"><img alt="NPM - Version" src="https://img.shields.io/npm/v/%40ephaptic%2Fclient?style=for-the-badge&labelColor=%23222222" /></a>


</div>

## What is `ephaptic`?

<br>

<blockquote>
    <b>ephaptic (adj.)</b><br>
    electrical conduction of a nerve impulse across an ephapse without the mediation of a neurotransmitter.
</blockquote>

Nah, just kidding. It's an RPC framework.

> **ephaptic** — Call your backend straight from your frontend. No JSON. Low latency. Invisible middleware.

## Getting Started

- Ephaptic is designed to be invisible. Write a function on the server, call it on the client. No extra boilerplate.

- Plus, it's horizontally scalable with Redis (optional), and features extremely low latency thanks to [msgpack](https://github.com/msgpack).

- Oh, and the client can also listen to events broadcasted by the server. No, like literally. You just need to add an `eventListener`. Did I mention? Events can be sent to specific targets, specific users - not just anyone online.

- Saved the best for last: it's type-safe. Don't believe me? Try it out for yourself. Simply type hint return values and parameters on the backend, and watch those very Python types transform into interfaces and types on the TypeScript frontend. Plus, you can use Pydantic - which means, for those of you who are FastAPI users, this is going to be great.

What are you waiting for? **Let's go.**

<h5>To see why you might want to use Ephaptic instead of traditional REST, see the <a href="https://ephaptic.github.io/ephaptic/advanced/replacing-rest">article</a> on it.</h5>

<details>
    <summary>Python</summary>
    
```shell
$ pip install ephaptic
```

```python
from fastapi import FastAPI # or `from quart import Quart`
from ephaptic import Ephaptic

app = FastAPI() # or `app = Quart(__name__)`

ephaptic = Ephaptic.from_app(app) # Finds which framework you're using, and creates an ephaptic server.
```

You can also specify a custom path:

```python
ephaptic = Ephaptic.from_app(app, path="/websocket")
```

And you can even use Redis for horizontal scaling!

```python
ephaptic = Ephaptic.from_app(app, redis_url="redis://my-redis-container:6379/0")
```

Now, how do you expose your function to the frontend?

```python
@ephaptic.expose
async def add(num1: int, num2: int) -> int:
    return num1 + num2
```

<h5>If you're trying to expose functions statelessly, e.g. in a different file, feel free to instead import and use the <code>expose</code> function from the library instead of the instance. Please note that if you do this, you must define all exposed functions <i>before</i> creating the ephaptic instance - easily done by simply placing your import line above the ephaptic constructor. The same thing can be done with the global <code>identity_loader</code> decorator.</h5>

Yep, it's really that simple.

But what if your code throws an error? No sweat — it surfaces on the frontend as a typed error you can `catch`. Raise a `ServiceError` for structured, typed errors (carrying a `code`, `message`, and `data`), or let ephaptic turn unexpected exceptions into a safe, generic error (details stay on the server unless you opt into debug mode). See the [error handling docs](https://ephaptic.github.io/ephaptic/tutorial/errors).

And, want to say something to the frontend?

```python
class Notification(BaseModel):
    message: str
    priority: Literal["high", "low", "default"]

await ephaptic.to(user1, user2).emit(Notification(message="Hello, world!", priority="high"))
```

To create a schema of your RPC endpoints (pass `--watch` to auto-regenerate on file changes):

```shell
$ ephaptic generate src.app:ephaptic -o schema.json
```

Or output TypeScript directly, skipping the JSON layer:

```shell
$ ephaptic generate src.app:ephaptic -o ephaptic.d.ts
```

Pydantic is entirely supported. It's validated for arguments, it's auto-serialized when you return a pydantic model, and your models receive type definitions in the schema.

To receive authentication objects and handle them:

```python
from ephaptic import identity_loader

@identity_loader
async def load_identity(auth): # You can use synchronous functions here too.
    jwt = auth.get("token")
    if not jwt: return None # unauthorized
    ... # app logic to retrieve user ID
    return user_id
```

From here, you can use <code>ephaptic.active_user()</code> within any exposed function, and it will give you the current active user ID / whatever else your identity loading function returns. (This is also how <code>ephaptic.to</code> works.)

</details>

<details>
    <summary>JavaScript/TypeScript — Browser (Svelte, React, Angular, Vite, etc.)</summary>

<h4>To use with a framework / Vite:</h4>

```shell
$ npm install @ephaptic/client
```

Then:

```typescript
import { connect } from "@ephaptic/client";

const client = connect(); // Defaults to `/_ephaptic`.
```

Or, you can use it with a custom URL:

```typescript
const client = connect({ url: '/ws' });
```

```typescript
const client = connect({ url: 'wss://my-backend.deployment/ephaptic' });
```

You can even send auth objects to the server for identity loading.

```typescript
const client = connect({ url: '...', auth: { token: window.localStorage.getItem('jwtToken') } })
```

And you can load types, too (pass `--watch` to auto-reload on changes):

```shell
$ ephaptic generate ./schema.json -o schema.d.ts
```

```typescript
import { connect } from "@ephaptic/client";
import { type EphapticService } from './schema';

const client = connect(...) as EphapticService;
```


<h4>Or, to use in your browser:</h4>

```html
<script type="module">
import { connect } from 'https://cdn.jsdelivr.net/npm/@ephaptic/client@latest/+esm';

const client = connect(...);
</script>
```

</details>

See more in the [docs](https://ephaptic.github.io/ephaptic/tutorial).

## Conformance

Ephaptic's wire protocol is specified in [`specs/SERVER.md`](https://github.com/ephaptic/ephaptic/blob/main/specs/SERVER.md) and [`specs/CLIENT.md`](https://github.com/ephaptic/ephaptic/blob/main/specs/CLIENT.md). Each package ships a `CONFORMANCE.md` recording exactly which requirements it satisfies, which it does not, and why.

## [License](https://github.com/ephaptic/ephaptic/blob/main/LICENSE)

[MIT](https://github.com/ephaptic/ephaptic/blob/main/LICENSE)

---

<p align="center">
    &copy; ephaptic 2025 &middot; I read <a href="https://justfuckingusestandards.com/">this</a> and now I don't know if Ephaptic is worth it anymore. Who cares.
</p>
