Skip to content

Commit a957aa0

Browse files
committed
Refactor React Native package and remove dependency
1 parent 184b555 commit a957aa0

23 files changed

Lines changed: 368 additions & 294 deletions

File tree

.changeset/cool-hoops-give.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
"@evolu/react-native": patch
3+
"@evolu/common": patch
4+
---
5+
6+
Refactor React Native package structure and remove react-native-quick-base64 dependency
7+
8+
**Breaking Changes:**
9+
10+
- Package exports reorganized: use `/expo-sqlite`, `/expo-op-sqlite`, or `/bare-op-sqlite` instead of `/expo-sqlite` and `/op-sqlite`
11+
- Updated quickstart documentation to reflect new import paths
12+
13+
**@evolu/react-native:**
14+
15+
- Reorganized package structure with exports in dedicated `/exports` directory
16+
- Move SQLite driver implementations into `/sqlite-drivers` directory
17+
- Created shared dependency initialization in `shared.ts`
18+
- Removed `react-native-quick-base64` dependency (no longer needed)
19+
- Added `createExpoDeps.ts` for Expo-specific configuration including SecureStore integration
20+
- Updated `package.json` exports to include three entry points:
21+
- `/expo-sqlite` - for Expo projects using expo-sqlite
22+
- `/expo-op-sqlite` - for Expo projects using @op-engineering/op-sqlite
23+
- `/bare-op-sqlite` - for bare React Native projects using @op-engineering/op-sqlite
24+
- Reorganized imports following project guidelines (named imports, top-down organization)
25+
26+
**@evolu/common:**
27+
28+
- Added `Platform.ts` module with platform detection utilities
29+
- Refactored `LocalAuth.ts` constants to follow naming conventions:
30+
- `AUTH_NAMESPACE``localAuth_Namespace`
31+
- `AUTH_DEFAULT_OPTIONS``localAuthDefaultOptions`
32+
- `AUTH_METAKEY_LAST_OWNER``localAuthMetakeyLastOwner` (private)
33+
- `AUTH_METAKEY_OWNER_NAMES``localAuthMetakeyOwnerNames` (private)
34+
35+
**Documentation:**
36+
37+
- Updated quickstart guide to remove `react-native-quick-base64` from installation instructions
38+
- Simplified Expo setup warnings and instructions
39+
- Updated React Native import example to use `/bare-op-sqlite` path

apps/web/src/app/(docs)/docs/quickstart/page.mdx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ npm install @evolu/common@preview @evolu/react@preview @evolu/react-web@preview
3434

3535
```bash {{ title: 'React Native' }}
3636
npm install @evolu/common@preview @evolu/react@preview @evolu/react-native@preview \
37-
@op-engineering/op-sqlite react-native-quick-crypto react-native-quick-base64
37+
@op-engineering/op-sqlite react-native-quick-crypto
3838
```
3939

4040
```bash {{ title: 'Expo' }}
4141
npm install @evolu/common@preview @evolu/react@preview @evolu/react-native@preview \
42-
expo-sqlite react-native-quick-crypto react-native-quick-base64
42+
expo-sqlite react-native-quick-crypto
4343
```
4444

4545
```bash {{ title: 'Svelte' }}
@@ -53,17 +53,14 @@ npm install @evolu/common@preview @evolu/web@preview
5353
</SinglePlatformCodeGroup>
5454

5555
<ConditionalPlatformAlert platform={["Expo"]} type="warning">
56-
**Expo Go is not supported.** You must use a [development
57-
build](https://docs.expo.dev/develop/development-builds/introduction/) or
58-
create a production build to use Evolu with Expo, as it requires native
59-
dependencies.
56+
**Expo Go is not supported.** as it requires native dependencies
57+
(`react-native-quick-crypto`). Use `expo-sqlite` for standard performance or
58+
`expo-op-sqlite` for better performance.
6059
</ConditionalPlatformAlert>
6160

6261
<ConditionalPlatformAlert platform={["Expo", "React Native"]} type="info">
6362
Make sure to follow the [react-native-quick-crypto setup
6463
instructions](https://github.com/margelo/react-native-quick-crypto#installation)
65-
and [react-native-quick-base64 setup
66-
instructions](https://github.com/craftzdog/react-native-quick-base64#installation)
6764
for proper native dependency configuration.
6865
</ConditionalPlatformAlert>
6966

@@ -162,7 +159,7 @@ const { insert, update } = useEvolu();
162159
```ts {{ title: 'React Native', language: 'tsx' }}
163160
import { createEvolu, getOrThrow, SimpleName } from "@evolu/common";
164161
import { createUseEvolu, EvoluProvider } from "@evolu/react";
165-
import { evoluReactNativeDeps } from "@evolu/react-native/op-sqlite";
162+
import { evoluReactNativeDeps } from "@evolu/react-native/bare-op-sqlite";
166163

