chore: react-native scaffolding (wip)
This commit is contained in:
38
examples/chat-rn/.gitignore
vendored
Normal file
38
examples/chat-rn/.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# Expo
|
||||
.expo/
|
||||
dist/
|
||||
web-build/
|
||||
|
||||
# Native
|
||||
*.orig.*
|
||||
*.jks
|
||||
*.p8
|
||||
*.p12
|
||||
*.key
|
||||
*.mobileprovision
|
||||
|
||||
# Metro
|
||||
.metro-health-check*
|
||||
|
||||
# debug
|
||||
npm-debug.*
|
||||
yarn-debug.*
|
||||
yarn-error.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
|
||||
ios
|
||||
android
|
||||
20
examples/chat-rn/App.tsx
Normal file
20
examples/chat-rn/App.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Open up App.tsx to start working on your app!</Text>
|
||||
<StatusBar style="auto" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
});
|
||||
29
examples/chat-rn/app.json
Normal file
29
examples/chat-rn/app.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "chat-rn",
|
||||
"slug": "chat-rn",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"splash": {
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "com.jazz.chatrn"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"package": "com.jazz.chatrn"
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
examples/chat-rn/assets/adaptive-icon.png
Normal file
BIN
examples/chat-rn/assets/adaptive-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
examples/chat-rn/assets/favicon.png
Normal file
BIN
examples/chat-rn/assets/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
examples/chat-rn/assets/icon.png
Normal file
BIN
examples/chat-rn/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
examples/chat-rn/assets/splash.png
Normal file
BIN
examples/chat-rn/assets/splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
6
examples/chat-rn/babel.config.js
Normal file
6
examples/chat-rn/babel.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = function(api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: ['babel-preset-expo'],
|
||||
};
|
||||
};
|
||||
8
examples/chat-rn/index.js
Normal file
8
examples/chat-rn/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { registerRootComponent } from "expo";
|
||||
|
||||
import App from "./App";
|
||||
|
||||
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
|
||||
// It also ensures that whether you load the app in the Expo client or in a native build,
|
||||
// the environment is set up appropriately
|
||||
registerRootComponent(App);
|
||||
27
examples/chat-rn/metro.config.js
Normal file
27
examples/chat-rn/metro.config.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// Learn more https://docs.expo.dev/guides/monorepos
|
||||
const { getDefaultConfig } = require("expo/metro-config");
|
||||
const { FileStore } = require("metro-cache");
|
||||
const path = require("path");
|
||||
|
||||
const projectRoot = __dirname;
|
||||
const workspaceRoot = path.resolve(projectRoot, "../..");
|
||||
|
||||
const config = getDefaultConfig(projectRoot);
|
||||
|
||||
// Since we are using pnpm, we have to setup the monorepo manually for Metro
|
||||
// #1 - Watch all files in the monorepo
|
||||
config.watchFolders = [workspaceRoot];
|
||||
// #2 - Try resolving with project modules first, then workspace modules
|
||||
config.resolver.nodeModulesPaths = [
|
||||
path.resolve(projectRoot, "node_modules"),
|
||||
path.resolve(workspaceRoot, "node_modules"),
|
||||
];
|
||||
|
||||
// Use turborepo to restore the cache when possible
|
||||
config.cacheStores = [
|
||||
new FileStore({
|
||||
root: path.join(projectRoot, "node_modules", ".cache", "metro"),
|
||||
}),
|
||||
];
|
||||
|
||||
module.exports = config;
|
||||
24
examples/chat-rn/package.json
Normal file
24
examples/chat-rn/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "chat-rn",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "expo start",
|
||||
"android": "expo run:android",
|
||||
"ios": "expo run:ios",
|
||||
"web": "expo start --web"
|
||||
},
|
||||
"dependencies": {
|
||||
"expo": "~51.0.28",
|
||||
"expo-status-bar": "~1.12.1",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.75",
|
||||
"jazz-react-native": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.0",
|
||||
"@types/react": "~18.2.45",
|
||||
"typescript": "^5.1.3"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
6
examples/chat-rn/tsconfig.json
Normal file
6
examples/chat-rn/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "expo/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
11
package.json
11
package.json
@@ -32,5 +32,14 @@
|
||||
"release": "pnpm changeset publish && git push --follow-tags"
|
||||
},
|
||||
"lint-staged": {},
|
||||
"version": "0.0.0"
|
||||
"version": "0.0.0",
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
"@babel/*",
|
||||
"expo-modules-*",
|
||||
"typescript"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
24
packages/jazz-react-native/.eslintrc.cjs
Normal file
24
packages/jazz-react-native/.eslintrc.cjs
Normal file
@@ -0,0 +1,24 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:require-extensions/recommended",
|
||||
"prettier"
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["@typescript-eslint", "require-extensions"],
|
||||
parserOptions: {
|
||||
project: "./tsconfig.json",
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
ignorePatterns: [".eslint.cjs"],
|
||||
root: true,
|
||||
rules: {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
},
|
||||
}
|
||||
171
packages/jazz-react-native/.gitignore
vendored
Normal file
171
packages/jazz-react-native/.gitignore
vendored
Normal 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
|
||||
2
packages/jazz-react-native/.npmignore
Normal file
2
packages/jazz-react-native/.npmignore
Normal file
@@ -0,0 +1,2 @@
|
||||
coverage
|
||||
node_modules
|
||||
9
packages/jazz-react-native/.prettierrc.js
Normal file
9
packages/jazz-react-native/.prettierrc.js
Normal file
@@ -0,0 +1,9 @@
|
||||
/** @type {import("prettier").Config} */
|
||||
const config = {
|
||||
trailingComma: "all",
|
||||
tabWidth: 4,
|
||||
semi: true,
|
||||
singleQuote: false,
|
||||
};
|
||||
|
||||
export default config;
|
||||
907
packages/jazz-react-native/CHANGELOG.md
Normal file
907
packages/jazz-react-native/CHANGELOG.md
Normal file
@@ -0,0 +1,907 @@
|
||||
# jazz-browser
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- bcec3be: Implement new top-level context creation and auth method API
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c2b62a0: Make anonymous auth work better
|
||||
- 1a979b6: Implement guest auth without account
|
||||
- Updated dependencies [6a147c2]
|
||||
- Updated dependencies [ad40b88]
|
||||
- Updated dependencies [23369dc]
|
||||
- Updated dependencies [c2b62a0]
|
||||
- Updated dependencies [1a979b6]
|
||||
- Updated dependencies [bcec3be]
|
||||
- cojson@0.8.0
|
||||
- jazz-tools@0.8.0
|
||||
- cojson-storage-indexeddb@0.8.0
|
||||
- cojson-transport-ws@0.8.0
|
||||
|
||||
## 0.7.35-guest-auth.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.35-guest-auth.6
|
||||
|
||||
## 0.7.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [49a8b54]
|
||||
- Updated dependencies [35bbcd9]
|
||||
- Updated dependencies [6f80282]
|
||||
- Updated dependencies [35bbcd9]
|
||||
- Updated dependencies [f350e90]
|
||||
- jazz-tools@0.7.35
|
||||
- cojson@0.7.35
|
||||
- cojson-storage-indexeddb@0.7.35
|
||||
- cojson-transport-ws@0.7.35
|
||||
|
||||
## 0.7.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5d91f9f]
|
||||
- Updated dependencies [5094e6d]
|
||||
- Updated dependencies [b09589b]
|
||||
- Updated dependencies [2c3a40c]
|
||||
- Updated dependencies [406ab9b]
|
||||
- Updated dependencies [4e16575]
|
||||
- Updated dependencies [ea882ab]
|
||||
- cojson@0.7.34
|
||||
- cojson-transport-ws@0.7.34
|
||||
- cojson-storage-indexeddb@0.7.34
|
||||
- jazz-tools@0.7.34
|
||||
|
||||
## 0.7.34-neverthrow.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.34-neverthrow.8
|
||||
- cojson-storage-indexeddb@0.7.34-neverthrow.8
|
||||
- cojson-transport-ws@0.7.34-neverthrow.8
|
||||
- jazz-tools@0.7.34-neverthrow.8
|
||||
|
||||
## 0.7.34-neverthrow.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.34-neverthrow.7
|
||||
- cojson-storage-indexeddb@0.7.34-neverthrow.7
|
||||
- cojson-transport-ws@0.7.34-neverthrow.7
|
||||
- jazz-tools@0.7.34-neverthrow.7
|
||||
|
||||
## 0.7.34-neverthrow.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.34-neverthrow.4
|
||||
- cojson-storage-indexeddb@0.7.34-neverthrow.4
|
||||
- cojson-transport-ws@0.7.34-neverthrow.4
|
||||
- jazz-tools@0.7.34-neverthrow.4
|
||||
|
||||
## 0.7.34-neverthrow.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.34-neverthrow.3
|
||||
- cojson-storage-indexeddb@0.7.34-neverthrow.3
|
||||
- cojson-transport-ws@0.7.34-neverthrow.3
|
||||
- jazz-tools@0.7.34-neverthrow.3
|
||||
|
||||
## 0.7.34-neverthrow.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.34-neverthrow.2
|
||||
|
||||
## 0.7.34-neverthrow.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.34-neverthrow.1
|
||||
- cojson-storage-indexeddb@0.7.34-neverthrow.1
|
||||
- cojson-transport-ws@0.7.34-neverthrow.1
|
||||
- jazz-tools@0.7.34-neverthrow.1
|
||||
|
||||
## 0.7.34-neverthrow.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.34-neverthrow.0
|
||||
- cojson-storage-indexeddb@0.7.34-neverthrow.0
|
||||
- cojson-transport-ws@0.7.34-neverthrow.0
|
||||
- jazz-tools@0.7.34-neverthrow.0
|
||||
|
||||
## 0.7.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [fdde8db]
|
||||
- Updated dependencies [b297c93]
|
||||
- Updated dependencies [07fe2b9]
|
||||
- Updated dependencies [3bf5127]
|
||||
- Updated dependencies [a8b74ff]
|
||||
- Updated dependencies [db53161]
|
||||
- cojson-transport-ws@0.7.33
|
||||
- cojson@0.7.33
|
||||
- cojson-storage-indexeddb@0.7.33
|
||||
- jazz-tools@0.7.33
|
||||
|
||||
## 0.7.33-hotfixes.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.33-hotfixes.5
|
||||
- cojson-storage-indexeddb@0.7.33-hotfixes.5
|
||||
- cojson-transport-ws@0.7.33-hotfixes.5
|
||||
- jazz-tools@0.7.33-hotfixes.5
|
||||
|
||||
## 0.7.33-hotfixes.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.33-hotfixes.4
|
||||
- cojson-storage-indexeddb@0.7.33-hotfixes.4
|
||||
- cojson-transport-ws@0.7.33-hotfixes.4
|
||||
- jazz-tools@0.7.33-hotfixes.4
|
||||
|
||||
## 0.7.33-hotfixes.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.7.33-hotfixes.3
|
||||
- cojson-transport-ws@0.7.33-hotfixes.3
|
||||
- cojson@0.7.33-hotfixes.3
|
||||
- jazz-tools@0.7.33-hotfixes.3
|
||||
|
||||
## 0.7.33-hotfixes.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.33-hotfixes.2
|
||||
|
||||
## 0.7.33-hotfixes.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.33-hotfixes.1
|
||||
|
||||
## 0.7.33-hotfixes.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.33-hotfixes.0
|
||||
- cojson-storage-indexeddb@0.7.33-hotfixes.0
|
||||
- cojson-transport-ws@0.7.33-hotfixes.0
|
||||
- jazz-tools@0.7.33-hotfixes.0
|
||||
|
||||
## 0.7.32
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.32
|
||||
|
||||
## 0.7.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.31
|
||||
- cojson@0.7.31
|
||||
- cojson-storage-indexeddb@0.7.31
|
||||
- jazz-tools@0.7.31
|
||||
|
||||
## 0.7.30
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.30
|
||||
|
||||
## 0.7.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.29
|
||||
- cojson-storage-indexeddb@0.7.29
|
||||
- cojson-transport-ws@0.7.29
|
||||
- jazz-tools@0.7.29
|
||||
|
||||
## 0.7.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.28
|
||||
- cojson-storage-indexeddb@0.7.28
|
||||
- cojson-transport-ws@0.7.28
|
||||
- jazz-tools@0.7.28
|
||||
|
||||
## 0.7.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.27
|
||||
|
||||
## 0.7.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Remove Effect from jazz/cojson internals
|
||||
- Updated dependencies
|
||||
- cojson@0.7.26
|
||||
- cojson-storage-indexeddb@0.7.26
|
||||
- cojson-transport-ws@0.7.26
|
||||
- jazz-tools@0.7.26
|
||||
|
||||
## 0.7.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.25
|
||||
|
||||
## 0.7.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.24
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.23
|
||||
- jazz-tools@0.7.23
|
||||
- cojson-storage-indexeddb@0.7.23
|
||||
- cojson-transport-ws@0.7.23
|
||||
|
||||
## 0.7.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-transport-ws@0.7.22
|
||||
|
||||
## 0.7.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.21
|
||||
|
||||
## 0.7.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.20
|
||||
|
||||
## 0.7.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.19
|
||||
|
||||
## 0.7.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.18
|
||||
- cojson-storage-indexeddb@0.7.18
|
||||
- cojson-transport-ws@0.7.18
|
||||
- jazz-tools@0.7.18
|
||||
|
||||
## 0.7.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.17
|
||||
- cojson-storage-indexeddb@0.7.17
|
||||
- cojson-transport-ws@0.7.17
|
||||
- jazz-tools@0.7.17
|
||||
|
||||
## 0.7.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.16
|
||||
|
||||
## 0.7.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.14
|
||||
- jazz-tools@0.7.14
|
||||
- cojson-storage-indexeddb@0.7.14
|
||||
- cojson-transport-ws@0.7.14
|
||||
|
||||
## 0.7.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.13
|
||||
|
||||
## 0.7.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.12
|
||||
|
||||
## 0.7.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.11
|
||||
- cojson-storage-indexeddb@0.7.11
|
||||
- jazz-tools@0.7.11
|
||||
|
||||
## 0.7.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.10
|
||||
- cojson-storage-indexeddb@0.7.10
|
||||
- jazz-tools@0.7.10
|
||||
|
||||
## 0.7.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.9
|
||||
- cojson-storage-indexeddb@0.7.9
|
||||
- jazz-tools@0.7.9
|
||||
|
||||
## 0.7.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.8
|
||||
|
||||
## 0.7.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.6
|
||||
|
||||
## 0.7.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Ability to add seed accounts to DemoAuth
|
||||
|
||||
## 0.7.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.3
|
||||
|
||||
## 0.7.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.1
|
||||
|
||||
## 0.7.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- e299c3e: New simplified API
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1a35307: WIP working-ish version of LSM storage
|
||||
- 59c18c3: CoMap fix
|
||||
- 8636319: Implement deep loading, simplify API
|
||||
- d8fe2b1: Expose experimental OPFS storage
|
||||
- c4151fc: Support stricter TS lint rules
|
||||
- daee49c: Add missing @scure/bip39 dep
|
||||
- 952982e: Consistent proxy based API
|
||||
- d2e03ff: Fix variance of ID.\_\_type
|
||||
- 354bdcd: Even friendlier for subclassing CoMap
|
||||
- 60d5ca2: Clean up exports
|
||||
- 69ac514: Use effect schema much less
|
||||
- f0f6f1b: Clean up API more & re-add jazz-nodejs
|
||||
- 1a44f87: Refactoring
|
||||
- 627d895: Get rid of Co namespace
|
||||
- 85d2b62: More subclass-friendly types in CoMap
|
||||
- Updated dependencies [8636319]
|
||||
- Updated dependencies [1a35307]
|
||||
- Updated dependencies [8636319]
|
||||
- Updated dependencies [1a35307]
|
||||
- Updated dependencies [96c494f]
|
||||
- Updated dependencies [59c18c3]
|
||||
- Updated dependencies [19f52b7]
|
||||
- Updated dependencies [8636319]
|
||||
- Updated dependencies [d8fe2b1]
|
||||
- Updated dependencies [19004b4]
|
||||
- Updated dependencies [a78f168]
|
||||
- Updated dependencies [1200aae]
|
||||
- Updated dependencies [52675c9]
|
||||
- Updated dependencies [129e2c1]
|
||||
- Updated dependencies [1cfa279]
|
||||
- Updated dependencies [704af7d]
|
||||
- Updated dependencies [1a35307]
|
||||
- Updated dependencies [460478f]
|
||||
- Updated dependencies [6b0418f]
|
||||
- Updated dependencies [e299c3e]
|
||||
- Updated dependencies [ed5643a]
|
||||
- Updated dependencies [bde684f]
|
||||
- Updated dependencies [bf0f8ec]
|
||||
- Updated dependencies [c4151fc]
|
||||
- Updated dependencies [63374cc]
|
||||
- Updated dependencies [8636319]
|
||||
- Updated dependencies [01ac646]
|
||||
- Updated dependencies [a5e68a4]
|
||||
- Updated dependencies [952982e]
|
||||
- Updated dependencies [1a35307]
|
||||
- Updated dependencies [5fa277c]
|
||||
- Updated dependencies [60d5ca2]
|
||||
- Updated dependencies [21771c4]
|
||||
- Updated dependencies [77c2b56]
|
||||
- Updated dependencies [63374cc]
|
||||
- Updated dependencies [d2e03ff]
|
||||
- Updated dependencies [354bdcd]
|
||||
- Updated dependencies [60d5ca2]
|
||||
- Updated dependencies [69ac514]
|
||||
- Updated dependencies [f8a5c46]
|
||||
- Updated dependencies [f0f6f1b]
|
||||
- Updated dependencies [e5eed5b]
|
||||
- Updated dependencies [1a44f87]
|
||||
- Updated dependencies [627d895]
|
||||
- Updated dependencies [1200aae]
|
||||
- Updated dependencies [63374cc]
|
||||
- Updated dependencies [ece35b3]
|
||||
- Updated dependencies [38d4410]
|
||||
- Updated dependencies [85d2b62]
|
||||
- Updated dependencies [fd86c11]
|
||||
- Updated dependencies [52675c9]
|
||||
- jazz-tools@0.7.0
|
||||
- cojson@0.7.0
|
||||
- cojson-storage-indexeddb@0.7.0
|
||||
|
||||
## 0.7.0-alpha.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.42
|
||||
- cojson@0.7.0-alpha.42
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.42
|
||||
|
||||
## 0.7.0-alpha.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-tools@0.7.0-alpha.41
|
||||
|
||||
## 0.7.0-alpha.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson@0.7.0-alpha.39
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.39
|
||||
- jazz-tools@0.7.0-alpha.39
|
||||
|
||||
## 0.7.0-alpha.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Implement deep loading, simplify API
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.38
|
||||
- cojson@0.7.0-alpha.38
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.38
|
||||
|
||||
## 0.7.0-alpha.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Expose experimental OPFS storage
|
||||
- Updated dependencies
|
||||
- cojson@0.7.0-alpha.37
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.37
|
||||
- jazz-tools@0.7.0-alpha.37
|
||||
|
||||
## 0.7.0-alpha.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1a35307: WIP working-ish version of LSM storage
|
||||
- Updated dependencies [1a35307]
|
||||
- Updated dependencies [1a35307]
|
||||
- Updated dependencies [1a35307]
|
||||
- Updated dependencies [6b0418f]
|
||||
- Updated dependencies [1a35307]
|
||||
- cojson@0.7.0-alpha.36
|
||||
- jazz-tools@0.7.0-alpha.36
|
||||
|
||||
## 0.7.0-alpha.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- cojson@0.7.0-alpha.35
|
||||
- jazz-tools@0.7.0-alpha.35
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.35
|
||||
|
||||
## 0.7.0-alpha.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.34
|
||||
|
||||
## 0.7.0-alpha.32
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Clean up exports
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.32
|
||||
|
||||
## 0.7.0-alpha.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.31
|
||||
|
||||
## 0.7.0-alpha.30
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.30
|
||||
|
||||
## 0.7.0-alpha.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.29
|
||||
- jazz-tools@0.7.0-alpha.29
|
||||
- cojson@0.7.0-alpha.29
|
||||
|
||||
## 0.7.0-alpha.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.28
|
||||
- cojson@0.7.0-alpha.28
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.28
|
||||
|
||||
## 0.7.0-alpha.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.27
|
||||
- cojson@0.7.0-alpha.27
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.27
|
||||
|
||||
## 0.7.0-alpha.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.26
|
||||
|
||||
## 0.7.0-alpha.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.25
|
||||
|
||||
## 0.7.0-alpha.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.24
|
||||
- cojson@0.7.0-alpha.24
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.24
|
||||
|
||||
## 0.7.0-alpha.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.23
|
||||
|
||||
## 0.7.0-alpha.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.22
|
||||
|
||||
## 0.7.0-alpha.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.21
|
||||
|
||||
## 0.7.0-alpha.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.20
|
||||
|
||||
## 0.7.0-alpha.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.19
|
||||
|
||||
## 0.7.0-alpha.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Add missing @scure/bip39 dep
|
||||
|
||||
## 0.7.0-alpha.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.17
|
||||
|
||||
## 0.7.0-alpha.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.16
|
||||
|
||||
## 0.7.0-alpha.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.15
|
||||
|
||||
## 0.7.0-alpha.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.14
|
||||
|
||||
## 0.7.0-alpha.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.13
|
||||
|
||||
## 0.7.0-alpha.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix variance of ID.\_\_type
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.12
|
||||
|
||||
## 0.7.0-alpha.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Support stricter TS lint rules
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.11
|
||||
- jazz-tools@0.7.0-alpha.11
|
||||
- cojson@0.7.0-alpha.11
|
||||
|
||||
## 0.7.0-alpha.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Clean up API more & re-add jazz-nodejs
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.7.0-alpha.10
|
||||
- jazz-tools@0.7.0-alpha.10
|
||||
- cojson@0.7.0-alpha.10
|
||||
|
||||
## 0.7.0-alpha.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Even friendlier for subclassing CoMap
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.9
|
||||
|
||||
## 0.7.0-alpha.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- More subclass-friendly types in CoMap
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.8
|
||||
|
||||
## 0.7.0-alpha.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Consistent proxy based API
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.6.4-alpha.4
|
||||
- jazz-tools@0.7.0-alpha.7
|
||||
- cojson@0.7.0-alpha.7
|
||||
|
||||
## 0.7.0-alpha.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- CoMap fix
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.6
|
||||
|
||||
## 0.7.0-alpha.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Refactoring
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.6.4-alpha.3
|
||||
- jazz-tools@0.7.0-alpha.5
|
||||
- cojson@0.7.0-alpha.5
|
||||
|
||||
## 0.7.0-alpha.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.4
|
||||
|
||||
## 0.7.0-alpha.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.3
|
||||
|
||||
## 0.7.0-alpha.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Get rid of Co namespace
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.6.4-alpha.2
|
||||
- jazz-tools@0.7.0-alpha.2
|
||||
|
||||
## 0.7.0-alpha.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Use effect schema much less
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.6.4-alpha.1
|
||||
- jazz-tools@0.7.0-alpha.1
|
||||
- cojson@0.7.0-alpha.1
|
||||
|
||||
## 0.7.0-alpha.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- New simplified API
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- jazz-tools@0.7.0-alpha.0
|
||||
- cojson@0.7.0-alpha.0
|
||||
- cojson-storage-indexeddb@0.6.4-alpha.0
|
||||
|
||||
## 0.6.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix migration changes being lost on loaded account
|
||||
- Updated dependencies
|
||||
- cojson@0.6.6
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Fix loading of accounts
|
||||
- Updated dependencies
|
||||
- cojson@0.6.5
|
||||
- jazz-autosub@0.6.1
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- IndexedDB & timer perf improvements
|
||||
- Updated dependencies
|
||||
- cojson@0.6.4
|
||||
- cojson-storage-indexeddb@0.6.1
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Make addMember and removeMember take loaded Accounts instead of just IDs
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- cojson-storage-indexeddb@0.6.0
|
||||
- jazz-autosub@0.6.0
|
||||
- cojson@0.6.0
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Allow account migrations to be async
|
||||
- Updated dependencies
|
||||
- cojson@0.5.2
|
||||
|
||||
## 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-storage-indexeddb@0.5.0
|
||||
- jazz-autosub@0.5.0
|
||||
- cojson@0.5.0
|
||||
19
packages/jazz-react-native/LICENSE.txt
Normal file
19
packages/jazz-react-native/LICENSE.txt
Normal 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.
|
||||
10
packages/jazz-react-native/README.md
Normal file
10
packages/jazz-react-native/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# `jazz-browser`
|
||||
|
||||
These are browser bindings for Jazz (see [jazz.tools](https://jazz.tools)), a framework for distributed state.
|
||||
|
||||
Use this only if you want to write Jazz apps using plain JavaScript,
|
||||
or to build your framework bindings for Jazz.
|
||||
|
||||
## Higher-level framework bindings:
|
||||
|
||||
- `jazz-react` - React bindings for Jazz
|
||||
27
packages/jazz-react-native/package.json
Normal file
27
packages/jazz-react-native/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "jazz-react-native",
|
||||
"version": "0.8.0",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scure/bip39": "^1.3.0",
|
||||
"cojson": "workspace:0.8.0",
|
||||
"cojson-storage-indexeddb": "workspace:0.8.0",
|
||||
"cojson-transport-ws": "workspace:0.8.0",
|
||||
"jazz-tools": "workspace:0.8.0",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext ts,tsx",
|
||||
"format": "prettier --write './src/**/*.{ts,tsx}'",
|
||||
"build": "npm run lint && rm -rf ./dist && tsc --sourceMap --outDir dist",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx}": "eslint --fix",
|
||||
"*.{js,jsx,mdx,json}": "prettier --write"
|
||||
},
|
||||
"gitHead": "33c27053293b4801b968c61d5c4c989f93a67d13"
|
||||
}
|
||||
348
packages/jazz-react-native/src/OPFSFilesystem.ts
Normal file
348
packages/jazz-react-native/src/OPFSFilesystem.ts
Normal file
@@ -0,0 +1,348 @@
|
||||
import { BlockFilename, FileSystem, WalFilename, CryptoProvider } from "cojson";
|
||||
|
||||
export class OPFSFilesystem
|
||||
implements
|
||||
FileSystem<
|
||||
{ id: number; filename: string },
|
||||
{ id: number; filename: string }
|
||||
>
|
||||
{
|
||||
opfsWorker: Worker;
|
||||
callbacks: Map<number, (event: MessageEvent) => void> = new Map();
|
||||
nextRequestId = 0;
|
||||
|
||||
constructor(public crypto: CryptoProvider) {
|
||||
this.opfsWorker = new Worker(
|
||||
URL.createObjectURL(
|
||||
new Blob([opfsWorkerJSSrc], { type: "text/javascript" }),
|
||||
),
|
||||
);
|
||||
this.opfsWorker.onmessage = (event) => {
|
||||
// console.log("Received from OPFS worker", event.data);
|
||||
const handler = this.callbacks.get(event.data.requestId);
|
||||
if (handler) {
|
||||
handler(event);
|
||||
this.callbacks.delete(event.data.requestId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
listFiles(): Promise<string[]> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("listFiles" + requestId + "_listFiles");
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
performance.mark("listFilesEnd" + requestId + "_listFiles");
|
||||
performance.measure(
|
||||
"listFiles" + requestId + "_listFiles",
|
||||
"listFiles" + requestId + "_listFiles",
|
||||
"listFilesEnd" + requestId + "_listFiles",
|
||||
);
|
||||
resolve(event.data.fileNames);
|
||||
});
|
||||
this.opfsWorker.postMessage({ type: "listFiles", requestId });
|
||||
});
|
||||
}
|
||||
|
||||
openToRead(
|
||||
filename: string,
|
||||
): Promise<{ handle: { id: number; filename: string }; size: number }> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("openToRead" + "_" + filename);
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
resolve({
|
||||
handle: { id: event.data.handle, filename },
|
||||
size: event.data.size,
|
||||
});
|
||||
performance.mark("openToReadEnd" + "_" + filename);
|
||||
performance.measure(
|
||||
"openToRead" + "_" + filename,
|
||||
"openToRead" + "_" + filename,
|
||||
"openToReadEnd" + "_" + filename,
|
||||
);
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "openToRead",
|
||||
filename,
|
||||
requestId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
createFile(filename: string): Promise<{ id: number; filename: string }> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("createFile" + "_" + filename);
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
performance.mark("createFileEnd" + "_" + filename);
|
||||
performance.measure(
|
||||
"createFile" + "_" + filename,
|
||||
"createFile" + "_" + filename,
|
||||
"createFileEnd" + "_" + filename,
|
||||
);
|
||||
resolve({ id: event.data.handle, filename });
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "createFile",
|
||||
filename,
|
||||
requestId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
openToWrite(filename: string): Promise<{ id: number; filename: string }> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("openToWrite" + "_" + filename);
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
performance.mark("openToWriteEnd" + "_" + filename);
|
||||
performance.measure(
|
||||
"openToWrite" + "_" + filename,
|
||||
"openToWrite" + "_" + filename,
|
||||
"openToWriteEnd" + "_" + filename,
|
||||
);
|
||||
resolve({ id: event.data.handle, filename });
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "openToWrite",
|
||||
filename,
|
||||
requestId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
append(
|
||||
handle: { id: number; filename: string },
|
||||
data: Uint8Array,
|
||||
): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("append" + "_" + handle.filename);
|
||||
this.callbacks.set(requestId, (_) => {
|
||||
performance.mark("appendEnd" + "_" + handle.filename);
|
||||
performance.measure(
|
||||
"append" + "_" + handle.filename,
|
||||
"append" + "_" + handle.filename,
|
||||
"appendEnd" + "_" + handle.filename,
|
||||
);
|
||||
resolve(undefined);
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "append",
|
||||
handle: handle.id,
|
||||
data,
|
||||
requestId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
read(
|
||||
handle: { id: number; filename: string },
|
||||
offset: number,
|
||||
length: number,
|
||||
): Promise<Uint8Array> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("read" + "_" + handle.filename);
|
||||
this.callbacks.set(requestId, (event) => {
|
||||
performance.mark("readEnd" + "_" + handle.filename);
|
||||
performance.measure(
|
||||
"read" + "_" + handle.filename,
|
||||
"read" + "_" + handle.filename,
|
||||
"readEnd" + "_" + handle.filename,
|
||||
);
|
||||
resolve(event.data.data);
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "read",
|
||||
handle: handle.id,
|
||||
offset,
|
||||
length,
|
||||
requestId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
close(handle: { id: number; filename: string }): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("close" + "_" + handle.filename);
|
||||
this.callbacks.set(requestId, (_) => {
|
||||
performance.mark("closeEnd" + "_" + handle.filename);
|
||||
performance.measure(
|
||||
"close" + "_" + handle.filename,
|
||||
"close" + "_" + handle.filename,
|
||||
"closeEnd" + "_" + handle.filename,
|
||||
);
|
||||
resolve(undefined);
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "close",
|
||||
handle: handle.id,
|
||||
requestId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
closeAndRename(
|
||||
handle: { id: number; filename: string },
|
||||
filename: BlockFilename,
|
||||
): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("closeAndRename" + "_" + handle.filename);
|
||||
this.callbacks.set(requestId, () => {
|
||||
performance.mark("closeAndRenameEnd" + "_" + handle.filename);
|
||||
performance.measure(
|
||||
"closeAndRename" + "_" + handle.filename,
|
||||
"closeAndRename" + "_" + handle.filename,
|
||||
"closeAndRenameEnd" + "_" + handle.filename,
|
||||
);
|
||||
resolve(undefined);
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "closeAndRename",
|
||||
handle: handle.id,
|
||||
filename,
|
||||
requestId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeFile(filename: BlockFilename | WalFilename): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const requestId = this.nextRequestId++;
|
||||
performance.mark("removeFile" + "_" + filename);
|
||||
this.callbacks.set(requestId, () => {
|
||||
performance.mark("removeFileEnd" + "_" + filename);
|
||||
performance.measure(
|
||||
"removeFile" + "_" + filename,
|
||||
"removeFile" + "_" + filename,
|
||||
"removeFileEnd" + "_" + filename,
|
||||
);
|
||||
resolve(undefined);
|
||||
});
|
||||
this.opfsWorker.postMessage({
|
||||
type: "removeFile",
|
||||
filename,
|
||||
requestId,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const opfsWorkerJSSrc = `
|
||||
|
||||
let rootDirHandle;
|
||||
const handlesByRequest = new Map();
|
||||
const handlesByFilename = new Map();
|
||||
const filenamesForHandles = new Map();
|
||||
|
||||
onmessage = async function handleEvent(event) {
|
||||
rootDirHandle = rootDirHandle || await navigator.storage.getDirectory();
|
||||
// console.log("Received in OPFS worker", {...event.data, data: event.data.data ? "some data of length " + event.data.data.length : undefined});
|
||||
if (event.data.type === "listFiles") {
|
||||
const fileNames = [];
|
||||
for await (const entry of rootDirHandle.values()) {
|
||||
if (entry.kind === "file") {
|
||||
fileNames.push(entry.name);
|
||||
}
|
||||
}
|
||||
postMessage({requestId: event.data.requestId, fileNames});
|
||||
} else if (event.data.type === "openToRead" || event.data.type === "openToWrite") {
|
||||
let syncHandle;
|
||||
const existingHandle = handlesByFilename.get(event.data.filename);
|
||||
if (existingHandle) {
|
||||
throw new Error("Handle already exists for file: " + event.data.filename);
|
||||
} else {
|
||||
const handle = await rootDirHandle.getFileHandle(event.data.filename);
|
||||
try {
|
||||
syncHandle = await handle.createSyncAccessHandle();
|
||||
} catch (e) {
|
||||
throw new Error("Couldn't open file for reading: " + event.data.filename, {cause: e});
|
||||
}
|
||||
}
|
||||
handlesByRequest.set(event.data.requestId, syncHandle);
|
||||
handlesByFilename.set(event.data.filename, syncHandle);
|
||||
filenamesForHandles.set(syncHandle, event.data.filename);
|
||||
let size;
|
||||
try {
|
||||
size = syncHandle.getSize();
|
||||
} catch (e) {
|
||||
throw new Error("Couldn't get size of file: " + event.data.filename, {cause: e});
|
||||
}
|
||||
postMessage({requestId: event.data.requestId, handle: event.data.requestId, size});
|
||||
} else if (event.data.type === "createFile") {
|
||||
const handle = await rootDirHandle.getFileHandle(event.data.filename, {
|
||||
create: true,
|
||||
});
|
||||
let syncHandle;
|
||||
try {
|
||||
syncHandle = await handle.createSyncAccessHandle();
|
||||
} catch (e) {
|
||||
throw new Error("Couldn't create file: " + event.data.filename, {cause: e});
|
||||
}
|
||||
handlesByRequest.set(event.data.requestId, syncHandle);
|
||||
handlesByFilename.set(event.data.filename, syncHandle);
|
||||
filenamesForHandles.set(syncHandle, event.data.filename);
|
||||
postMessage({requestId: event.data.requestId, handle: event.data.requestId, result: "done"});
|
||||
} else if (event.data.type === "append") {
|
||||
const writable = handlesByRequest.get(event.data.handle);
|
||||
writable.write(event.data.data, {at: writable.getSize()});
|
||||
writable.flush();
|
||||
postMessage({requestId: event.data.requestId, result: "done"});
|
||||
} else if (event.data.type === "read") {
|
||||
const readable = handlesByRequest.get(event.data.handle);
|
||||
const buffer = new Uint8Array(event.data.length);
|
||||
const read = readable.read(buffer, {at: event.data.offset});
|
||||
if (read < event.data.length) {
|
||||
throw new Error("Couldn't read enough");
|
||||
}
|
||||
postMessage({requestId: event.data.requestId, data: buffer, result: "done"});
|
||||
} else if (event.data.type === "close") {
|
||||
const handle = handlesByRequest.get(event.data.handle);
|
||||
// console.log("Closing handle", filenamesForHandles.get(handle), event.data.handle, handle);
|
||||
handle.flush();
|
||||
handle.close();
|
||||
handlesByRequest.delete(handle);
|
||||
const filename = filenamesForHandles.get(handle);
|
||||
handlesByFilename.delete(filename);
|
||||
filenamesForHandles.delete(handle);
|
||||
postMessage({requestId: event.data.requestId, result: "done"});
|
||||
} else if (event.data.type === "closeAndRename") {
|
||||
const handle = handlesByRequest.get(event.data.handle);
|
||||
handle.flush();
|
||||
const buffer = new Uint8Array(handle.getSize());
|
||||
const read = handle.read(buffer, {at: 0});
|
||||
if (read < buffer.length) {
|
||||
throw new Error("Couldn't read enough " + read + ", " + handle.getSize());
|
||||
}
|
||||
handle.close();
|
||||
const oldFilename = filenamesForHandles.get(handle);
|
||||
await rootDirHandle.removeEntry(oldFilename);
|
||||
|
||||
const newHandle = await rootDirHandle.getFileHandle(event.data.filename, { create: true });
|
||||
let writable;
|
||||
try {
|
||||
writable = await newHandle.createSyncAccessHandle();
|
||||
} catch (e) {
|
||||
throw new Error("Couldn't create file (to rename to): " + event.data.filename, { cause: e })
|
||||
}
|
||||
writable.write(buffer);
|
||||
writable.close();
|
||||
postMessage({requestId: event.data.requestId, result: "done"});
|
||||
} else if (event.data.type === "removeFile") {
|
||||
try {
|
||||
await rootDirHandle.removeEntry(event.data.filename);
|
||||
} catch(e) {
|
||||
throw new Error("Couldn't remove file: " + event.data.filename, { cause: e });
|
||||
}
|
||||
postMessage({requestId: event.data.requestId, result: "done"});
|
||||
} else {
|
||||
console.error("Unknown event type", event.data.type);
|
||||
}
|
||||
};
|
||||
|
||||
//# sourceURL=opfsWorker.js
|
||||
`;
|
||||
158
packages/jazz-react-native/src/auth/DemoAuth.ts
Normal file
158
packages/jazz-react-native/src/auth/DemoAuth.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
import { AgentSecret } from "cojson";
|
||||
import { Account, AuthMethod, AuthResult, ID } from "jazz-tools";
|
||||
|
||||
type StorageData = {
|
||||
accountID: ID<Account>;
|
||||
accountSecret: AgentSecret;
|
||||
};
|
||||
|
||||
const localStorageKey = "demo-auth-logged-in-secret";
|
||||
|
||||
export class BrowserDemoAuth implements AuthMethod {
|
||||
constructor(
|
||||
public driver: BrowserDemoAuth.Driver,
|
||||
seedAccounts?: {
|
||||
[name: string]: {
|
||||
accountID: ID<Account>;
|
||||
accountSecret: AgentSecret;
|
||||
};
|
||||
},
|
||||
) {
|
||||
for (const [name, credentials] of Object.entries(seedAccounts || {})) {
|
||||
const storageData = JSON.stringify(
|
||||
credentials satisfies StorageData,
|
||||
);
|
||||
if (
|
||||
!(
|
||||
localStorage["demo-auth-existing-users"]?.split(",") as
|
||||
| string[]
|
||||
| undefined
|
||||
)?.includes(name)
|
||||
) {
|
||||
localStorage["demo-auth-existing-users"] = localStorage[
|
||||
"demo-auth-existing-users"
|
||||
]
|
||||
? localStorage["demo-auth-existing-users"] + "," + name
|
||||
: name;
|
||||
}
|
||||
localStorage["demo-auth-existing-users-" + name] = storageData;
|
||||
}
|
||||
}
|
||||
|
||||
async start() {
|
||||
if (localStorage["demo-auth-logged-in-secret"]) {
|
||||
const localStorageData = JSON.parse(
|
||||
localStorage[localStorageKey],
|
||||
) as StorageData;
|
||||
|
||||
const accountID = localStorageData.accountID as ID<Account>;
|
||||
const secret = localStorageData.accountSecret;
|
||||
|
||||
return {
|
||||
type: "existing",
|
||||
credentials: { accountID, secret },
|
||||
onSuccess: () => {
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
onError: (error: string | Error) => {
|
||||
this.driver.onError(error)
|
||||
},
|
||||
logOut: () => {
|
||||
delete localStorage[localStorageKey];
|
||||
}
|
||||
} satisfies AuthResult;
|
||||
} else {
|
||||
return new Promise<AuthResult>((resolve) => {
|
||||
this.driver.onReady({
|
||||
signUp: async (username) => {
|
||||
resolve({
|
||||
type: "new",
|
||||
creationProps: { name: username },
|
||||
saveCredentials: async (credentials: {
|
||||
accountID: ID<Account>;
|
||||
secret: AgentSecret;
|
||||
}) => {
|
||||
const storageData = JSON.stringify({
|
||||
accountID: credentials.accountID,
|
||||
accountSecret: credentials.secret,
|
||||
} satisfies StorageData);
|
||||
|
||||
localStorage["demo-auth-logged-in-secret"] =
|
||||
storageData;
|
||||
localStorage[
|
||||
"demo-auth-existing-users-" + username
|
||||
] = storageData;
|
||||
|
||||
localStorage["demo-auth-existing-users"] =
|
||||
localStorage["demo-auth-existing-users"]
|
||||
? localStorage[
|
||||
"demo-auth-existing-users"
|
||||
] +
|
||||
"," +
|
||||
username
|
||||
: username;
|
||||
},
|
||||
onSuccess: () => {
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
onError: (error: string | Error) => {
|
||||
this.driver.onError(error)
|
||||
},
|
||||
logOut: () => {
|
||||
delete localStorage[localStorageKey];
|
||||
}
|
||||
});
|
||||
},
|
||||
existingUsers:
|
||||
localStorage["demo-auth-existing-users"]?.split(",") ??
|
||||
[],
|
||||
logInAs: async (existingUser) => {
|
||||
const storageData = JSON.parse(
|
||||
localStorage[
|
||||
"demo-auth-existing-users-" + existingUser
|
||||
],
|
||||
) as StorageData;
|
||||
|
||||
localStorage["demo-auth-logged-in-secret"] =
|
||||
JSON.stringify(storageData);
|
||||
|
||||
resolve({
|
||||
type: "existing",
|
||||
credentials: {
|
||||
accountID: storageData.accountID,
|
||||
secret: storageData.accountSecret,
|
||||
},
|
||||
onSuccess: () => {
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
onError: (error: string | Error) => {
|
||||
this.driver.onError(error)
|
||||
},
|
||||
logOut: () => {
|
||||
delete localStorage[localStorageKey];
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @category Auth Providers */
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
export namespace BrowserDemoAuth {
|
||||
export interface Driver {
|
||||
onReady: (next: {
|
||||
signUp: (username: string) => Promise<void>;
|
||||
existingUsers: string[];
|
||||
logInAs: (existingUser: string) => Promise<void>;
|
||||
}) => void;
|
||||
onSignedIn: (next: { logOut: () => void }) => void;
|
||||
onError: (error: string | Error) => void;
|
||||
}
|
||||
}
|
||||
|
||||
function logOut() {
|
||||
delete localStorage[localStorageKey];
|
||||
}
|
||||
192
packages/jazz-react-native/src/auth/PasskeyAuth.ts
Normal file
192
packages/jazz-react-native/src/auth/PasskeyAuth.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
import {
|
||||
RawAccountID,
|
||||
AgentSecret,
|
||||
cojsonInternals,
|
||||
CryptoProvider,
|
||||
} from "cojson";
|
||||
import { Account, AuthMethod, AuthResult, ID } from "jazz-tools";
|
||||
|
||||
type LocalStorageData = {
|
||||
accountID: ID<Account>;
|
||||
accountSecret: AgentSecret;
|
||||
};
|
||||
|
||||
const localStorageKey = "jazz-logged-in-secret";
|
||||
|
||||
export class BrowserPasskeyAuth implements AuthMethod {
|
||||
constructor(
|
||||
public driver: BrowserPasskeyAuth.Driver,
|
||||
public appName: string,
|
||||
// TODO: is this a safe default?
|
||||
public appHostname: string = window.location.hostname,
|
||||
) {}
|
||||
|
||||
accountLoaded() {
|
||||
this.driver.onSignedIn({ logOut });
|
||||
}
|
||||
|
||||
onError(error: string | Error) {
|
||||
this.driver.onError(error);
|
||||
}
|
||||
|
||||
async start(crypto: CryptoProvider): Promise<AuthResult> {
|
||||
if (localStorage[localStorageKey]) {
|
||||
const localStorageData = JSON.parse(
|
||||
localStorage[localStorageKey],
|
||||
) as LocalStorageData;
|
||||
|
||||
const accountID = localStorageData.accountID as ID<Account>;
|
||||
const secret = localStorageData.accountSecret;
|
||||
|
||||
return {
|
||||
type: "existing",
|
||||
credentials: { accountID, secret },
|
||||
onSuccess: () => {
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
onError: (error: string | Error) => {
|
||||
this.driver.onError(error);
|
||||
},
|
||||
logOut: () => {
|
||||
delete localStorage[localStorageKey];
|
||||
},
|
||||
} satisfies AuthResult;
|
||||
} else {
|
||||
return new Promise<AuthResult>((resolve) => {
|
||||
this.driver.onReady({
|
||||
signUp: async (username) => {
|
||||
const secretSeed = crypto.newRandomSecretSeed();
|
||||
|
||||
resolve({
|
||||
type: "new",
|
||||
creationProps: { name: username },
|
||||
initialSecret:
|
||||
crypto.agentSecretFromSecretSeed(secretSeed),
|
||||
saveCredentials: async ({ accountID, secret }) => {
|
||||
const webAuthNCredentialPayload =
|
||||
new Uint8Array(
|
||||
cojsonInternals.secretSeedLength +
|
||||
cojsonInternals.shortHashLength,
|
||||
);
|
||||
|
||||
webAuthNCredentialPayload.set(secretSeed);
|
||||
webAuthNCredentialPayload.set(
|
||||
cojsonInternals.rawCoIDtoBytes(
|
||||
accountID as unknown as RawAccountID,
|
||||
),
|
||||
cojsonInternals.secretSeedLength,
|
||||
);
|
||||
|
||||
await navigator.credentials.create({
|
||||
publicKey: {
|
||||
challenge: Uint8Array.from([0, 1, 2]),
|
||||
rp: {
|
||||
name: this.appName,
|
||||
id: this.appHostname,
|
||||
},
|
||||
user: {
|
||||
id: webAuthNCredentialPayload,
|
||||
name:
|
||||
username +
|
||||
` (${new Date().toLocaleString()})`,
|
||||
displayName: username,
|
||||
},
|
||||
pubKeyCredParams: [
|
||||
{ alg: -7, type: "public-key" },
|
||||
],
|
||||
authenticatorSelection: {
|
||||
authenticatorAttachment: "platform",
|
||||
},
|
||||
timeout: 60000,
|
||||
attestation: "direct",
|
||||
},
|
||||
});
|
||||
|
||||
localStorage[localStorageKey] = JSON.stringify({
|
||||
accountID,
|
||||
accountSecret: secret,
|
||||
} satisfies LocalStorageData);
|
||||
},
|
||||
onSuccess: () => {
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
onError: (error: string | Error) => {
|
||||
this.driver.onError(error);
|
||||
},
|
||||
logOut: () => {
|
||||
delete localStorage[localStorageKey];
|
||||
},
|
||||
});
|
||||
},
|
||||
logIn: async () => {
|
||||
const webAuthNCredential =
|
||||
(await navigator.credentials.get({
|
||||
publicKey: {
|
||||
challenge: Uint8Array.from([0, 1, 2]),
|
||||
rpId: this.appHostname,
|
||||
allowCredentials: [],
|
||||
timeout: 60000,
|
||||
},
|
||||
})) as unknown as {
|
||||
response: { userHandle: ArrayBuffer };
|
||||
};
|
||||
if (!webAuthNCredential) {
|
||||
throw new Error("Couldn't log in");
|
||||
}
|
||||
|
||||
const webAuthNCredentialPayload = new Uint8Array(
|
||||
webAuthNCredential.response.userHandle,
|
||||
);
|
||||
const accountSecretSeed =
|
||||
webAuthNCredentialPayload.slice(
|
||||
0,
|
||||
cojsonInternals.secretSeedLength,
|
||||
);
|
||||
|
||||
const secret =
|
||||
crypto.agentSecretFromSecretSeed(accountSecretSeed);
|
||||
|
||||
const accountID = cojsonInternals.rawCoIDfromBytes(
|
||||
webAuthNCredentialPayload.slice(
|
||||
cojsonInternals.secretSeedLength,
|
||||
cojsonInternals.secretSeedLength +
|
||||
cojsonInternals.shortHashLength,
|
||||
),
|
||||
) as ID<Account>;
|
||||
|
||||
resolve({
|
||||
type: "existing",
|
||||
credentials: { accountID, secret },
|
||||
onSuccess: () => {
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
onError: (error: string | Error) => {
|
||||
this.driver.onError(error);
|
||||
},
|
||||
logOut: () => {
|
||||
delete localStorage[localStorageKey];
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @category Auth Providers */
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
export namespace BrowserPasskeyAuth {
|
||||
export interface Driver {
|
||||
onReady: (next: {
|
||||
signUp: (username: string) => Promise<void>;
|
||||
logIn: () => Promise<void>;
|
||||
}) => void;
|
||||
onSignedIn: (next: { logOut: () => void }) => void;
|
||||
onError: (error: string | Error) => void;
|
||||
}
|
||||
}
|
||||
|
||||
function logOut() {
|
||||
delete localStorage[localStorageKey];
|
||||
}
|
||||
144
packages/jazz-react-native/src/auth/PassphraseAuth.ts
Normal file
144
packages/jazz-react-native/src/auth/PassphraseAuth.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { AgentSecret, cojsonInternals, CryptoProvider } from "cojson";
|
||||
import {
|
||||
Account,
|
||||
AuthMethod,
|
||||
AuthResult,
|
||||
ID,
|
||||
} from "jazz-tools";
|
||||
import * as bip39 from "@scure/bip39";
|
||||
|
||||
type LocalStorageData = {
|
||||
accountID: ID<Account>;
|
||||
accountSecret: AgentSecret;
|
||||
};
|
||||
|
||||
const localStorageKey = "jazz-logged-in-secret";
|
||||
|
||||
export class BrowserPassphraseAuth implements AuthMethod {
|
||||
constructor(
|
||||
public driver: BrowserPassphraseAuth.Driver,
|
||||
public wordlist: string[],
|
||||
public appName: string,
|
||||
// TODO: is this a safe default?
|
||||
public appHostname: string = window.location.hostname,
|
||||
) {}
|
||||
|
||||
async start(crypto: CryptoProvider): Promise<AuthResult> {
|
||||
if (localStorage[localStorageKey]) {
|
||||
const localStorageData = JSON.parse(
|
||||
localStorage[localStorageKey],
|
||||
) as LocalStorageData;
|
||||
|
||||
const accountID = localStorageData.accountID as ID<Account>;
|
||||
const secret = localStorageData.accountSecret;
|
||||
|
||||
return {
|
||||
type: "existing",
|
||||
credentials: { accountID, secret },
|
||||
onSuccess: () => {
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
onError: (error: string | Error) => {
|
||||
this.driver.onError(error);
|
||||
},
|
||||
logOut: () => {
|
||||
delete localStorage[localStorageKey];
|
||||
},
|
||||
} satisfies AuthResult;
|
||||
} else {
|
||||
return new Promise<AuthResult>((resolve) => {
|
||||
this.driver.onReady({
|
||||
signUp: async (username, passphrase) => {
|
||||
const secretSeed = bip39.mnemonicToEntropy(
|
||||
passphrase,
|
||||
this.wordlist,
|
||||
);
|
||||
const accountSecret =
|
||||
crypto.agentSecretFromSecretSeed(secretSeed);
|
||||
if (!accountSecret) {
|
||||
this.driver.onError("Invalid passphrase");
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
type: "new",
|
||||
creationProps: { name: username },
|
||||
initialSecret: accountSecret,
|
||||
saveCredentials: async (credentials) => {
|
||||
localStorage[localStorageKey] = JSON.stringify({
|
||||
accountID: credentials.accountID,
|
||||
accountSecret: credentials.secret,
|
||||
} satisfies LocalStorageData);
|
||||
},
|
||||
onSuccess: () => {
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
onError: (error: string | Error) => {
|
||||
this.driver.onError(error);
|
||||
},
|
||||
logOut: () => {
|
||||
delete localStorage[localStorageKey];
|
||||
},
|
||||
});
|
||||
},
|
||||
logIn: async (passphrase: string) => {
|
||||
const secretSeed = bip39.mnemonicToEntropy(
|
||||
passphrase,
|
||||
this.wordlist,
|
||||
);
|
||||
const accountSecret =
|
||||
crypto.agentSecretFromSecretSeed(secretSeed);
|
||||
|
||||
if (!accountSecret) {
|
||||
this.driver.onError("Invalid passphrase");
|
||||
return;
|
||||
}
|
||||
|
||||
const accountID = cojsonInternals.idforHeader(
|
||||
cojsonInternals.accountHeaderForInitialAgentSecret(
|
||||
accountSecret,
|
||||
crypto,
|
||||
),
|
||||
crypto,
|
||||
) as ID<Account>;
|
||||
|
||||
resolve({
|
||||
type: "existing",
|
||||
credentials: { accountID, secret: accountSecret },
|
||||
onSuccess: () => {
|
||||
localStorage[localStorageKey] = JSON.stringify({
|
||||
accountID,
|
||||
accountSecret,
|
||||
} satisfies LocalStorageData);
|
||||
this.driver.onSignedIn({ logOut });
|
||||
},
|
||||
onError: (error: string | Error) => {
|
||||
this.driver.onError(error);
|
||||
},
|
||||
logOut: () => {
|
||||
delete localStorage[localStorageKey];
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @category Auth Providers */
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
export namespace BrowserPassphraseAuth {
|
||||
export interface Driver {
|
||||
onReady: (next: {
|
||||
signUp: (username: string, passphrase: string) => Promise<void>;
|
||||
logIn: (passphrase: string) => Promise<void>;
|
||||
}) => void;
|
||||
onSignedIn: (next: { logOut: () => void }) => void;
|
||||
onError: (error: string | Error) => void;
|
||||
}
|
||||
}
|
||||
|
||||
function logOut() {
|
||||
delete localStorage[localStorageKey];
|
||||
}
|
||||
362
packages/jazz-react-native/src/index.ts
Normal file
362
packages/jazz-react-native/src/index.ts
Normal file
@@ -0,0 +1,362 @@
|
||||
import {
|
||||
CoValue,
|
||||
ID,
|
||||
AgentID,
|
||||
SessionID,
|
||||
cojsonInternals,
|
||||
InviteSecret,
|
||||
Account,
|
||||
CoValueClass,
|
||||
WasmCrypto,
|
||||
CryptoProvider,
|
||||
AuthMethod,
|
||||
createJazzContext,
|
||||
AnonymousJazzAgent,
|
||||
} from "jazz-tools";
|
||||
import { RawAccountID, LSMStorage } from "cojson";
|
||||
import { OPFSFilesystem } from "./OPFSFilesystem.js";
|
||||
import { IDBStorage } from "cojson-storage-indexeddb";
|
||||
import { createWebSocketPeer } from "cojson-transport-ws";
|
||||
export { BrowserDemoAuth } from "./auth/DemoAuth.js";
|
||||
export { BrowserPasskeyAuth } from "./auth/PasskeyAuth.js";
|
||||
export { BrowserPassphraseAuth } from "./auth/PassphraseAuth.js";
|
||||
|
||||
/** @category Context Creation */
|
||||
export type BrowserContext<Acc extends Account> = {
|
||||
me: Acc;
|
||||
logOut: () => void;
|
||||
// TODO: Symbol.dispose?
|
||||
done: () => void;
|
||||
};
|
||||
|
||||
export type BrowserGuestContext = {
|
||||
guest: AnonymousJazzAgent;
|
||||
logOut: () => void;
|
||||
done: () => void;
|
||||
};
|
||||
|
||||
export type BrowserContextOptions<Acc extends Account> = {
|
||||
auth: AuthMethod;
|
||||
AccountSchema: CoValueClass<Acc> & {
|
||||
fromNode: (typeof Account)["fromNode"];
|
||||
};
|
||||
} & BaseBrowserContextOptions;
|
||||
|
||||
export type BaseBrowserContextOptions = {
|
||||
peer: `wss://${string}` | `ws://${string}`;
|
||||
reconnectionTimeout?: number;
|
||||
storage?: "indexedDB" | "singleTabOPFS";
|
||||
crypto?: CryptoProvider;
|
||||
};
|
||||
|
||||
/** @category Context Creation */
|
||||
export async function createJazzBrowserContext<Acc extends Account>(
|
||||
options: BrowserContextOptions<Acc>,
|
||||
): Promise<BrowserContext<Acc>>;
|
||||
export async function createJazzBrowserContext(
|
||||
options: BaseBrowserContextOptions,
|
||||
): Promise<BrowserGuestContext>;
|
||||
export async function createJazzBrowserContext<Acc extends Account>(
|
||||
options: BrowserContextOptions<Acc> | BaseBrowserContextOptions,
|
||||
): Promise<BrowserContext<Acc> | BrowserGuestContext>;
|
||||
export async function createJazzBrowserContext<Acc extends Account>(
|
||||
options: BrowserContextOptions<Acc> | BaseBrowserContextOptions,
|
||||
): Promise<BrowserContext<Acc> | BrowserGuestContext> {
|
||||
const crypto = options.crypto || (await WasmCrypto.create());
|
||||
|
||||
const firstWsPeer = createWebSocketPeer({
|
||||
websocket: new WebSocket(options.peer),
|
||||
id: options.peer + "@" + new Date().toISOString(),
|
||||
role: "server",
|
||||
});
|
||||
let shouldTryToReconnect = true;
|
||||
|
||||
let currentReconnectionTimeout = options.reconnectionTimeout || 500;
|
||||
|
||||
function onOnline() {
|
||||
console.log("Online, resetting reconnection timeout");
|
||||
currentReconnectionTimeout = options.reconnectionTimeout || 500;
|
||||
}
|
||||
|
||||
window.addEventListener("online", onOnline);
|
||||
|
||||
const context =
|
||||
"auth" in options
|
||||
? await createJazzContext({
|
||||
AccountSchema: options.AccountSchema,
|
||||
auth: options.auth,
|
||||
crypto: await WasmCrypto.create(),
|
||||
peersToLoadFrom: [
|
||||
options.storage === "singleTabOPFS"
|
||||
? await LSMStorage.asPeer({
|
||||
fs: new OPFSFilesystem(crypto),
|
||||
// trace: true,
|
||||
})
|
||||
: await IDBStorage.asPeer(),
|
||||
firstWsPeer,
|
||||
],
|
||||
sessionProvider: provideBroswerLockSession,
|
||||
})
|
||||
: await createJazzContext({
|
||||
crypto: await WasmCrypto.create(),
|
||||
peersToLoadFrom: [
|
||||
options.storage === "singleTabOPFS"
|
||||
? await LSMStorage.asPeer({
|
||||
fs: new OPFSFilesystem(crypto),
|
||||
// trace: true,
|
||||
})
|
||||
: await IDBStorage.asPeer(),
|
||||
firstWsPeer,
|
||||
],
|
||||
});
|
||||
|
||||
const node =
|
||||
"account" in context
|
||||
? context.account._raw.core.node
|
||||
: context.agent.node;
|
||||
|
||||
async function websocketReconnectLoop() {
|
||||
while (shouldTryToReconnect) {
|
||||
if (
|
||||
Object.keys(node.syncManager.peers).some((peerId) =>
|
||||
peerId.includes(options.peer),
|
||||
)
|
||||
) {
|
||||
// TODO: this might drain battery, use listeners instead
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
} else {
|
||||
console.log(
|
||||
"Websocket disconnected, trying to reconnect in " +
|
||||
currentReconnectionTimeout +
|
||||
"ms",
|
||||
);
|
||||
currentReconnectionTimeout = Math.min(
|
||||
currentReconnectionTimeout * 2,
|
||||
30000,
|
||||
);
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, currentReconnectionTimeout);
|
||||
window.addEventListener(
|
||||
"online",
|
||||
() => {
|
||||
console.log(
|
||||
"Online, trying to reconnect immediately",
|
||||
);
|
||||
resolve();
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
});
|
||||
|
||||
node.syncManager.addPeer(
|
||||
createWebSocketPeer({
|
||||
websocket: new WebSocket(options.peer),
|
||||
id: options.peer + "@" + new Date().toISOString(),
|
||||
role: "server",
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void websocketReconnectLoop();
|
||||
|
||||
return "account" in context
|
||||
? {
|
||||
me: context.account,
|
||||
done: () => {
|
||||
shouldTryToReconnect = false;
|
||||
window.removeEventListener("online", onOnline);
|
||||
context.done();
|
||||
},
|
||||
logOut: () => {
|
||||
context.logOut();
|
||||
},
|
||||
}
|
||||
: {
|
||||
guest: context.agent,
|
||||
done: () => {
|
||||
shouldTryToReconnect = false;
|
||||
window.removeEventListener("online", onOnline);
|
||||
context.done();
|
||||
},
|
||||
logOut: () => {
|
||||
context.logOut();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** @category Auth Providers */
|
||||
export type SessionProvider = (
|
||||
accountID: ID<Account> | AgentID,
|
||||
) => Promise<SessionID>;
|
||||
|
||||
export function provideBroswerLockSession(
|
||||
accountID: ID<Account> | AgentID,
|
||||
crypto: CryptoProvider,
|
||||
) {
|
||||
let sessionDone!: () => void;
|
||||
const donePromise = new Promise<void>((resolve) => {
|
||||
sessionDone = resolve;
|
||||
});
|
||||
|
||||
let resolveSession: (sessionID: SessionID) => void;
|
||||
const sessionPromise = new Promise<SessionID>((resolve) => {
|
||||
resolveSession = resolve;
|
||||
});
|
||||
|
||||
void (async function () {
|
||||
for (let idx = 0; idx < 100; idx++) {
|
||||
// To work better around StrictMode
|
||||
for (let retry = 0; retry < 2; retry++) {
|
||||
// console.debug("Trying to get lock", accountID + "_" + idx);
|
||||
const sessionFinishedOrNoLock = await navigator.locks.request(
|
||||
accountID + "_" + idx,
|
||||
{ ifAvailable: true },
|
||||
async (lock) => {
|
||||
if (!lock) return "noLock";
|
||||
|
||||
const sessionID =
|
||||
localStorage[accountID + "_" + idx] ||
|
||||
crypto.newRandomSessionID(
|
||||
accountID as RawAccountID | AgentID,
|
||||
);
|
||||
localStorage[accountID + "_" + idx] = sessionID;
|
||||
|
||||
// console.debug(
|
||||
// "Got lock",
|
||||
// accountID + "_" + idx,
|
||||
// sessionID
|
||||
// );
|
||||
|
||||
resolveSession(sessionID);
|
||||
|
||||
await donePromise;
|
||||
console.log(
|
||||
"Done with lock",
|
||||
accountID + "_" + idx,
|
||||
sessionID,
|
||||
);
|
||||
return "sessionFinished";
|
||||
},
|
||||
);
|
||||
|
||||
if (sessionFinishedOrNoLock === "sessionFinished") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error("Couldn't get lock on session after 100x2 tries");
|
||||
})();
|
||||
|
||||
return sessionPromise.then((sessionID) => ({
|
||||
sessionID,
|
||||
sessionDone,
|
||||
}));
|
||||
}
|
||||
|
||||
/** @category Invite Links */
|
||||
export function createInviteLink<C extends CoValue>(
|
||||
value: C,
|
||||
role: "reader" | "writer" | "admin",
|
||||
// default to same address as window.location, but without hash
|
||||
{
|
||||
baseURL = window.location.href.replace(/#.*$/, ""),
|
||||
valueHint,
|
||||
}: { baseURL?: string; valueHint?: string } = {},
|
||||
): string {
|
||||
const coValueCore = value._raw.core;
|
||||
let currentCoValue = coValueCore;
|
||||
|
||||
while (currentCoValue.header.ruleset.type === "ownedByGroup") {
|
||||
currentCoValue = currentCoValue.getGroup().core;
|
||||
}
|
||||
|
||||
if (currentCoValue.header.ruleset.type !== "group") {
|
||||
throw new Error("Can't create invite link for object without group");
|
||||
}
|
||||
|
||||
const group = cojsonInternals.expectGroup(
|
||||
currentCoValue.getCurrentContent(),
|
||||
);
|
||||
const inviteSecret = group.createInvite(role);
|
||||
|
||||
return `${baseURL}#/invite/${valueHint ? valueHint + "/" : ""}${
|
||||
value.id
|
||||
}/${inviteSecret}`;
|
||||
}
|
||||
|
||||
/** @category Invite Links */
|
||||
export function parseInviteLink<C extends CoValue>(
|
||||
inviteURL: string,
|
||||
):
|
||||
| {
|
||||
valueID: ID<C>;
|
||||
valueHint?: string;
|
||||
inviteSecret: InviteSecret;
|
||||
}
|
||||
| undefined {
|
||||
const url = new URL(inviteURL);
|
||||
const parts = url.hash.split("/");
|
||||
|
||||
let valueHint: string | undefined;
|
||||
let valueID: ID<C> | undefined;
|
||||
let inviteSecret: InviteSecret | undefined;
|
||||
|
||||
if (parts[0] === "#" && parts[1] === "invite") {
|
||||
if (parts.length === 5) {
|
||||
valueHint = parts[2];
|
||||
valueID = parts[3] as ID<C>;
|
||||
inviteSecret = parts[4] as InviteSecret;
|
||||
} else if (parts.length === 4) {
|
||||
valueID = parts[2] as ID<C>;
|
||||
inviteSecret = parts[3] as InviteSecret;
|
||||
}
|
||||
|
||||
if (!valueID || !inviteSecret) {
|
||||
return undefined;
|
||||
}
|
||||
return { valueID, inviteSecret, valueHint };
|
||||
}
|
||||
}
|
||||
|
||||
/** @category Invite Links */
|
||||
export function consumeInviteLinkFromWindowLocation<V extends CoValue>({
|
||||
as,
|
||||
forValueHint,
|
||||
invitedObjectSchema,
|
||||
}: {
|
||||
as: Account;
|
||||
forValueHint?: string;
|
||||
invitedObjectSchema: CoValueClass<V>;
|
||||
}): Promise<
|
||||
| {
|
||||
valueID: ID<V>;
|
||||
valueHint?: string;
|
||||
inviteSecret: InviteSecret;
|
||||
}
|
||||
| undefined
|
||||
> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const result = parseInviteLink<V>(window.location.href);
|
||||
|
||||
if (result && result.valueHint === forValueHint) {
|
||||
as.acceptInvite(
|
||||
result.valueID,
|
||||
result.inviteSecret,
|
||||
invitedObjectSchema,
|
||||
)
|
||||
.then(() => {
|
||||
resolve(result);
|
||||
window.history.replaceState(
|
||||
{},
|
||||
"",
|
||||
window.location.href.replace(/#.*$/, ""),
|
||||
);
|
||||
})
|
||||
.catch(reject);
|
||||
} else {
|
||||
resolve(undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
16
packages/jazz-react-native/tsconfig.json
Normal file
16
packages/jazz-react-native/tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"module": "esnext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"esModuleInterop": true,
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
}
|
||||
6087
pnpm-lock.yaml
generated
6087
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user