Compare commits

..

40 Commits

Author SHA1 Message Date
Guido D'Orsi
83513b624e Merge pull request #1187 from garden-co/changeset-release/main
Version Packages
2025-01-12 12:41:54 +01:00
github-actions[bot]
6042250940 Version Packages 2025-01-12 09:54:11 +00:00
Guido D'Orsi
f78c234780 fix(rn): add unstable_enablePackageExports to the metro config 2025-01-12 10:53:03 +01:00
Guido D'Orsi
21efae9276 Merge pull request #1185 from garden-co/changeset-release/main
Version Packages
2025-01-11 16:35:54 +01:00
github-actions[bot]
1e58606ae7 Version Packages 2025-01-11 14:44:01 +00:00
Guido D'Orsi
4a11682316 Merge pull request #1186 from tobiaslins/fix-priority-rn-sqlite
[React Native] Change priority of sqlite to `100`
2025-01-11 15:42:46 +01:00
Tobias Lins
3e92680b08 Update README.md 2025-01-11 15:12:37 +01:00
Tobias Lins
2be47d688b Change priority of sqlite to 100 2025-01-11 15:11:37 +01:00
Guido D'Orsi
2ddccdbca5 Update dull-walls-crash.md 2025-01-11 14:00:02 +01:00
Guido D'Orsi
ab05897cd6 Merge pull request #1183 from tobiaslins/improve-expo-secure-storage
[react native] don't require faceid for every KV operation
2025-01-11 13:56:16 +01:00
Tobias Lins
7cd691f5f0 Create dull-walls-crash.md 2025-01-11 13:48:08 +01:00
Tobias Lins
24a13af657 Improve initialization when using custom kv storage 2025-01-11 13:41:12 +01:00
Tobias Lins
b13530e84b don't require faceid for every get/set 2025-01-11 11:09:56 +01:00
Guido D'Orsi
3911b72f87 docs: fix version number on the rn upgrade docs 2025-01-11 00:23:32 +01:00
Guido D'Orsi
ec278cfcd8 Merge pull request #1182 from garden-co/changeset-release/main
Version Packages
2025-01-11 00:22:19 +01:00
github-actions[bot]
912730378e Version Packages 2025-01-10 21:59:07 +00:00
Guido D'Orsi
ac35f19f01 Merge pull request #1130 from tobiaslins/rn-storage-sqlite
feat: sqlite react native storage
2025-01-10 22:58:03 +01:00
Guido D'Orsi
31fd994d83 Merge pull request #1180 from garden-co/jazz-636-add-test-for-react-starter-app
Fix and test react starter app
2025-01-10 16:53:42 +01:00
Trisha Lim
a6eea34c74 Run starter test 2025-01-10 15:35:16 +00:00
Trisha Lim
3605b746a9 Highlight new lines on upgrade guide 2025-01-10 15:32:02 +00:00
Trisha Lim
4b29a9aaa6 Test react starter app 2025-01-10 15:30:15 +00:00
Trisha Lim
e60a9f4a74 Fix react starter app 2025-01-10 15:26:56 +00:00
Guido D'Orsi
55e8a269c0 fix: fix homepage type error 2025-01-10 12:45:42 +01:00
Guido D'Orsi
0db0aadd45 fix: fix homepage type error 2025-01-10 12:38:12 +01:00
Guido D'Orsi
83f3873e03 feat: make the persistence disabled by default 2025-01-10 12:26:14 +01:00
Guido D'Orsi
80fd3e9697 chore: changeset 2025-01-10 12:16:04 +01:00
Guido D'Orsi
bae8268b29 feat: add upgrade docs and option to disable storage 2025-01-10 12:14:16 +01:00
Guido D'Orsi
3e9b7e829c Merge pull request #1175 from garden-co/jazz-639-fix-passkey-svelte
Fix imports for passkey-svelte
2025-01-09 15:51:05 +01:00
Benjamin S. Leveritt
530720f2b9 Fix imports 2025-01-09 14:47:23 +00:00
Guido D'Orsi
2db8b35cf7 feat: simplify storage setup and update docs 2025-01-08 18:12:22 +01:00
Guido D'Orsi
a3234f3912 Merge remote-tracking branch 'origin/main' into pr-rn-storage-sqlite 2025-01-08 16:38:35 +01:00
Tobias Lins
7ebc77c95f Update chat.tsx 2025-01-08 09:54:55 +01:00
Tobias Lins
de20b17989 Update App.tsx 2025-01-08 09:53:37 +01:00
Tobias Lins
cae4b244e8 Update polyfills.js 2025-01-08 09:52:53 +01:00
Tobias Lins
eed5aec08d Cleanup 2025-01-08 09:51:29 +01:00
Tobias Lins
90fa0e0588 Merge remote-tracking branch 'upstream/main' into rn-storage-sqlite 2025-01-08 09:26:44 +01:00
Tobias Lins
c4d5cad2d4 Fixes 2025-01-05 10:53:59 +01:00
Tobias Lins
718543cf83 fix tx support 2025-01-04 16:52:05 +01:00
Tobias Lins
ca8f21358e Move to other library 2025-01-04 12:42:22 +01:00
Tobias Lins
d09584fa88 WIP sqlite react native storage 2025-01-04 11:24:13 +01:00
46 changed files with 1589 additions and 68 deletions

View File

@@ -13,7 +13,7 @@ jobs:
continue-on-error: true
strategy:
matrix:
project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/pets", "examples/onboarding"]
project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/pets", "examples/onboarding", "starters/react-demo-auth-tailwind"]
steps:
- uses: actions/checkout@v3

View File

@@ -1,5 +1,21 @@
# chat-rn-clerk
## 1.0.45
### Patch Changes
- Updated dependencies [7cd691f]
- jazz-react-native@0.9.3
- jazz-react-native-auth-clerk@0.9.3
## 1.0.44
### Patch Changes
- Updated dependencies [80fd3e9]
- jazz-react-native@0.9.2
- jazz-react-native-auth-clerk@0.9.2
## 1.0.43
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-clerk",
"main": "index.js",
"version": "1.0.43",
"version": "1.0.45",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",
@@ -20,6 +20,7 @@
"@bam.tech/react-native-image-resizer": "^3.0.11",
"@clerk/clerk-expo": "^2.2.21",
"@expo/vector-icons": "^14.0.2",
"@op-engineering/op-sqlite": "^11.2.12",
"@react-native-community/netinfo": "^11.4.1",
"@react-navigation/native": "^7.0.13",
"@react-navigation/native-stack": "^7.1.14",