167164
const evolu = createEvolu(evoluReactNativeDeps)(Schema, {
168165
name: SimpleName.orThrow("your-app-name"),

examples/react-expo/app/_layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// import "react-native-quick-base64";
21
import { install } from "react-native-quick-crypto";
2+
33
install();
44

55
import { Stack } from "expo-router";

examples/react-expo/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
"expo-sqlite": "~16.0.8",
3535
"react": "catalog:react19",
3636
"react-native": "^0.81.4",
37-
"react-native-quick-base64": "^2.2.1",
3837
"react-native-quick-crypto": "^0.7.17",
3938
"react-native-safe-area-context": "^5.6.0",
4039
"react-native-screens": "^4.15.3",

packages/common/src/Evolu/LocalAuth.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const createLocalAuth = (
8484
id: OwnerId,
8585
options?: LocalAuthOptions,
8686
): Promise<void> => {
87-
await deps.secureStorage.setItem(AUTH_METAKEY_LAST_OWNER, id, {
87+
await deps.secureStorage.setItem(localAuthMetakeyLastOwner, id, {
8888
...buildAuthOptions(options),
8989
accessControl: "none",
9090
});
@@ -93,7 +93,7 @@ export const createLocalAuth = (
9393
const getLastOwnerId = async (
9494
options?: LocalAuthOptions,
9595
): Promise<OwnerId | undefined> => {
96-
const item = await deps.secureStorage.getItem(AUTH_METAKEY_LAST_OWNER, {
96+
const item = await deps.secureStorage.getItem(localAuthMetakeyLastOwner, {
9797
...buildAuthOptions(options),
9898
accessControl: "none",
9999
});
@@ -103,7 +103,7 @@ export const createLocalAuth = (
103103
const getOwnerNames = async (
104104
options?: LocalAuthOptions,
105105
): Promise<Record<OwnerId, string>> => {
106-
const item = await deps.secureStorage.getItem(AUTH_METAKEY_OWNER_NAMES, {
106+
const item = await deps.secureStorage.getItem(localAuthMetakeyOwnerNames, {
107107
...buildAuthOptions(options),
108108
accessControl: "none",
109109
});
@@ -122,7 +122,7 @@ export const createLocalAuth = (
122122
const names = await getOwnerNames(options);
123123
names[id] = username;
124124
await deps.secureStorage.setItem(
125-
AUTH_METAKEY_OWNER_NAMES,
125+
localAuthMetakeyOwnerNames,
126126
JSON.stringify(names),
127127
{
128128
...buildAuthOptions(options),
@@ -137,7 +137,7 @@ export const createLocalAuth = (
137137
): Promise<void> => {
138138
const { [id]: _, ...names } = await getOwnerNames(options);
139139
await deps.secureStorage.setItem(
140-
AUTH_METAKEY_OWNER_NAMES,
140+
localAuthMetakeyOwnerNames,
141141
JSON.stringify(names),
142142
{
143143
...buildAuthOptions(options),
@@ -157,8 +157,8 @@ export const createLocalAuth = (
157157
.filter(Boolean)
158158
.filter(
159159
(i) =>
160-
i.key !== AUTH_METAKEY_LAST_OWNER &&
161-
i.key !== AUTH_METAKEY_OWNER_NAMES,
160+
i.key !== localAuthMetakeyLastOwner &&
161+
i.key !== localAuthMetakeyOwnerNames,
162162
)
163163
.map((i) => i.key as OwnerId);
164164
};
@@ -171,7 +171,7 @@ export const createLocalAuth = (
171171
username?: string,
172172
): LocalAuthOptions => {
173173
const newOptions: LocalAuthOptions = {
174-
...AUTH_DEFAULT_OPTIONS,
174+
...localAuthDefaultOptions,
175175
...(username && { webAuthnUsername: username }),
176176
...options,
177177
};
@@ -311,13 +311,11 @@ export const createLocalAuth = (
311311
};
312312
};
313313

314-
// TOHO: With `const`, we don't need UPPER_CASE
315-
export const AUTH_NAMESPACE = "evolu";
316-
export const AUTH_METAKEY_LAST_OWNER = "_last_owner";
317-
export const AUTH_METAKEY_OWNER_NAMES = "_owner_names";
318-
export const AUTH_DEFAULT_OPTIONS: LocalAuthOptions = {
319-
service: AUTH_NAMESPACE,
320-
keychainGroup: AUTH_NAMESPACE,
314+
export const localAuth_Namespace = "evolu";
315+
316+
export const localAuthDefaultOptions: LocalAuthOptions = {
317+
service: localAuth_Namespace,
318+
keychainGroup: localAuth_Namespace,
321319
androidBiometricsStrongOnly: true,
322320
iosSynchronizable: true,
323321
webAuthnUsername: "Evolu User",
@@ -326,6 +324,9 @@ export const AUTH_DEFAULT_OPTIONS: LocalAuthOptions = {
326324
},
327325
};
328326

327+
const localAuthMetakeyLastOwner = "_last_owner";
328+
const localAuthMetakeyOwnerNames = "_owner_names";
329+
329330
export interface AuthResult {
330331
/** The app owner created during registration. */
331332
readonly owner: AppOwner | undefined;

packages/common/src/Platform.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Platform detection utilities for Evolu.
3+
*
4+
* @module
5+
*/
6+
7+
/** Detects if the code is running in React Native environment. */
8+
export const isReactNative =
9+
typeof navigator !== "undefined" &&
10+
"product" in navigator &&
11+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
12+
(navigator as any).product === "ReactNative";
13+
14+
/**
15+
* Detects if Node.js Buffer is available and should be used.
16+
*
17+
* React Native apps often polyfill Node.js APIs like Buffer, but we want to use
18+
* native methods when available for better performance.
19+
*
20+
* Returns false in React Native even if Buffer is polyfilled, as we prefer
21+
* native methods in that environment.
22+
*
23+
* @see https://github.com/craftzdog/react-native-quick-base64#installation
24+
*/
25+
export const hasNodeBuffer =
26+
!isReactNative && typeof globalThis.Buffer !== "undefined";

packages/common/src/Type.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ import { pack } from "msgpackr";
182182
import type { Brand } from "./Brand.js";
183183
import { type RandomBytesDep } from "./Crypto.js";
184184
import { isPlainObject } from "./Object.js";
185+
import { hasNodeBuffer } from "./Platform.js";
185186
import { err, getOrNull, getOrThrow, ok, Result, trySync } from "./Result.js";
186187
import { safelyStringifyUnknownValue } from "./String.js";
187188
import type { Literal, Simplify, WidenLiteral } from "./Types.js";
@@ -1426,7 +1427,6 @@ export const formatBase64UrlError = createTypeErrorFormatter<Base64UrlError>(
14261427
(error) => `The value ${error.value} is not a valid Base64Url string.`,
14271428
);
14281429

1429-
const hasNodeBuffer = typeof globalThis.Buffer !== "undefined";
14301430
const base64UrlOptions = { alphabet: "base64url", omitPadding: true };
14311431

14321432
/** Encodes a Uint8Array to a {@link Base64Url} string. */

packages/common/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export * from "./ManyToManyMap.js";
1616
export * from "./Number.js";
1717
export * from "./Object.js";
1818
export * from "./Order.js";
19+
export * from "./Platform.js";
1920
export * from "./Random.js";
2021
export * from "./Ref.js";
2122
export * from "./Result.js";

packages/common/typedoc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"src/Number.ts",
3434
"src/Object.ts",
3535
"src/Order.ts",
36+
"src/Platform.ts",
3637
"src/Random.ts",
3738
"src/Ref.ts",
3839
"src/Result.ts",

packages/react-native/package.json

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,21 @@
2525
"react-native": "./dist/index.js"
2626
},
2727
"./expo-sqlite": {
28-
"types": "./dist/expo-sqlite.d.ts",
29-
"default": "./dist/expo-sqlite.js",
30-
"react-native": "./dist/expo-sqlite.js",
28+
"types": "./dist/exports/expo-sqlite.d.ts",
29+
"default": "./dist/exports/expo-sqlite.js",
30+
"react-native": "./dist/exports/expo-sqlite.js",
3131
"browser": "./dist/web.js"
3232
},
33-
"./op-sqlite": {
34-
"types": "./dist/op-sqlite.d.ts",
35-
"default": "./dist/op-sqlite.js",
36-
"react-native": "./dist/op-sqlite.js",
33+
"./expo-op-sqlite": {
34+
"types": "./dist/exports/expo-op-sqlite.d.ts",
35+
"default": "./dist/exports/expo-op-sqlite.js",
36+
"react-native": "./dist/exports/expo-op-sqlite.js",
37+
"browser": "./dist/web.js"
38+
},
39+
"./bare-op-sqlite": {
40+
"types": "./dist/exports/bare-op-sqlite.d.ts",
41+
"default": "./dist/exports/bare-op-sqlite.js",
42+
"react-native": "./dist/exports/bare-op-sqlite.js",
3743
"browser": "./dist/web.js"
3844
}
3945
},
@@ -43,10 +49,13 @@
4349
"./dist/index.d.ts"
4450
],
4551
"expo-sqlite": [
46-
"./dist/expo-sqlite.d.ts"
52+
"./dist/exports/expo-sqlite.d.ts"
4753
],
48-
"op-sqlite": [
49-
"./dist/op-sqlite.d.ts"
54+
"expo-op-sqlite": [
55+
"./dist/exports/expo-op-sqlite.d.ts"
56+
],
57+
"bare-op-sqlite": [
58+
"./dist/exports/bare-op-sqlite.d.ts"
5059
]
5160
}
5261
},
@@ -61,9 +70,6 @@
6170
"clean": "shx rm -rf .turbo node_modules dist",
6271
"format": "prettier --write \"src/*.{ts,tsx,md}\""
6372
},
64-
"dependencies": {
65-
"blo": "^2.0.0"
66-
},
6773
"devDependencies": {
6874
"@evolu/common": "workspace:*",
6975
"@evolu/react": "workspace:*",

0 commit comments

Comments
 (0)