Skip to content

Commit 0779580

Browse files
authored
Merge pull request evoluhq#609 from evoluhq/add-owner-usage-tracking
Add owner usage tracking [in progress]
2 parents 36035be + bad9ca4 commit 0779580

49 files changed

Lines changed: 2149 additions & 1296 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/kind-jars-lay.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
"@evolu/common": patch
3+
"@evolu/nodejs": patch
4+
"@evolu/react-native": patch
5+
"@evolu/react-web": patch
6+
---
7+
8+
Add owner usage tracking and storage improvements
9+
10+
### Breaking Changes
11+
12+
- Renamed `TransportConfig` to `OwnerTransport` and `WebSocketTransportConfig` to `OwnerWebSocketTransport` for clearer naming
13+
- Renamed `SqliteStorageBase` to `BaseSqliteStorage` and `createSqliteStorageBase` to `createBaseSqliteStorage`
14+
- Extracted storage table creation into separate functions: `createBaseSqliteStorageTables` and `createRelayStorageTables` to support serverless deployments where table setup must be separate from storage operations
15+
- Removed `assertNoErrorInCatch` - it was unnecessary
16+
17+
### Features
18+
19+
- **Owner usage tracking** (in progress): Added `evolu_usage` table and `OwnerUsage` interface to track data consumption metrics per owner (stored bytes, received bytes, sent bytes, first/last timestamps). Table structure is in place but not yet fully implemented
20+
- **Timestamp privacy documentation**: Added privacy considerations explaining that timestamps are metadata visible to relays, with guidance on implementing local write queues for maximum privacy
21+
- **React Native polyfills**: Added polyfills for `AbortSignal.any()` and `AbortSignal.timeout()` to support Task cancellation on React Native platforms that don't yet implement these APIs
22+
23+
### Performance
24+
25+
- **isSqlMutation optimization**: Added LRU cache (10,000 entries) to `isSqlMutation` function, restoring Timestamp insert benchmark from 34k back to 57k inserts/sec.

.changeset/shy-planes-report.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
"@evolu/common": patch
3+
---
4+
5+
Evolu identicons
6+
7+
Added `createIdenticon` function for generating visually distinct SVG identicons from Evolu `Id` (including branded IDs like `OwnerId`, etc.). For user avatars, visual identity markers, and differentiating entities in UI without storing images.
8+
9+
### Features
10+
11+
- **Multiple styles**: Choose from 4 styles:
12+
- `"github"` (default): 5×5 grid with horizontal mirroring, inspired by GitHub avatars
13+
- `"quadrant"`: 2×2 color block grid with direct RGB mapping
14+
- `"gradient"`: Diagonal stripe pattern with smooth color gradients
15+
- `"sutnar"`: Ladislav Sutnar-inspired compositional design with adaptive colors
16+
- **SVG output**: Returns SVG string that can be used directly
17+
18+
### Example
19+
20+
```ts
21+
import { createIdenticon } from "@evolu/common";
22+
23+
// Basic usage with default GitHub style
24+
const svg = createIdenticon(userId);
25+
26+
const quadrant = createIdenticon(ownerId, "quadrant");
27+
const gradient = createIdenticon(postId, "gradient");
28+
const sutnar = createIdenticon(teamId, "sutnar");
29+
```

.changeset/strict-jokes-tie.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
"@evolu/common": patch
3+
---
4+
5+
Add Cache module with generic cache interface and LRU cache implementation
6+
7+
- New `Cache<K, V>` interface with `has`, `get`, `set`, `delete` methods
8+
- New `createLruCache` factory function for creating LRU caches with configurable capacity
9+
- Keys are compared by reference (standard Map semantics)
10+
- LRU cache automatically evicts least recently used entries when capacity is reached
11+
- Both `get` and `set` operations update access order
12+
- Exposes readonly `map` property for iteration and inspection
13+
14+
Example:
15+
16+
```ts
17+
const cache = createLruCache<string, number>(2);
18+
cache.set("a", 1);
19+
cache.set("b", 2);
20+
cache.set("c", 3); // Evicts "a"
21+
cache.has("a"); // false
22+
```