View File

@@ -50,6 +50,7 @@ export function JazzAndAuth({ children }: PropsWithChildren) {
{auth && clerk.user ? (
<JazzProvider
auth={auth}
storage="sqlite"
peer="wss://cloud.jazz.tools/?key=chat-rn-clerk-example-jazz@garden.co"
>
{children}

View File

@@ -1,5 +1,19 @@
# chat-rn
## 1.0.42
### Patch Changes
- Updated dependencies [7cd691f]
- jazz-react-native@0.9.3
## 1.0.41
### Patch Changes
- Updated dependencies [80fd3e9]
- jazz-react-native@0.9.2
## 1.0.40
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.40",
"version": "1.0.42",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",
@@ -13,6 +13,7 @@
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@op-engineering/op-sqlite": "^11.2.12",
"@react-native-community/netinfo": "^11.4.1",
"@react-navigation/native": "^7.0.13",
"@react-navigation/native-stack": "^7.1.14",

View File

@@ -33,7 +33,6 @@ function App() {
"ChatScreen" | "HandleInviteScreen"
>("ChatScreen");
const navigationRef = useNavigationContainerRef();
useEffect(() => {
Linking.getInitialURL().then((url) => {
if (url) {
@@ -52,6 +51,7 @@ function App() {
<StrictMode>
<JazzProvider
auth={auth}
storage="sqlite"
peer="wss://cloud.jazz.tools/?key=chat-rn-example-jazz@garden.co"
>
<NavigationContainer linking={linking} ref={navigationRef}>

View File

@@ -1,3 +0,0 @@
import { createJazzApp } from 'jazz-svelte';
export const { useAccount, useCoState, Provider } = createJazzApp();

View File

@@ -1,6 +1,5 @@
<script lang="ts">
import { usePasskeyAuth, PasskeyAuthBasicUI } from 'jazz-svelte';
import { Provider } from '$lib/jazz';
import { JazzProvider, PasskeyAuthBasicUI, usePasskeyAuth } from 'jazz-svelte';
let { children } = $props();
@@ -15,12 +14,12 @@
<PasskeyAuthBasicUI state={auth.state} />
{#if auth.current}
<Provider
<JazzProvider
auth={auth.current}
peer="wss://cloud.jazz.tools/?key=minimal-svelte-auth-passkey@garden.co"
>
{@render children?.()}
</Provider>
</JazzProvider>
{/if}
</div>

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { useAccount } from '$lib/jazz';
import { useAccount } from 'jazz-svelte';
const account = useAccount({
root: {}

View File

@@ -36,9 +36,7 @@ Tested with:
```bash
npx expo install expo-linking expo-secure-store expo-file-system @react-native-community/netinfo @bam.tech/react-native-image-resizer @azure/core-asynciterator-polyfill
npm i -S react-native-polyfill-globals react-native-url-polyfill web-streams-polyfill@3.2.1 base-64 text-encoding react-native-fetch-api react-native-get-random-values buffer
npm i -D @babel/plugin-transform-class-static-block
npm i -S react-native-polyfill-globals react-native-url-polyfill web-streams-polyfill@3.2.1 base-64 text-encoding react-native-fetch-api react-native-get-random-values buffer @op-engineering/op-sqlite
npm i -S jazz-tools jazz-react-native jazz-react-native-media-images

View File

@@ -21,7 +21,7 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
<div>
The `JazzProvider` is now imported from `jazz-react` instead of `createJazzReactApp`.
While `createJazzReactApp` was originally designed to setup strong typing for custom Account schemas in `useAccount`,
While `createJazzReactApp` was originally designed to setup strong typing for custom Account schemas in `useAccount`,
we found that this approach made the Jazz setup awkward and confusing for some users.
So we decided to remove `createJazzReactApp` step and to provide the types through namespace declarations:
@@ -46,29 +46,29 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
<JazzProvider
auth={passkeyAuth} // old
peer="wss://cloud.jazz.tools/?key=you@example.com" // old
AccountSchema={MyAppAccount} {/* The custom Account schema is passed here */}
AccountSchema={MyAppAccount} {/* The custom Account schema is passed here */} // *add*
>
{children} // old
</JazzProvider>
<PasskeyAuthBasicUI state={passKeyState} /> // old
</> // old
);
);
}
// Register the Account schema so `useAccount` returns our custom `MyAppAccount`
declare module "jazz-react" {
interface Register {
Account: MyAppAccount;
}
}
declare module "jazz-react" { // *add*
interface Register { // *add*
Account: MyAppAccount; // *add*
} // *add*
} // *add*
```
</CodeGroup>
<h3>Top level imports for hooks</h3>
<div>
All Jazz hooks are now available as top-level imports from the `jazz-react` package.
All Jazz hooks are now available as top-level imports from the `jazz-react` package.
This change improves IDE intellisense support and simplifies imports:
</div>
@@ -86,7 +86,7 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
<>
Hello {me.profile?.name}
</>
);
);
}
```
</CodeGroup>
@@ -105,7 +105,7 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
```tsx
import { createJazzTestAccount, JazzTestProvider } from "jazz-react/testing";
import { renderHook } from "@testing-library/react"; // old
import { usePlaylist } from "./usePlaylist"; // old
import { usePlaylist } from "./usePlaylist"; // old
import { Playlist, MusicAccount } from "./schema"; // old
test("should load the playlist", async () => {
@@ -146,7 +146,7 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
<div>
The `JazzProvider` is now imported from `jazz-react-native` instead of `createJazzRNApp`.
While `createJazzRNApp` was originally designed to setup strong typing for custom Account schemas in `useAccount`,
While `createJazzRNApp` was originally designed to setup strong typing for custom Account schemas in `useAccount`,
we found that this approach made the Jazz setup awkward and confusing for some users.
So we decided to remove `createJazzRNApp` step and to provide the types through namespace declarations:
@@ -177,7 +177,7 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
</JazzProvider>
<DemoAuthBasicUI appName="My App" state={state} /> // old
</> // old
);
);
}
// Register the Account schema so `useAccount` returns our custom `MyAppAccount`
@@ -192,8 +192,8 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
<h3>Top level imports for hooks</h3>
<div>
All Jazz hooks are now available as top-level imports from the `jazz-react-native` package.
All Jazz hooks are now available as top-level imports from the `jazz-react-native` package.
This change improves IDE intellisense support and simplifies imports:
</div>
@@ -211,7 +211,7 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
<>
Hello {me.profile?.name}
</>
);
);
}
```
</CodeGroup>
@@ -271,7 +271,7 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
<div>
The `JazzProvider` is now imported from `jazz-svelte` instead of `createJazzApp`.
While `createJazzApp` was originally designed to setup strong typing for custom Account schemas in `useAccount`,
While `createJazzApp` was originally designed to setup strong typing for custom Account schemas in `useAccount`,
we found that this approach made the Jazz setup awkward and confusing for some users.
So we decided to remove `createJazzApp` step and to provide the types through namespace declarations:
@@ -302,7 +302,7 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
let AccountSchema = MyAccount;
</script>
<JazzProvider {auth} {peer} {AccountSchema}>
<JazzProvider {auth} {peer} {AccountSchema}>
<App />
</JazzProvider>
```
@@ -311,8 +311,8 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
<h3>Top level imports for hooks</h3>
<div>
All Jazz hooks are now available as top-level imports from the `jazz-svelte` package.
All Jazz hooks are now available as top-level imports from the `jazz-svelte` package.
This change improves IDE intellisense support and simplifies imports:
</div>
@@ -387,7 +387,7 @@ export const metadata = { title: "Upgrade to Jazz 0.9.0" };
<div>
The `JazzProvider` is now imported from `jazz-vue` instead of `createJazzVueApp`.
While `createJazzReactApp` was originally designed to setup strong typing for custom Account schemas in `useAccount`,
While `createJazzReactApp` was originally designed to setup strong typing for custom Account schemas in `useAccount`,
we found that this approach made the Jazz setup awkward and confusing for some users.
So we decided to remove `createJazzReactApp` step and to provide the types through namespace declarations:
@@ -409,7 +409,7 @@ export const { useAccount, useCoState } = Jazz; // *bin*
const { JazzProvider } = Jazz; // *bin*
const RootComponent = defineComponent({ // old
name: "RootComponent", // old
name: "RootComponent", // old
setup() { // old
const { authMethod, state } = useDemoAuth(); // old
return () => [ // old
@@ -449,8 +449,8 @@ app.mount("#app"); // old
<h3>Top level imports for hooks</h3>
<div>
All Jazz hooks are now available as top-level imports from the `jazz-vue` package.
All Jazz hooks are now available as top-level imports from the `jazz-vue` package.
This change improves IDE intellisense support and simplifies imports:
</div>

View File

@@ -0,0 +1,49 @@
import { ContentByFramework, CodeGroup } from '@/components/forMdx'
export const metadata = { title: "Enable local persistence" };
# Enable local persistence
<h2 className="not-prose text-sm text-stone-600 dark:text-stone-400 mb-5 pb-2 border-b">
10 January 2025
</h2>
<ContentByFramework framework="react-native">
<div>
Version 0.9.2 introduces local persistence for React Native apps using SQLite.
If you are upgrading from a version before 0.9.2, you need to enable local persistence by following the steps below.
Local persistence will become the default in 0.10.0.
</div>
<h3>Add the required dependencies</h3>
<div>
As SQLite package we now use `@op-engineering/op-sqlite`.
To get local persistence working, you need to add `@op-engineering/op-sqlite` as a direct dependency to your project and run `npx pod-install`.
</div>
<h3>Update your JazzProvider to enable local persistence</h3>
<div>
Local persistence is now disabled by default.
To enable it, you need to pass the `storage` option to the `JazzProvider` component:
</div>
<CodeGroup>
```tsx
<JazzProvider
auth={auto}
storage="sqlite"
peer="wss://cloud.jazz.tools/?key=you@example.com"
AccountSchema={MyAppAccount}
>
<App />
</JazzProvider>
```
</CodeGroup>
</ContentByFramework>

View File

@@ -12,19 +12,21 @@ export function DocNav({ className }: { className?: string }) {
const items = docNavigationItems.map((headerItem) => {
return {
...headerItem,
items: headerItem.items.map((item) => {
if (!item.href?.startsWith("/docs")) return item;
items: headerItem.items
.filter((item) => !item.framework || item.framework === framework)
.map((item) => {
if (!item.href?.startsWith("/docs")) return item;
let done =
typeof item.done === "number" ? item.done : item.done[framework];
let href = item.href.replace("/docs", `/docs/${framework}`);
let done =
typeof item.done === "number" ? item.done : item.done[framework];
let href = item.href.replace("/docs", `/docs/${framework}`);
return {
...item,
href,
done,
};
}),
return {
...item,
href,
done,
};
}),
};
});

View File

@@ -1,5 +1,6 @@
import { ThemeToggle } from "@/components/ThemeToggle";
import { socials } from "@/lib/socials";
import { useFramework } from "@/lib/use-framework";
import { JazzLogo } from "gcmp-design-system/src/app/components/atoms/logos/JazzLogo";
import { Nav } from "gcmp-design-system/src/app/components/organisms/Nav";
import { DocNav } from "./docs/nav";

View File

@@ -50,6 +50,13 @@ export const docNavigationItems = [
href: "/docs/project-setup/server-side",
done: 80,
},
{
// upgrade guides
name: "Enable local persistence",
href: "/docs/upgrade/react-native-local-persistence",
done: 100,
framework: "react-native",
},
{
// upgrade guides
name: "Upgrade to Jazz 0.9.0",

View File

@@ -0,0 +1,171 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
\*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
\*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
\*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
\*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.\*
.DS_Store

View File

@@ -0,0 +1,2 @@
coverage
node_modules

View File

@@ -0,0 +1,595 @@
# cojson-storage-sqlite
## 0.8.51
### Patch Changes
- 2be47d6: Fix priority of rn sqlite
## 0.8.50
### Patch Changes
- Updated dependencies [43378ef]
- cojson@0.8.50
- cojson-storage@0.8.50
## 0.8.49
### Patch Changes
- Updated dependencies [25dfd90]
- cojson@0.8.49
- cojson-storage@0.8.49
## 0.8.48
### Patch Changes
- Updated dependencies [10ea733]
- cojson@0.8.48
- cojson-storage@0.8.48
## 0.8.45
### Patch Changes
- Updated dependencies [6f0bd7f]
- Updated dependencies [fca6a0b]
- Updated dependencies [88d7d9a]
- cojson@0.8.45
- cojson-storage@0.8.45
## 0.8.44
### Patch Changes
- Updated dependencies [5d20c81]
- cojson@0.8.44
- cojson-storage@0.8.44
## 0.8.41
### Patch Changes
- Updated dependencies [3252502]
- Updated dependencies [6370348]
- Updated dependencies [ac216b9]
- cojson@0.8.41
- cojson-storage@0.8.41
## 0.8.40
### Patch Changes
- Updated dependencies [e905c84]
- cojson-storage@0.8.40
## 0.8.39
### Patch Changes
- ecc7c96: Bump better-sqlite3 dependency, which drops support for Node v21
- Updated dependencies [249eecb]
- Updated dependencies [3121551]
- cojson@0.8.39
- cojson-storage@0.8.39
## 0.8.38
### Patch Changes
- da13eca: Improve work scheduling under pressure
- Updated dependencies [b00ee91]
- Updated dependencies [f488c09]
- cojson@0.8.38
- cojson-storage@0.8.38
## 0.8.37
### Patch Changes
- Updated dependencies [3d9f12e]
- cojson@0.8.37
- cojson-storage@0.8.37
## 0.8.36
### Patch Changes
- 1afbd2c: Refactor the SQLite and IndexedDB storage packages to extract common synchronization functionality into newly created cojson-storage package.
- Updated dependencies [441fe27]
- Updated dependencies [1afbd2c]
- cojson@0.8.36
- cojson-storage@0.8.36
## 0.8.35
### Patch Changes
- 8b87117: Implement Group Inheritance
- Updated dependencies [3f15a23]
- Updated dependencies [46f2ab8]
- Updated dependencies [8b87117]
- Updated dependencies [a6b6ccf]
- cojson@0.8.35
## 0.8.34
### Patch Changes
- Updated dependencies [e4f110f]
- cojson@0.8.34
## 0.8.32
### Patch Changes
- Updated dependencies [df42b2b]
- cojson@0.8.32
## 0.8.31
### Patch Changes
- Updated dependencies [e511d6d]
- cojson@0.8.31
## 0.8.30
### Patch Changes
- Updated dependencies [0a2fae3]
- Updated dependencies [99cda2f]
- cojson@0.8.30
## 0.8.29
### Patch Changes
- Updated dependencies [dcc9c2e]
- Updated dependencies [699553f]
- cojson@0.8.29
## 0.8.28
### Patch Changes
- Updated dependencies [605734c]
- cojson@0.8.28
## 0.8.27
### Patch Changes
- Updated dependencies [75fdff4]
- cojson@0.8.27
## 0.8.25
### Patch Changes
- 63d46c9: Fix: sqlite not delivering depended-on CoValues
## 0.8.23
### Patch Changes
- Updated dependencies [6f745be]
- Updated dependencies [124bf67]
- cojson@0.8.23
## 0.8.21
### Patch Changes
- Updated dependencies [0f30eea]
- cojson@0.8.21
## 0.8.19
### Patch Changes
- Updated dependencies [9c2aadb]
- cojson@0.8.19
## 0.8.18
### Patch Changes
- Updated dependencies [d4319d8]
- cojson@0.8.18
## 0.8.17
### Patch Changes
- Updated dependencies [d433cf4]
- cojson@0.8.17
## 0.8.16
### Patch Changes
- Updated dependencies [b934fab]
- cojson@0.8.16
## 0.8.12
### Patch Changes
- 6ed75eb: Introduce "storage" peer role
- Updated dependencies [6ed75eb]
- cojson@0.8.12
## 0.8.11
### Patch Changes
- Updated dependencies [1ed4ab5]
- cojson@0.8.11
## 0.8.5
### Patch Changes
- Updated dependencies [c3f4e6b]
- Updated dependencies [d9152ed]
- cojson@0.8.5
## 0.8.3
### Patch Changes
- Updated dependencies
- cojson@0.8.3
## 0.8.0
### Patch Changes
- Updated dependencies [6a147c2]
- Updated dependencies [ad40b88]
- cojson@0.8.0
## 0.7.35
### Patch Changes
- f350e90: Added a priority system for the sync messages
- Updated dependencies [35bbcd9]
- Updated dependencies [f350e90]
- cojson@0.7.35
## 0.7.34
### Patch Changes
- Updated dependencies [5d91f9f]
- Updated dependencies [5094e6d]
- Updated dependencies [b09589b]
- Updated dependencies [2c3a40c]
- Updated dependencies [4e16575]
- Updated dependencies [ea882ab]
- cojson@0.7.34
## 0.7.34-neverthrow.8
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.8
## 0.7.34-neverthrow.7
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.7
## 0.7.34-neverthrow.4
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.4
## 0.7.34-neverthrow.3
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.3
## 0.7.34-neverthrow.1
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.1
## 0.7.34-neverthrow.0
### Patch Changes
- Updated dependencies
- cojson@0.7.34-neverthrow.0
## 0.7.33
### Patch Changes
- 3bf5127: Allow crashing whole node on peer errors
- Updated dependencies [b297c93]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson@0.7.33
## 0.7.33-hotfixes.6
### Patch Changes
- Get rid of simulated errors
## 0.7.33-hotfixes.5
### Patch Changes
- Make simulated errors even more likely
- Updated dependencies
- cojson@0.7.33-hotfixes.5
## 0.7.33-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
## 0.7.33-hotfixes.3
### Patch Changes
- Allow crashing whole node on peer errors
- Updated dependencies
- cojson@0.7.33-hotfixes.3
## 0.7.33-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
## 0.7.31
### Patch Changes
- Updated dependencies
- cojson@0.7.31
## 0.7.29
### Patch Changes
- Updated dependencies
- cojson@0.7.29
## 0.7.28
### Patch Changes
- Updated dependencies
- cojson@0.7.28
## 0.7.26
### Patch Changes
- Remove Effect from jazz/cojson internals
- Updated dependencies
- cojson@0.7.26
## 0.7.23
### Patch Changes
- Updated dependencies
- cojson@0.7.23
## 0.7.18
### Patch Changes
- Updated dependencies
- cojson@0.7.18
## 0.7.17
### Patch Changes
- Updated dependencies
- cojson@0.7.17
## 0.7.14
### Patch Changes
- Updated dependencies
- cojson@0.7.14
## 0.7.11
### Patch Changes
- Updated dependencies
- cojson@0.7.11
## 0.7.10
### Patch Changes
- Updated dependencies
- cojson@0.7.10
## 0.7.9
### Patch Changes
- Updated dependencies
- cojson@0.7.9
## 0.7.0
### Patch Changes
- c4151fc: Support stricter TS lint rules
- 21771c4: Reintroduce changes from main
- 69ac514: Use effect schema much less
- f0f6f1b: Clean up API more & re-add jazz-nodejs
- Updated dependencies [1a35307]
- Updated dependencies [96c494f]
- Updated dependencies [19f52b7]
- Updated dependencies [d8fe2b1]
- Updated dependencies [1200aae]
- Updated dependencies [52675c9]
- Updated dependencies [1a35307]
- Updated dependencies [e299c3e]
- Updated dependencies [bf0f8ec]
- Updated dependencies [c4151fc]
- Updated dependencies [8636319]
- Updated dependencies [952982e]
- Updated dependencies [21771c4]
- Updated dependencies [69ac514]
- Updated dependencies [f0f6f1b]
- Updated dependencies [1a44f87]
- Updated dependencies [63374cc]
- cojson@0.7.0
## 0.7.0-alpha.42
### Patch Changes
- Updated dependencies
- cojson@0.7.0-alpha.42
## 0.7.0-alpha.39
### Patch Changes
- Updated dependencies
- cojson@0.7.0-alpha.39
## 0.7.0-alpha.38
### Patch Changes
- Updated dependencies
- cojson@0.7.0-alpha.38
## 0.7.0-alpha.37
### Patch Changes
- Updated dependencies
- cojson@0.7.0-alpha.37
## 0.7.0-alpha.36
### Patch Changes
- Updated dependencies [1a35307]
- Updated dependencies [1a35307]
- cojson@0.7.0-alpha.36
## 0.7.0-alpha.35
### Patch Changes
- Updated dependencies
- cojson@0.7.0-alpha.35
## 0.7.0-alpha.29
### Patch Changes
- Reintroduce changes from main
- Updated dependencies
- cojson@0.7.0-alpha.29
## 0.7.0-alpha.28
### Patch Changes
- Updated dependencies
- cojson@0.7.0-alpha.28
## 0.7.0-alpha.27
### Patch Changes
- Updated dependencies
- cojson@0.7.0-alpha.27
## 0.7.0-alpha.24
### Patch Changes
- Updated dependencies
- cojson@0.7.0-alpha.24
## 0.7.0-alpha.11
### Patch Changes
- Support stricter TS lint rules
- Updated dependencies
- cojson@0.7.0-alpha.11
## 0.7.0-alpha.10
### Patch Changes
- Clean up API more & re-add jazz-nodejs
- Updated dependencies
- cojson@0.7.0-alpha.10
## 0.5.3-alpha.1
### Patch Changes
- Use effect schema much less
- Updated dependencies
- cojson@0.7.0-alpha.1
## 0.5.3-alpha.0
### Patch Changes
- Updated dependencies
- cojson@0.7.0-alpha.0
## 0.5.2
### Patch Changes
- Updated dependencies
- cojson@0.6.0
## 0.5.1
### Patch Changes
- Make typedefs for better-sqlite3 a normal dependency
## 0.5.0
### Minor Changes
- Adding a lot of performance improvements to cojson, add a stresstest for the twit example and make that run smoother in a lot of ways.
### Patch Changes
- Updated dependencies
- cojson@0.5.0

View File

@@ -0,0 +1,19 @@
Copyright 2024, Garden Computing, Inc.
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.

View File

@@ -0,0 +1,3 @@
# CoJSON Storage SQLite for React Native
This implements persistence for CoJSON / Jazz (see [jazz.tools](https://jazz.tools)) using SQLite.

View File

@@ -0,0 +1,23 @@
{
"name": "cojson-storage-rn-sqlite",
"type": "module",
"version": "0.8.51",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"cojson": "workspace:*",
"cojson-storage": "workspace:*"
},
"devDependencies": {
"@op-engineering/op-sqlite": "^11.2.12",
"typescript": "~5.6.2"
},
"scripts": {
"dev": "tsc --watch --sourceMap --outDir dist",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"build": "rm -rf ./dist && tsc --sourceMap --outDir dist",
"prepublishOnly": "npm run build"
}
}

View File

@@ -0,0 +1,159 @@
import { type DB as DatabaseT } from "@op-engineering/op-sqlite";
import { CojsonInternalTypes, type OutgoingSyncQueue, RawCoID } from "cojson";
import type {
DBClientInterface,
SessionRow,
SignatureAfterRow,
StoredCoValueRow,
StoredSessionRow,
TransactionRow,
} from "cojson-storage";
import { Transaction } from "cojson/src/coValueCore.js";
import { Signature } from "cojson/src/crypto/crypto.js";
export class SQLiteClient implements DBClientInterface {
private readonly db: DatabaseT;
constructor(db: DatabaseT, _: OutgoingSyncQueue) {
this.db = db;
}
async getCoValue(coValueId: RawCoID): Promise<StoredCoValueRow | undefined> {
const { rows } = await this.db.execute(
"SELECT * FROM coValues WHERE id = ?",
[coValueId],
);
if (!rows || rows.length === 0) return;
const coValueRow = rows[0] as any & { rowID: number };
try {
const parsedHeader =
coValueRow?.header &&
(JSON.parse(coValueRow.header) as CojsonInternalTypes.CoValueHeader);
return {
...coValueRow,
header: parsedHeader,
};
} catch (e) {
console.warn(coValueId, "Invalid JSON in header", e, coValueRow?.header);
return;
}
}
async getCoValueSessions(coValueRowId: number): Promise<StoredSessionRow[]> {
const { rows } = await this.db.execute(
"SELECT * FROM sessions WHERE coValue = ?",
[coValueRowId],
);
return rows as StoredSessionRow[];
}
async getNewTransactionInSession(
sessionRowId: number,
firstNewTxIdx: number,
): Promise<TransactionRow[]> {
const { rows } = await this.db.execute(
"SELECT * FROM transactions WHERE ses = ? AND idx >= ?",
[sessionRowId, firstNewTxIdx],
);
if (!rows || rows.length === 0) return [];
try {
return rows.map((row: any) => ({
...row,
tx: JSON.parse(row.tx) as Transaction,
}));
} catch (e) {
console.warn("Invalid JSON in transaction", e);
return [];
}
}
getSignatures(
sessionRowId: number,
firstNewTxIdx: number,
): Promise<SignatureAfterRow[]> | SignatureAfterRow[] {
const { rows } = this.db.executeSync(
"SELECT * FROM signatureAfter WHERE ses = ? AND idx >= ?",
[sessionRowId, firstNewTxIdx],
);
return rows as SignatureAfterRow[];
}
async addCoValue(
msg: CojsonInternalTypes.NewContentMessage,
): Promise<number> {
const { insertId } = await this.db.execute(
"INSERT INTO coValues (id, header) VALUES (?, ?)",
[msg.id, JSON.stringify(msg.header)],
);
return insertId ?? 0;
}
async addSessionUpdate({
sessionUpdate,
}: {
sessionUpdate: SessionRow;
}): Promise<number> {
const { rows } = await this.db.execute(
`INSERT INTO sessions (coValue, sessionID, lastIdx, lastSignature, bytesSinceLastSignature)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT(coValue, sessionID)
DO UPDATE SET lastIdx=excluded.lastIdx,
lastSignature=excluded.lastSignature,
bytesSinceLastSignature=excluded.bytesSinceLastSignature
RETURNING rowID`,
[
sessionUpdate.coValue,
sessionUpdate.sessionID,
sessionUpdate.lastIdx,
sessionUpdate.lastSignature,
sessionUpdate.bytesSinceLastSignature!,
],
);
return rows[0]?.rowID as number;
}
async addTransaction(
sessionRowID: number,
nextIdx: number,
newTransaction: Transaction,
): Promise<void> {
await this.db.execute(
"INSERT INTO transactions (ses, idx, tx) VALUES (?, ?, ?)",
[sessionRowID, nextIdx, JSON.stringify(newTransaction)],
);
}
async addSignatureAfter({
sessionRowID,
idx,
signature,
}: {
sessionRowID: number;
idx: number;
signature: Signature;
}): Promise<void> {
await this.db.execute(
"INSERT INTO signatureAfter (ses, idx, signature) VALUES (?, ?, ?)",
[sessionRowID, idx, signature],
);
}
async unitOfWork(
operationsCallback: () => Promise<unknown>[],
): Promise<void> {
try {
await this.db.transaction(async () => {
await Promise.all(operationsCallback());
});
} catch (e) {
console.error("Transaction failed:", e);
throw e;
}
}
}

View File

@@ -0,0 +1,4 @@
export {
SQLiteReactNative,
SQLiteReactNative as SQLiteStorage,
} from "./sqlite-react-native.js";

View File

@@ -0,0 +1,165 @@
import { type DB, open } from "@op-engineering/op-sqlite";
import {
type IncomingSyncStream,
type OutgoingSyncQueue,
type Peer,
cojsonInternals,
} from "cojson";
import { SyncManager } from "cojson-storage";
import { SQLiteClient } from "./client.js";
export class SQLiteReactNative {
private readonly syncManager: SyncManager;
private readonly dbClient: SQLiteClient;
constructor(
db: DB,
fromLocalNode: IncomingSyncStream,
toLocalNode: OutgoingSyncQueue,
) {
this.dbClient = new SQLiteClient(db, toLocalNode);
this.syncManager = new SyncManager(this.dbClient, toLocalNode);
const processMessages = async () => {
let lastTimer = performance.now();
for await (const msg of fromLocalNode) {
try {
if (msg === "Disconnected" || msg === "PingTimeout") {
throw new Error("Unexpected Disconnected message");
}
await this.syncManager.handleSyncMessage(msg);
// Since better-sqlite3 is synchronous there may be the case
// where a bulk of messages are processed using only microtasks
// which may block other peers from sending messages.
// To avoid this we schedule a timer to downgrade the priority of the storage peer work
if (performance.now() - lastTimer > 500) {
lastTimer = performance.now();
await new Promise((resolve) => setTimeout(resolve, 0));
}
} catch (e) {
console.error(
new Error(
`Error reading from localNode, handling msg\n\n${JSON.stringify(
msg,
(k, v) =>
k === "changes" || k === "encryptedChanges"
? `${v.slice(0, 20)}...`
: v,
)}`,
{ cause: e },
),
);
console.error(e);
}
}
};
processMessages().catch((e) =>
console.error("Error in processMessages in sqlite", e),
);
}
static async asPeer({
filename,
trace,
localNodeName = "local",
}: {
filename: string;
trace?: boolean;
localNodeName?: string;
}): Promise<Peer> {
const [localNodeAsPeer, storageAsPeer] = cojsonInternals.connectedPeers(
localNodeName,
"storage",
{ peer1role: "client", peer2role: "storage", trace, crashOnClose: true },
);
await SQLiteReactNative.open(
filename,
localNodeAsPeer.incoming,
localNodeAsPeer.outgoing,
);
return { ...storageAsPeer, priority: 100 };
}
static async open(
filename: string,
fromLocalNode: IncomingSyncStream,
toLocalNode: OutgoingSyncQueue,
) {
const db = open({
name: filename,
});
await db.execute("PRAGMA journal_mode = WAL;"); // or OFF
const oldVersion =
Number((await db.execute("PRAGMA user_version")).rows[0]?.user_version) ??
0;
if (oldVersion === 0) {
await db.execute(
`CREATE TABLE IF NOT EXISTS transactions (
ses INTEGER,
idx INTEGER,
tx TEXT NOT NULL,
PRIMARY KEY (ses, idx)
) WITHOUT ROWID;`,
);
await db.execute(
`CREATE TABLE IF NOT EXISTS sessions (
rowID INTEGER PRIMARY KEY,
coValue INTEGER NOT NULL,
sessionID TEXT NOT NULL,
lastIdx INTEGER,
lastSignature TEXT,
UNIQUE (sessionID, coValue)
);`,
);
await db.execute(
`CREATE INDEX IF NOT EXISTS sessionsByCoValue ON sessions (coValue);`,
);
await db.execute(
`CREATE TABLE IF NOT EXISTS coValues (
rowID INTEGER PRIMARY KEY,
id TEXT NOT NULL UNIQUE,
header TEXT NOT NULL UNIQUE
);`,
);
await db.execute(
`CREATE INDEX IF NOT EXISTS coValuesByID ON coValues (id);`,
);
await db.execute("PRAGMA user_version = 1");
}
if (oldVersion <= 2) {
await db.execute(
`CREATE TABLE IF NOT EXISTS signatureAfter (
ses INTEGER,
idx INTEGER,
signature TEXT NOT NULL,
PRIMARY KEY (ses, idx)
) WITHOUT ROWID;`,
);
await db.execute(
`ALTER TABLE sessions ADD COLUMN bytesSinceLastSignature INTEGER;`,
);
await db.execute("PRAGMA user_version = 3");
}
return new SQLiteReactNative(db, fromLocalNode, toLocalNode);
}
}

View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"module": "esnext",
"target": "ES2020",
"moduleResolution": "bundler",
"moduleDetection": "force",
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noUncheckedIndexedAccess": true,
"esModuleInterop": true
},
"include": ["./src/**/*"]
}

View File

@@ -1,5 +1,11 @@
# create-jazz-app
## 0.1.5
### Patch Changes
- f78c234: Fix metro config for the RN starter
## 0.1.4
### Patch Changes

View File

@@ -5,7 +5,7 @@
"types": "src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.1.4",
"version": "0.1.5",
"bin": {
"create-jazz-app": "./dist/index.js"
},

View File

@@ -124,6 +124,8 @@ const { withNativeWind } = require("nativewind/metro");
const config = getDefaultConfig(__dirname);
config.resolver.unstable_enablePackageExports = true;
module.exports = withNativeWind(config, { input: "./src/global.css" });
`;
fs.writeFileSync(metroConfigPath, metroConfig);

View File

@@ -1,5 +1,19 @@
# jazz-react-native-auth-clerk
## 0.9.3
### Patch Changes
- Updated dependencies [7cd691f]
- jazz-react-native@0.9.3
## 0.9.2
### Patch Changes
- Updated dependencies [80fd3e9]
- jazz-react-native@0.9.2
## 0.9.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react-native-auth-clerk",
"version": "0.9.1",
"version": "0.9.3",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,23 @@
# jazz-browser
## 0.9.3
### Patch Changes
- 7cd691f: Fix auth when using custom KV implementation
- Updated dependencies [2be47d6]
- cojson-storage-rn-sqlite@0.8.51
## 0.9.2
### Patch Changes
- 80fd3e9: Add local persistence with "@op-engineering/op-sqlite".
Disabled by default, follow the upgrade guide to enable it.
https://jazz.tools/docs/react-native/upgrade/react-native-local-persistence
## 0.9.1
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react-native",
"version": "0.9.1",
"version": "0.9.3",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -29,6 +29,7 @@
"jazz-react-core": "workspace:*",
"cojson": "workspace:*",
"cojson-transport-ws": "workspace:*",
"cojson-storage-rn-sqlite": "workspace:*",
"jazz-tools": "workspace:*",
"react-native-quick-crypto": "1.0.0-beta.9"
},

View File

@@ -111,20 +111,22 @@ export class RNDemoAuth implements AuthMethod {
) {
let kvStore = store;
if (!kvStore) {
const kvStoreContext = KvStoreContext.getInstance();
const kvStoreContext = KvStoreContext.getInstance();
if (!kvStoreContext.isInitialized()) {
if (!kvStoreContext.isInitialized()) {
if (!kvStore) {
const { ExpoSecureStoreAdapter } = await import(
"../storage/expo-secure-store-adapter.js"
);
kvStoreContext.initialize(new ExpoSecureStoreAdapter());
} else {
kvStoreContext.initialize(kvStore);
}
kvStore = kvStoreContext.getStorage();
}
kvStore = kvStoreContext.getStorage();
await migrateExistingUsersKeys(kvStore);
for (const [name, credentials] of Object.entries(seedAccounts || {})) {

View File

@@ -1,3 +1,4 @@
import { SQLiteStorage } from "cojson-storage-rn-sqlite";
import {
Account,
AgentID,
@@ -47,7 +48,7 @@ export type ReactNativeContextOptions<Acc extends Account> = {
export type BaseReactNativeContextOptions = {
peer: `wss://${string}` | `ws://${string}`;
reconnectionTimeout?: number;
storage?: "indexedDB" | "singleTabOPFS";
storage?: "sqlite" | "disabled";
CryptoProvider?: typeof PureJSCrypto | typeof RNQuickCrypto;
};
@@ -74,18 +75,28 @@ export async function createJazzRNContext<Acc extends Account>(
const CryptoProvider = options.CryptoProvider || PureJSCrypto;
const peersToLoadFrom = [websocketPeer.peer];
if (options.storage === "sqlite") {
const storage = await SQLiteStorage.asPeer({
filename: "jazz-storage",
trace: false,
});
peersToLoadFrom.push(storage);
}
const context =
"auth" in options
? await createJazzContext({
AccountSchema: options.AccountSchema,
auth: options.auth,
crypto: await CryptoProvider.create(),
peersToLoadFrom: [websocketPeer.peer],
peersToLoadFrom,
sessionProvider: provideLockSession,
})
: await createJazzContext({
crypto: await CryptoProvider.create(),
peersToLoadFrom: [websocketPeer.peer],
peersToLoadFrom,
});
const node =

View File

@@ -18,6 +18,7 @@ export type JazzProviderProps<Acc extends Account = RegisteredAccount> = {
peer: `wss://${string}` | `ws://${string}`;
AccountSchema?: AccountClass<Acc>;
CryptoProvider?: BaseReactNativeContextOptions["CryptoProvider"];
storage?: BaseReactNativeContextOptions["storage"];
};
/** @category Context & Hooks */
@@ -27,6 +28,7 @@ export function JazzProvider<Acc extends Account = RegisteredAccount>({
peer,
AccountSchema = Account as unknown as AccountClass<Acc>,
CryptoProvider,
storage,
}: JazzProviderProps<Acc>) {
const [ctx, setCtx] = useState<JazzContextType<Acc> | undefined>();
@@ -60,12 +62,14 @@ export function JazzProvider<Acc extends Account = RegisteredAccount>({
? {
peer,
CryptoProvider,
storage,
}
: {
AccountSchema,
auth: auth,
peer,
CryptoProvider,
storage,
},
);

View File

@@ -4,21 +4,21 @@ import type { KvStore } from "./kv-store-context.js";
export class ExpoSecureStoreAdapter implements KvStore {
get(key: string): Promise<string | null> {
return SecureStore.getItemAsync(key, {
requireAuthentication: SecureStore.canUseBiometricAuthentication(),
requireAuthentication: false,
keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK,
});
}
async set(key: string, value: string): Promise<void> {
return SecureStore.setItemAsync(key, value, {
requireAuthentication: SecureStore.canUseBiometricAuthentication(),
requireAuthentication: false,
keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK,
});
}
async delete(key: string): Promise<void> {
return SecureStore.deleteItemAsync(key, {
requireAuthentication: SecureStore.canUseBiometricAuthentication(),
requireAuthentication: false,
keychainAccessible: SecureStore.AFTER_FIRST_UNLOCK,
});
}

View File

@@ -11,7 +11,7 @@ import type {
DepthsIn,
ID
} from 'jazz-tools';
import { Account, createCoValueObservable, subscribeToCoValue } from 'jazz-tools';
import { Account, subscribeToCoValue } from 'jazz-tools';
import { getContext, untrack } from 'svelte';
import Provider from './Provider.svelte';
@@ -44,8 +44,8 @@ export type RegisteredAccount = Register extends { Account: infer Acc }
? Acc
: Account;
export function useAccount(): { me: RegisteredAccount; logOut: () => void };
export function useAccount<D extends DepthsIn<RegisteredAccount>>(
export function useAccount(): { me: RegisteredAccount; logOut: () => void };
export function useAccount<D extends DepthsIn<RegisteredAccount>>(
depth: D
): { me: DeeplyLoaded<RegisteredAccount, D> | undefined; logOut: () => void };
/**

45
pnpm-lock.yaml generated
View File

@@ -107,6 +107,9 @@ importers:
'@azure/core-asynciterator-polyfill':
specifier: ^1.0.2
version: 1.0.2
'@op-engineering/op-sqlite':
specifier: ^11.2.12
version: 11.2.12(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)
'@react-native-community/netinfo':
specifier: ^11.4.1
version: 11.4.1(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.18)(react@18.3.1))
@@ -219,6 +222,9 @@ importers:
'@expo/vector-icons':
specifier: ^14.0.2
version: 14.0.4
'@op-engineering/op-sqlite':
specifier: ^11.2.12
version: 11.2.12(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)
'@react-native-community/netinfo':
specifier: ^11.4.1
version: 11.4.1(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.18)(react@18.3.1))
@@ -1468,6 +1474,22 @@ importers:
specifier: ^8.15.0
version: 8.41.0
packages/cojson-storage-rn-sqlite:
dependencies:
cojson:
specifier: workspace:*
version: link:../cojson
cojson-storage:
specifier: workspace:*
version: link:../cojson-storage
devDependencies:
'@op-engineering/op-sqlite':
specifier: ^11.2.12
version: 11.2.12(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)
typescript:
specifier: ~5.6.2
version: 5.6.3
packages/cojson-storage-sqlite:
dependencies:
better-sqlite3:
@@ -1737,6 +1759,9 @@ importers:
cojson:
specifier: workspace:*
version: link:../cojson
cojson-storage-rn-sqlite:
specifier: workspace:*
version: link:../cojson-storage-rn-sqlite
cojson-transport-ws:
specifier: workspace:*
version: link:../cojson-transport-ws
@@ -1991,6 +2016,9 @@ importers:
'@biomejs/biome':
specifier: 1.9.4
version: 1.9.4
'@playwright/test':
specifier: ^1.46.1
version: 1.49.1
'@types/react':
specifier: ^18.3.12
version: 18.3.18
@@ -2006,6 +2034,9 @@ importers:
globals:
specifier: ^15.11.0
version: 15.14.0
is-ci:
specifier: ^3.0.1
version: 3.0.1
postcss:
specifier: ^8.4.27
version: 8.4.49
@@ -2082,6 +2113,9 @@ importers:
'@azure/core-asynciterator-polyfill':
specifier: ^1.0.2
version: 1.0.2
'@op-engineering/op-sqlite':
specifier: ^11.2.12
version: 11.2.12(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)
'@react-native-community/netinfo':
specifier: ^11.4.1
version: 11.4.1(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.18)(react@18.3.1))
@@ -3845,6 +3879,12 @@ packages:
resolution: {integrity: sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
'@op-engineering/op-sqlite@11.2.12':
resolution: {integrity: sha512-X3qv/H8oCTkk0MyoaMa7Et+0Z8Rkbe8PTBAIBLwwocIc1b84T1Q6wn9DRrS346p2wOgP8j7EYLFqtm0+1tCtkA==}
peerDependencies:
react: 18.3.1
react-native: '*'
'@opentelemetry/api@1.9.0':
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
@@ -13486,6 +13526,11 @@ snapshots:
dependencies:
semver: 7.6.3
'@op-engineering/op-sqlite@11.2.12(react-native@0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.18)(react@18.3.1))(react@18.3.1)':
dependencies:
react: 18.3.1
react-native: 0.76.5(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.18)(react@18.3.1)
'@opentelemetry/api@1.9.0': {}
'@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0)':

View File

@@ -18,10 +18,12 @@
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@playwright/test": "^1.46.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"typescript": "~5.6.2",
"vite": "^5.4.10",
"postcss": "^8.4.27",

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,46 @@
import { defineConfig, devices } from "@playwright/test";
import isCI from "is-ci";
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: isCI,
/* Retry on CI only */
retries: isCI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: isCI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://localhost:5173/",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
permissions: ["clipboard-read", "clipboard-write"],
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
/* Run your local dev server before starting the tests */
webServer: [
{
command: "pnpm preview --port 5173",
url: "http://localhost:5173/",
reuseExistingServer: !isCI,
},
],
});

View File

@@ -13,6 +13,7 @@ function JazzAndAuth({ children }: { children: React.ReactNode }) {
<JazzProvider
auth={auth}
peer="wss://cloud.jazz.tools/?key=react-demo-auth-tailwind@garden.co"
AccountSchema={JazzAccount}
>
{children}
</JazzProvider>

View File

@@ -0,0 +1,40 @@
import { Locator, Page, expect } from "@playwright/test";
export class LoginPage {
readonly page: Page;
readonly usernameInput: Locator;
readonly signupButton: Locator;
constructor(page: Page) {
this.page = page;
this.usernameInput = page.getByRole("textbox");
this.signupButton = page.getByRole("button", {
name: "Sign up",
});
}
async goto() {
this.page.goto("/");
}
async fillUsername(value: string) {
await this.usernameInput.clear();
await this.usernameInput.fill(value);
}
async loginAs(value: string) {
await this.page
.getByRole("button", {
name: value,
})
.click();
}
async signup() {
await this.signupButton.click();
}
async expectLoaded() {
await expect(this.signupButton).toBeVisible();
}
}

View File

@@ -0,0 +1,15 @@
import { expect, test } from "@playwright/test";
import { LoginPage } from "./pages/LoginPage";
test("home page loads", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.fillUsername("Alice");
await loginPage.signup();
await expect(page.getByText("Welcome!")).toBeVisible();
await page.getByLabel("First name").fill("Bob");
await expect(page.getByText("Welcome, Bob!")).toBeVisible();
});

View File

@@ -12,6 +12,7 @@
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@op-engineering/op-sqlite": "^11.2.12",
"@react-native-community/netinfo": "^11.4.1",
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",