chore: initial evolu setup 17940899
Steve · 2025-10-24 22:00 7 file(s) · +132 −26
bun.lock +43 −0
4 4
    "": {
5 5
      "name": "alcove",
6 6
      "dependencies": {
7 +
        "@evolu/common": "^6.0.1-preview.19",
8 +
        "@evolu/react": "^9.0.1-preview.4",
9 +
        "@evolu/react-web": "^1.0.1-preview.3",
7 10
        "@radix-ui/react-slot": "^1.2.3",
8 11
        "@tailwindcss/vite": "^4.1.16",
9 12
        "class-variance-authority": "^0.7.1",
97 100
98 101
    "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.0", "", { "dependencies": { "@eslint/core": "^0.16.0", "levn": "^0.4.1" } }, "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A=="],
99 102
103 +
    "@evolu/common": ["@evolu/common@6.0.1-preview.19", "", { "dependencies": { "@noble/ciphers": "^1.3.0", "@noble/hashes": "^1.8.0", "@scure/bip39": "^1.6.0", "kysely": "^0.28.4", "msgpackr": "^1.11.5", "nanoid": "^3.3.11", "random": "^5.4.1" } }, "sha512-9xBsnr8wRBGxnC+Joj7jIHtUf2N9nONblYnWpXvpmRE+w2qJYBV7mmUNmbh8+0aSJYJwpPbkWt7qKNhO5oKWOQ=="],
104 +
105 +
    "@evolu/react": ["@evolu/react@9.0.1-preview.4", "", { "peerDependencies": { "@evolu/common": "^6.0.1-preview.18", "react": "^19.0.0" } }, "sha512-zSTFK+vlSXLr22MmtlKtlZoY9H+FPUpDduQWF0p2+mUZbMlCR0w/X8l+aw2z7+wFzHDGyHy+XzNUvQfEjdu7ZQ=="],
106 +
107 +
    "@evolu/react-web": ["@evolu/react-web@1.0.1-preview.3", "", { "peerDependencies": { "@evolu/common": "^6.0.1-preview.18", "@evolu/web": "^1.0.1-preview.4", "react-dom": "^19.0.0" } }, "sha512-HXrwQaweuMMve4GAvmGa8rKw7OcQfrS+BV/5h7piNkqk29pPTdt9XK0D01SY9reAJgOdIfvgM8YAyd5GRXIstQ=="],
108 +
109 +
    "@evolu/web": ["@evolu/web@1.0.1-preview.5", "", { "dependencies": { "@sqlite.org/sqlite-wasm": "3.50.4-build1" }, "peerDependencies": { "@evolu/common": "^6.0.1-preview.18" } }, "sha512-3MHTpw7Dm7xgKjp1s9lymVNA+FbobhcsBabs3vohUv26sqF5bl4/tZeVrdORYL+mT9K3TPiGolzi19nZF2N+hQ=="],
110 +
100 111
    "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
101 112
102 113
    "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
115 126
116 127
    "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
117 128
129 +
    "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="],
130 +
131 +
    "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="],
132 +
133 +
    "@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3", "", { "os": "linux", "cpu": "arm" }, "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw=="],
134 +
135 +
    "@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg=="],
136 +
137 +
    "@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3", "", { "os": "linux", "cpu": "x64" }, "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg=="],
138 +
139 +
    "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="],
140 +
118 141
    "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="],
142 +
143 +
    "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="],
144 +
145 +
    "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
119 146
120 147
    "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
121 148
160 187
    "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-beta.41", "", { "os": "win32", "cpu": "x64" }, "sha512-UlpxKmFdik0Y2VjZrgUCgoYArZJiZllXgIipdBRV1hw6uK45UbQabSTW6Kp6enuOu7vouYWftwhuxfpE8J2JAg=="],
161 188
162 189
    "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.43", "", {}, "sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ=="],
190 +
191 +
    "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="],