.github/copilot-instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ const formatCurrencyCodeError = createTypeErrorFormatter<CurrencyCodeError>(
179179
- Use for catching developer mistakes eagerly (e.g., invalid configuration)
180180

181181
```ts
182-
import { assert, assertNonEmptyArray, assertNoErrorInCatch } from "./Assert.js";
182+
import { assert, assertNonEmptyArray } from "./Assert.js";
183183

184184
// ✅ Good example
185185
const length = buffer.getLength();

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ storybook-static
1515
.direnv
1616
.eslintcache
1717
out
18+
test-identicons

apps/relay/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"dev": "node --experimental-strip-types --watch src/index.ts",
88
"build": "shx rm -rf dist && tsc",
99
"start": "node dist/index.js",
10-
"clean": "shx rm -rf .turbo node_modules dist db.sqlite",
10+
"clean": "shx rm -rf .turbo node_modules dist data/evolu-relay.db",
1111
"docker:build": "docker-compose build --no-cache",
1212
"docker:up": "docker-compose up --build",
1313
"docker:up:detached": "docker-compose up -d --build",

apps/relay/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ const relay = await createNodeJsRelay({
1616
* ### Example
1717
*
1818
* ```ts
19-
* Evolu.createWebSocketTransportConfig({
20-
* relayUrl: "ws://localhost:4000",
19+
* Evolu.createOwnerWebSocketTransport({
20+
* url: "ws://localhost:4000",
2121
* ownerId: "6jy_2F4RT5qqeLgJ14_dnQ" as Evolu.OwnerId,
2222
* });
2323
* ```

apps/web/src/app/(landing)/blog/the-copy-paste-typescript-standard-library/page.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ It’s half a joke and half the truth. Programmers should understand the code th
8686

8787
- [Result](https://github.com/evoluhq/evolu/blob/main/packages/common/src/Result.ts) (type‑safe errors)
8888
- [Brand](https://github.com/evoluhq/evolu/blob/main/packages/common/src/Brand.ts) (prevents mixing incompatible values, e.g., `type UserId = string & Brand<"UserId">`)
89-
- [Assert](https://github.com/evoluhq/evolu/blob/main/packages/common/src/Assert.ts) (fail‑fast helpers: `assert`, `assertNonEmptyArray`, `assertNoErrorInCatch`)
89+
- [Assert](https://github.com/evoluhq/evolu/blob/main/packages/common/src/Assert.ts) (fail‑fast helpers: `assert`, `assertNonEmptyArray`)
9090
- [Array](https://github.com/evoluhq/evolu/blob/main/packages/common/src/Array.ts) (non‑empty arrays and helpers: `NonEmptyArray`, `isNonEmptyArray`, `appendToArray`)
9191
- [Function](https://github.com/evoluhq/evolu/blob/main/packages/common/src/Function.ts) (small function utils: `exhaustiveCheck`, `identity`, `LazyValue`)
9292
- [Object](https://github.com/evoluhq/evolu/blob/main/packages/common/src/Object.ts) (object helpers: `isPlainObject`, `mapObject`, `objectToEntries`, `excludeProp`)

examples/react-expo/app/index.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import Alert from "@blazejkustra/react-native-alert";
2+
import type { Evolu as EvoluType } from "@evolu/common";
13
import * as Evolu from "@evolu/common";
24
import { createUseEvolu, EvoluProvider, useQuery } from "@evolu/react";
5+
import { EvoluIdenticon } from "@evolu/react-native";
36
import {
47
evoluReactNativeDeps,
58
localAuth,
6-
EvoluAvatar,
79
} from "@evolu/react-native/expo-sqlite";
810
import { FC, Suspense, use, useEffect, useMemo, useState } from "react";
9-
import type { Evolu as EvoluType } from "@evolu/common";
10-
1111
import {
1212
ActivityIndicator,
1313
ScrollView,
@@ -18,7 +18,6 @@ import {
1818
View,
1919
} from "react-native";
2020
import { SafeAreaView } from "react-native-safe-area-context";
21-
import Alert from "@blazejkustra/react-native-alert";
2221

2322
// Namespace for the current app (scopes databases, passkeys, etc.)
2423
const service = "rn-expo";
@@ -97,15 +96,15 @@ export default function Index(): React.ReactNode {
9796
);
9897
}
9998

100-
function EvoluDemo({
99+
const EvoluDemo = ({
101100
evolu,
102101
ownerIds,
103102
authResult,
104103
}: {
105104
evolu: EvoluType<typeof Schema>;
106105
ownerIds: Array<Evolu.AuthList> | null;
107106
authResult: Evolu.AuthResult | null;
108-
}): React.ReactNode {
107+
}): React.ReactNode => {
109108
const useEvolu = createUseEvolu(evolu);
110109

111110
// Evolu uses Kysely for type-safe SQL (https://kysely.dev/).
@@ -501,7 +500,7 @@ function EvoluDemo({
501500
return (
502501
<View style={styles.ownerProfileRow}>
503502
<View style={styles.ownerInfo}>
504-
<EvoluAvatar id={ownerId} />
503+
<EvoluIdenticon id={ownerId} />
505504
<View style={styles.ownerDetails}>
506505
<Text style={styles.ownerUsername}>{username}</Text>
507506
<Text
@@ -577,7 +576,7 @@ function EvoluDemo({
577576
</ScrollView>
578577
</SafeAreaView>
579578
);
580-
}
579+
};
581580

582581
const styles = StyleSheet.create({
583582
container: {

examples/react-vite-pwa/src/components/EvoluMinimalExample.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as Evolu from "@evolu/common";
22
import { createUseEvolu, EvoluProvider, useQuery } from "@evolu/react";
3-
import { evoluReactWebDeps, EvoluAvatar, localAuth } from "@evolu/react-web";
3+
import { evoluReactWebDeps, EvoluIdenticon, localAuth } from "@evolu/react-web";
44
import { IconEdit, IconTrash } from "@tabler/icons-react";
55
import clsx from "clsx";
66
import { FC, Suspense, use, useMemo, useState } from "react";
@@ -415,7 +415,7 @@ const OwnerProfile: FC<{
415415
return (
416416
<div className="flex justify-between gap-3">
417417
<div className="flex items-center gap-3">
418-
<EvoluAvatar id={ownerId} />
418+
<EvoluIdenticon id={ownerId} />
419419
<span className="text-sm font-medium text-gray-900">{username}</span>
420420
<span className="text-xs text-gray-500 italic">{ownerId}</span>
421421
</div>

0 commit comments

Comments
 (0)