From 88e1b087f04d79adab4fb8b9197d230860e42c07 Mon Sep 17 00:00:00 2001
From: Austin Mudd <31991302+austinm911@users.noreply.github.com>
Date: Wed, 19 Feb 2025 23:10:00 -0800
Subject: [PATCH 1/2] wip
---
contents/docs/expo/index.mdx | 148 +++++++++++++++++++++++++++++
contents/docs/react-expo/index.mdx | 87 +++++++++++++++++
lib/routes-config.ts | 135 +++++++++++++-------------
3 files changed, 303 insertions(+), 67 deletions(-)
create mode 100644 contents/docs/expo/index.mdx
create mode 100644 contents/docs/react-expo/index.mdx
diff --git a/contents/docs/expo/index.mdx b/contents/docs/expo/index.mdx
new file mode 100644
index 0000000..c995c7f
--- /dev/null
+++ b/contents/docs/expo/index.mdx
@@ -0,0 +1,148 @@
+---
+title: Expo
+---
+
+Zero has built-in support for Expo and React Native using the `expo-sqlite` and `op-sqlite` packages.
+
+## Prerequisites
+
+The `crypto.getRandomValues()` API is not available in React Native, so we need to polyfill it.
+
+### Polyfill manually
+
+First, install the `expo-crypto` package. See the [expo-crypto docs](https://docs.expo.dev/versions/latest/sdk/crypto/) for more information.
+
+```bash
+npx expo install expo-crypto
+```
+
+Then create a new file in your project, e.g. `lib/crypto.ts`, and add the following code:
+
+```tsx
+// lib/crypto.ts
+import * as Crypto from 'expo-crypto';
+
+declare const global: {
+ crypto: {
+ getRandomValues(array: Uint8Array): Uint8Array;
+ randomUUID(): string;
+ };
+};
+
+export function bootCryptoPolyfill() {
+ global.crypto = {
+ getRandomValues(array: Uint8Array) {
+ return Crypto.getRandomValues(array);
+ },
+ randomUUID() {
+ return Crypto.randomUUID();
+ },
+ };
+}
+```
+
+This will allow you to use the `crypto` API in your React Native project such as `crypto.getRandomValues()` and `crypto.randomUUID()`.
+
+
+## Expo SQLite
+
+For more information on how to use the `expo-sqlite` package, see the [expo-sqlite docs](https://docs.expo.dev/versions/latest/sdk/sqlite/).
+
+Remember to install the dependencies:
+
+```bash
+npx expo install expo-sqlite
+```
+
+## OP-SQLite
+
+For more information on how to use the `op-sqlite` package, see the [op-sqlite docs](https://github.com/OP-Engineering/op-sqlite).
+
+Per the docs, if you are using Expo, you cannot add this library on a expo-go app, you need to pre-build your app.
+
+```bash
+npx expo install @op-engineering/op-sqlite
+npx expo prebuild
+```
+
+## Usage
+
+In your mobile app's layout, wrap your app's root component in the `ZeroProvider` component:
+
+```tsx
+// apps/my-app/_layout.tsx
+import '../globals.css';
+import {Zero} from '@rocicorp/zero';
+import {ZeroProvider} from '@rocicorp/zero/react';
+import {createExpoSQLiteStore} from '@rocicorp/zero/expo';
+// or if using op-sqlite
+// import { createOPSQLiteStore } from '@rocicorp/zero/op-sqlite';
+
+import {Stack} from 'expo-router';
+import {useMemo} from 'react';
+import {schema} from '../lib/schema'; // or wherever you have your schema
+
+export const unstable_settings = {
+ // Ensure that reloading on `/modal` keeps a back button present.
+ initialRouteName: '(tabs)',
+};
+
+export default function RootLayout() {
+ // Memoize the Zero instance so it's only created once per app lifecycle
+ // Note: If you intend to use Expo Web, you should use kvStore: 'mem' or 'idb' with a check like
+ // const store = Platform.OS === 'web' ? 'idb' : createExpoSQLiteStore;
+ const z = useMemo(
+ () =>
+ new Zero({
+ userID: 'your-user-id',
+ auth: 'your-auth-token',
+ server: process.env.EXPO_PUBLIC_SERVER_URL, // see https://docs.expo.dev/guides/environment-variables/
+ kvStore: createExpoSQLiteStore, // initialize the SQLite store
+ // kvStore: createExpoSQLiteStore, // or if using op-sqlite
+ schema,
+ }),
+ [],
+ );
+
+ if (!z) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
+ );
+}
+```
+
+Interact with the Zero instance in your components using the `zero/react` package. Please see the [React docs](react) for more details.
+
+```tsx
+import { useQuery, useZero } from '@rocicorp/zero/react';
+
+function IssueList() {
+ const z = useZero();
+
+ let issueQuery = z.query.issue
+ .related('creator')
+ .related('labels')
+ .limit(100);
+
+ const userID = selectedUserID();
+
+ if (userID) {
+ issueQuery = issueQuery.where('creatorID', '=', userID);
+ }
+
+ const [issues, issuesDetail] = useQuery(issueQuery);
+
+ // Your component ReactJSX
+ return ...;
+}
+```
+
+Complete quickstart here: COMING SOON
diff --git a/contents/docs/react-expo/index.mdx b/contents/docs/react-expo/index.mdx
new file mode 100644
index 0000000..68aa046
--- /dev/null
+++ b/contents/docs/react-expo/index.mdx
@@ -0,0 +1,87 @@
+---
+title: React Expo
+---
+
+Zero has built-in support for React Expo using the `expo-sqlite` and `op-sqlite` packages.
+
+In your mobile app's layout, wrap your app's root component in the `ZeroProvider` component:
+```tsx
+// apps/my-app/_layout.tsx
+import '../globals.css';
+import { Zero } from '@rocicorp/zero';
+import { ZeroProvider } from '@rocicorp/zero/react';
+import { createExpoSQLiteStore } from '@rocicorp/zero/expo';
+// or if using op-sqlite
+// import { createOPSQLiteStore } from '@rocicorp/zero/op-sqlite';
+
+import { Stack } from 'expo-router';
+import { useMemo } from 'react';
+import { schema } from '../lib/schema'; // or wherever you have your schema
+
+export const unstable_settings = {
+ // Ensure that reloading on `/modal` keeps a back button present.
+ initialRouteName: '(tabs)',
+};
+
+export default function RootLayout() {
+ // Memoize the Zero instance so it's only created once per app lifecycle
+ const zero = useMemo(
+ () =>
+ new Zero({
+ userID: "your-user-id",
+ auth: "your-auth-token",
+ server: process.env.EXPO_PUBLIC_SERVER_URL, // see https://docs.expo.dev/guides/environment-variables/
+ kvStore: createExpoSQLiteStore, // initialize the SQLite store
+ // kvStore: createExpoSQLiteStore, // or if using op-sqlite
+ schema,
+ }),
+ []
+ );
+
+ if (!z) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+```
+
+Interact with the Zero instance in your components using the `zero/react` package. Please see the [React docs](react) for more details.
+
+```tsx
+import {useQuery, useZero} from "@rocicorp/zero/react";
+
+function IssueList() {
+ const z = useZero();
+
+ let issueQuery = z.query.issue
+ .related('creator')
+ .related('labels')
+ .limit(100);
+
+ const userID = selectedUserID();
+
+ if (userID) {
+ issueQuery = issueQuery.where('creatorID', '=', userID);
+ }
+
+ const [issues, issuesDetail] = useQuery(issueQuery);
+
+ // Your component ReactJSX
+ return (
+
+ ...
+
+ )
+}
+```
+
+Complete quickstart here: COMING SOON
\ No newline at end of file
diff --git a/lib/routes-config.ts b/lib/routes-config.ts
index 665488d..e73b6d5 100644
--- a/lib/routes-config.ts
+++ b/lib/routes-config.ts
@@ -1,82 +1,83 @@
// for page navigation & to sort on leftbar
export type EachRoute = {
- title: string;
- href: string;
- noLink?: true;
- items?: EachRoute[];
+ title: string;
+ href: string;
+ noLink?: true;
+ items?: EachRoute[];
};
export const ROUTES: EachRoute[] = [
- {
- title: 'Welcome',
- href: '',
- noLink: true,
- items: [
- {title: 'Introduction', href: '/introduction'},
- {title: 'Quickstart', href: '/quickstart'},
- {title: 'Samples', href: '/samples'},
- ],
- },
+ {
+ title: "Welcome",
+ href: "",
+ noLink: true,
+ items: [
+ { title: "Introduction", href: "/introduction" },
+ { title: "Quickstart", href: "/quickstart" },
+ { title: "Samples", href: "/samples" },
+ ],
+ },
- {
- title: 'Using Zero',
- href: '',
- noLink: true,
- items: [
- //TODO
- //{title: 'How Zero Works', href: '/overview'},
- {title: 'Connecting to Postgres', href: '/connecting-to-postgres'},
- {title: 'Supported Postgres Features', href: '/postgres-support'},
- {title: 'Zero Schema', href: '/zero-schema'},
- {title: 'Reading Data with ZQL', href: '/reading-data'},
- {title: 'Writing Data with Mutators', href: '/writing-data'},
- {title: 'Authentication', href: '/auth'},
- {title: 'Permissions', href: '/permissions'},
- {title: 'Preloading', href: '/preloading'},
- {title: 'Schema Migrations', href: '/migrations'},
- {title: 'Deployment', href: '/deployment'},
- {title: '`zero-cache` Config', href: '/zero-cache-config'},
- {title: 'Recipes', href: '/recipes'},
- ],
- },
+ {
+ title: "Using Zero",
+ href: "",
+ noLink: true,
+ items: [
+ //TODO
+ //{title: 'How Zero Works', href: '/overview'},
+ { title: "Connecting to Postgres", href: "/connecting-to-postgres" },
+ { title: "Supported Postgres Features", href: "/postgres-support" },
+ { title: "Zero Schema", href: "/zero-schema" },
+ { title: "Reading Data with ZQL", href: "/reading-data" },
+ { title: "Writing Data with Mutators", href: "/writing-data" },
+ { title: "Authentication", href: "/auth" },
+ { title: "Permissions", href: "/permissions" },
+ { title: "Preloading", href: "/preloading" },
+ { title: "Schema Migrations", href: "/migrations" },
+ { title: "Deployment", href: "/deployment" },
+ { title: "`zero-cache` Config", href: "/zero-cache-config" },
+ { title: "Recipes", href: "/recipes" },
+ ],
+ },
- {
- title: 'Integrations',
- href: '',
- noLink: true,
- items: [
- {title: 'React', href: '/react'},
- {title: 'SolidJS', href: '/solidjs'},
- {title: 'Community', href: '/community'},
- ],
- },
+ {
+ title: "Integrations",
+ href: "",
+ noLink: true,
+ items: [
+ { title: "React", href: "/react" },
+ { title: "Expo", href: "/expo" },
+ { title: "SolidJS", href: "/solidjs" },
+ { title: "Community", href: "/community" },
+ ],
+ },
- {
- title: 'Meta',
- href: '',
- noLink: true,
- items: [
- {title: 'Roadmap', href: '/roadmap'},
- {title: 'Reporting Bugs', href: '/reporting-bugs'},
- {title: 'Release Notes', href: '/release-notes'},
- {title: 'Open Source', href: '/open-source'},
- ],
- },
+ {
+ title: "Meta",
+ href: "",
+ noLink: true,
+ items: [
+ { title: "Roadmap", href: "/roadmap" },
+ { title: "Reporting Bugs", href: "/reporting-bugs" },
+ { title: "Release Notes", href: "/release-notes" },
+ { title: "Open Source", href: "/open-source" },
+ ],
+ },
];
-type Page = {title: string; href: string};
+type Page = { title: string; href: string };
function getRecurrsiveAllLinks(node: EachRoute) {
- const ans: Page[] = [];
- if (!node.noLink) {
- ans.push({title: node.title, href: node.href});
- }
- node.items?.forEach(subNode => {
- const temp = {...subNode, href: `${node.href}${subNode.href}`};
- ans.push(...getRecurrsiveAllLinks(temp));
- });
- return ans;
+ const ans: Page[] = [];
+ if (!node.noLink) {
+ ans.push({ title: node.title, href: node.href });
+ }
+ node.items?.forEach((subNode) => {
+ const temp = { ...subNode, href: `${node.href}${subNode.href}` };
+ ans.push(...getRecurrsiveAllLinks(temp));
+ });
+ return ans;
}
-export const page_routes = ROUTES.map(it => getRecurrsiveAllLinks(it)).flat();
+export const page_routes = ROUTES.flatMap((it) => getRecurrsiveAllLinks(it));
From a75125190c1be937dce88a8bdb08e8908926a2dc Mon Sep 17 00:00:00 2001
From: Austin Mudd <31991302+austinm911@users.noreply.github.com>
Date: Wed, 19 Feb 2025 23:10:12 -0800
Subject: [PATCH 2/2] wip
---
contents/docs/expo/index.mdx | 24 +++++----
contents/docs/react-expo/index.mdx | 87 ------------------------------
2 files changed, 13 insertions(+), 98 deletions(-)
delete mode 100644 contents/docs/react-expo/index.mdx
diff --git a/contents/docs/expo/index.mdx b/contents/docs/expo/index.mdx
index c995c7f..4e79dcc 100644
--- a/contents/docs/expo/index.mdx
+++ b/contents/docs/expo/index.mdx
@@ -6,9 +6,8 @@ Zero has built-in support for Expo and React Native using the `expo-sqlite` and
## Prerequisites
-The `crypto.getRandomValues()` API is not available in React Native, so we need to polyfill it.
+The `crypto` API is not available in React Native, so we need to polyfill it.
-### Polyfill manually
First, install the `expo-crypto` package. See the [expo-crypto docs](https://docs.expo.dev/versions/latest/sdk/crypto/) for more information.
@@ -30,6 +29,10 @@ declare const global: {
};
export function bootCryptoPolyfill() {
+ if (global.crypto) {
+ return;
+ }
+
global.crypto = {
getRandomValues(array: Uint8Array) {
return Crypto.getRandomValues(array);
@@ -43,7 +46,6 @@ export function bootCryptoPolyfill() {
This will allow you to use the `crypto` API in your React Native project such as `crypto.getRandomValues()` and `crypto.randomUUID()`.
-
## Expo SQLite
For more information on how to use the `expo-sqlite` package, see the [expo-sqlite docs](https://docs.expo.dev/versions/latest/sdk/sqlite/).
@@ -67,7 +69,7 @@ npx expo prebuild
## Usage
-In your mobile app's layout, wrap your app's root component in the `ZeroProvider` component:
+In your mobile app's root index or layout file, wrap your app's with the `ZeroProvider` component:
```tsx
// apps/my-app/_layout.tsx
@@ -88,7 +90,7 @@ export const unstable_settings = {
};
export default function RootLayout() {
- // Memoize the Zero instance so it's only created once per app lifecycle
+ // In production, memoize the Zero instance so it's only created once per app lifecycle
// Note: If you intend to use Expo Web, you should use kvStore: 'mem' or 'idb' with a check like
// const store = Platform.OS === 'web' ? 'idb' : createExpoSQLiteStore;
const z = useMemo(
@@ -97,11 +99,11 @@ export default function RootLayout() {
userID: 'your-user-id',
auth: 'your-auth-token',
server: process.env.EXPO_PUBLIC_SERVER_URL, // see https://docs.expo.dev/guides/environment-variables/
- kvStore: createExpoSQLiteStore, // initialize the SQLite store
+ kvStore: createExpoSQLiteStore,
// kvStore: createExpoSQLiteStore, // or if using op-sqlite
schema,
}),
- [],
+ [userId, authToken],
);
if (!z) {
@@ -111,8 +113,8 @@ export default function RootLayout() {
return (
-
-
+
+
);
@@ -122,7 +124,7 @@ export default function RootLayout() {
Interact with the Zero instance in your components using the `zero/react` package. Please see the [React docs](react) for more details.
```tsx
-import { useQuery, useZero } from '@rocicorp/zero/react';
+import {useQuery, useZero} from '@rocicorp/zero/react';
function IssueList() {
const z = useZero();
@@ -140,7 +142,7 @@ function IssueList() {
const [issues, issuesDetail] = useQuery(issueQuery);
- // Your component ReactJSX
+ // Your component React Native JSX
return ...;
}
```
diff --git a/contents/docs/react-expo/index.mdx b/contents/docs/react-expo/index.mdx
deleted file mode 100644
index 68aa046..0000000
--- a/contents/docs/react-expo/index.mdx
+++ /dev/null
@@ -1,87 +0,0 @@
----
-title: React Expo
----
-
-Zero has built-in support for React Expo using the `expo-sqlite` and `op-sqlite` packages.
-
-In your mobile app's layout, wrap your app's root component in the `ZeroProvider` component:
-```tsx
-// apps/my-app/_layout.tsx
-import '../globals.css';
-import { Zero } from '@rocicorp/zero';
-import { ZeroProvider } from '@rocicorp/zero/react';
-import { createExpoSQLiteStore } from '@rocicorp/zero/expo';
-// or if using op-sqlite
-// import { createOPSQLiteStore } from '@rocicorp/zero/op-sqlite';
-
-import { Stack } from 'expo-router';
-import { useMemo } from 'react';
-import { schema } from '../lib/schema'; // or wherever you have your schema
-
-export const unstable_settings = {
- // Ensure that reloading on `/modal` keeps a back button present.
- initialRouteName: '(tabs)',
-};
-
-export default function RootLayout() {
- // Memoize the Zero instance so it's only created once per app lifecycle
- const zero = useMemo(
- () =>
- new Zero({
- userID: "your-user-id",
- auth: "your-auth-token",
- server: process.env.EXPO_PUBLIC_SERVER_URL, // see https://docs.expo.dev/guides/environment-variables/
- kvStore: createExpoSQLiteStore, // initialize the SQLite store
- // kvStore: createExpoSQLiteStore, // or if using op-sqlite
- schema,
- }),
- []
- );
-
- if (!z) {
- return null;
- }
-
- return (
-
-
-
-
-
-
- );
-}
-
-```
-
-Interact with the Zero instance in your components using the `zero/react` package. Please see the [React docs](react) for more details.
-
-```tsx
-import {useQuery, useZero} from "@rocicorp/zero/react";
-
-function IssueList() {
- const z = useZero();
-
- let issueQuery = z.query.issue
- .related('creator')
- .related('labels')
- .limit(100);
-
- const userID = selectedUserID();
-
- if (userID) {
- issueQuery = issueQuery.where('creatorID', '=', userID);
- }
-
- const [issues, issuesDetail] = useQuery(issueQuery);
-
- // Your component ReactJSX
- return (
-
- ...
-
- )
-}
-```
-
-Complete quickstart here: COMING SOON
\ No newline at end of file