192 +
193 +
    "@scure/bip39": ["@scure/bip39@1.6.0", "", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="],
194 +
195 +
    "@sqlite.org/sqlite-wasm": ["@sqlite.org/sqlite-wasm@3.50.4-build1", "", { "bin": { "sqlite-wasm": "bin/index.js" } }, "sha512-Qig2Wso7gPkU1PtXwFzndh+CTRzrIFxVGqv6eCetjU7YqxlHItj+GvQYwYTppCRgAPawtRN/4AJcEgB9xDHGug=="],
163 196
164 197
    "@tailwindcss/node": ["@tailwindcss/node@4.1.16", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.19", "source-map-js": "^1.2.1", "tailwindcss": "4.1.16" } }, "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw=="],
165 198
379 412
380 413
    "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
381 414
415 +
    "kysely": ["kysely@0.28.8", "", {}, "sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA=="],
416 +
382 417
    "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
383 418
384 419
    "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
423 458
424 459
    "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
425 460
461 +
    "msgpackr": ["msgpackr@1.11.5", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA=="],
462 +
463 +
    "msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="],
464 +
426 465
    "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
427 466
428 467
    "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
468 +
469 +
    "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
429 470
430 471
    "node-releases": ["node-releases@2.0.26", "", {}, "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA=="],
431 472
452 493
    "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
453 494
454 495
    "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
496 +
497 +
    "random": ["random@5.4.1", "", {}, "sha512-HtccRkYkAXCbj9bqsyGKGlicyeZ5AsQgs49fEuUO/BvrJ7WOQqXPjdg1CZrFjBkoT75ozrWlQXJ7TcXXLv2ISQ=="],
455 498
456 499
    "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
457 500
package.json +3 −0
10 10
    "preview": "vite preview"
11 11
  },
12 12
  "dependencies": {
13 +
    "@evolu/common": "^6.0.1-preview.19",
14 +
    "@evolu/react": "^9.0.1-preview.4",
15 +
    "@evolu/react-web": "^1.0.1-preview.3",
13 16
    "@radix-ui/react-slot": "^1.2.3",
14 17
    "@tailwindcss/vite": "^4.1.16",
15 18
    "class-variance-authority": "^0.7.1",
src/App.tsx +7 −7
1 -
import { ThemeProvider } from "@/components/theme-provider";
1 +
import { useEvolu } from "./main";
2 2
3 3
function App() {
4 +
	const { insert, update } = useEvolu();
5 +
4 6
	return (
5 -
		<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
6 -
			<main className="min-h-screen w-full items-center justify-center flex-col flex gap-2">
7 -
				<h1 className="text-6xl font-bold">ALCOVE</h1>
8 -
				<p className="text-lg">Coming soon</p>
9 -
			</main>
10 -
		</ThemeProvider>
7 +
		<main className="min-h-screen w-full items-center justify-center flex-col flex gap-2">
8 +
			<h1 className="text-6xl font-bold">ALCOVE</h1>
9 +
			<p className="text-lg">Coming soon</p>
10 +
		</main>
11 11
	);
12 12
}
13 13
src/components/theme-provider.tsx +1 −10
1 -
import { createContext, useContext, useEffect, useState } from "react";
1 +
import { createContext, useEffect, useState } from "react";
2 2
3 3
type Theme = "dark" | "light" | "system";
4 4
62 62
		</ThemeProviderContext.Provider>
63 63
	);
64 64
}
65 -
66 -
export const useTheme = () => {
67 -
	const context = useContext(ThemeProviderContext);
68 -
69 -
	if (context === undefined)
70 -
		throw new Error("useTheme must be used within a ThemeProvider");
71 -
72 -
	return context;
73 -
};
src/main.tsx +25 −9
1 -
import { StrictMode } from 'react'
2 -
import { createRoot } from 'react-dom/client'
3 -
import './index.css'
4 -
import App from './App.tsx'
1 +
import { StrictMode } from "react";
2 +
import { ThemeProvider } from "@/components/theme-provider";
3 +
import { createRoot } from "react-dom/client";
4 +
import { createEvolu, getOrThrow, SimpleName } from "@evolu/common";
5 +
import { createUseEvolu, EvoluProvider } from "@evolu/react";
6 +
import { Schema } from "./scheme.ts";
7 +
import { evoluReactWebDeps } from "@evolu/react-web";
8 +
import "./index.css";
9 +
import App from "./App.tsx";
5 10
6 -
createRoot(document.getElementById('root')!).render(
7 -
  <StrictMode>
8 -
    <App />
9 -
  </StrictMode>,
10 -
)
11 +
const evolu = createEvolu(evoluReactWebDeps)(Schema, {
12 +
	name: getOrThrow(SimpleName.from("your-app-name")),
13 +
	syncUrl: "wss://your-sync-url", // optional, defaults to wss://free.evoluhq.com
14 +
});
15 +
16 +
export const useEvolu = createUseEvolu(evolu);
17 +
18 +
createRoot(document.getElementById("root")!).render(
19 +
	<StrictMode>
20 +
		<EvoluProvider value={evolu}>
21 +
			<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
22 +
				<App />
23 +
			</ThemeProvider>
24 +
		</EvoluProvider>
25 +
	</StrictMode>,
26 +
);
src/scheme.ts (added) +51 −0
1 +
import {
2 +
	id,
3 +
	maxLength,
4 +
	NonEmptyString,
5 +
	NonEmptyString1000,
6 +
	nullOr,
7 +
} from "@evolu/common";
8 +
9 +
// RSS Feed ID
10 +
const RSSFeedId = id("RSSFeed");
11 +
type RSSFeedId = typeof RSSFeedId.Type;
12 +
13 +
// RSS Post ID
14 +
const RSSPostId = id("RSSPost");
15 +
type RSSPostId = typeof RSSPostId.Type;
16 +
17 +
// Custom branded types for string length constraints
18 +
const NonEmptyString50 = maxLength(50)(NonEmptyString);
19 +
type NonEmptyString50 = typeof NonEmptyString50.Type;
20 +
21 +
const NonEmptyString200 = maxLength(200)(NonEmptyString);
22 +
type NonEmptyString200 = typeof NonEmptyString200.Type;
23 +
24 +
export const Schema = {
25 +
	rssFeed: {
26 +
		id: RSSFeedId,
27 +
		feedUrl: NonEmptyString1000,
28 +
		title: NonEmptyString200,
29 +
		description: nullOr(NonEmptyString1000),
30 +
		category: nullOr(NonEmptyString50),
31 +
	},
32 +
	rssPost: {
33 +
		id: RSSPostId,
34 +
		feedId: RSSFeedId,
35 +
		title: NonEmptyString1000,
36 +
		link: NonEmptyString1000,
37 +
		content: nullOr(NonEmptyString1000),
38 +
		author: nullOr(NonEmptyString200),
39 +
	},
40 +
	readStatus: {
41 +
		id: id("ReadStatus"),
42 +
		feedId: RSSFeedId,
43 +
		postId: RSSPostId,
44 +
	},
45 +
	userPreferences: {
46 +
		id: id("UserPreferences"),
47 +
		theme: nullOr(NonEmptyString50), // Will store "light" or "dark"
48 +
		refreshInterval: nullOr(NonEmptyString50), // Will store number as string
49 +
		postsPerPage: nullOr(NonEmptyString50), // Will store number as string
50 +
	},
51 +
};
tsconfig.json +2 −0
5 5
		{ "path": "./tsconfig.node.json" }
6 6
	],
7 7
	"compilerOptions": {
8 +
		"strict": true,
9 +
		"exactOptionalPropertyTypes": true,
8 10
		"baseUrl": ".",
9 11
		"paths": {
10 12
			"@/*": ["./src/*"]