Compare commits
145 Commits
jazz-brows
...
jazz-tools
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3baa951bb9 | ||
|
|
b726e31669 | ||
|
|
63bb31e0ad | ||
|
|
d059460abd | ||
|
|
ba81951331 | ||
|
|
bd132bb9ad | ||
|
|
1ee435ad95 | ||
|
|
646ad330ae | ||
|
|
af8e6e3f82 | ||
|
|
f247525dfe | ||
|
|
012022db2b | ||
|
|
da92891498 | ||
|
|
b0c55720f8 | ||
|
|
a3d825fc6f | ||
|
|
29ca2e6f65 | ||
|
|
07a683c13d | ||
|
|
e53f02d6d7 | ||
|
|
4915bfa26d | ||
|
|
af45aac5f2 | ||
|
|
1136d9b744 | ||
|
|
92e78dc262 | ||
|
|
bf76d798c4 | ||
|
|
627f8c4c28 | ||
|
|
a1e0410863 | ||
|
|
03897a2689 | ||
|
|
823f546028 | ||
|
|
9bc54d1939 | ||
|
|
30780c05f0 | ||
|
|
118b6294ac | ||
|
|
6dc9b9d2ec | ||
|
|
ccbcee5102 | ||
|
|
0ae2067c3c | ||
|
|
2137938ead | ||
|
|
d14bb57ff5 | ||
|
|
3f42a4ddf9 | ||
|
|
0eed228170 | ||
|
|
a519537701 | ||
|
|
43c79cac2a | ||
|
|
44dbaa00d4 | ||
|
|
a0df32e81a | ||
|
|
236d8226d8 | ||
|
|
1220fa5d97 | ||
|
|
f3a5f83f25 | ||
|
|
a1bd6fc79b | ||
|
|
0f83320222 | ||
|
|
a3c4067de3 | ||
|
|
3042627748 | ||
|
|
8cea1e96cf | ||
|
|
64bb9ba90e | ||
|
|
f136dfe39b | ||
|
|
b32ae6240c | ||
|
|
fc4a89f77f | ||
|
|
7a6f8db509 | ||
|
|
086b9af565 | ||
|
|
5e95d8b76e | ||
|
|
47e0b68c2e | ||
|
|
5cc58c8e02 | ||
|
|
9df644c578 | ||
|
|
a20e430e7f | ||
|
|
1e625f3c12 | ||
|
|
8b3686c7ce | ||
|
|
bce04ee06d | ||
|
|
f2e9115f4c | ||
|
|
6854f9930c | ||
|
|
ee0897d9a8 | ||
|
|
243ab074eb | ||
|
|
385659b243 | ||
|
|
938f9256db | ||
|
|
88521721bf | ||
|
|
2701630582 | ||
|
|
07ce619fa2 | ||
|
|
895de1a470 | ||
|
|
4450761a7b | ||
|
|
08b3d65c0b | ||
|
|
5dac731f26 | ||
|
|
e99308cda2 | ||
|
|
88e314d980 | ||
|
|
62e0e5d721 | ||
|
|
aa16ad9c1c | ||
|
|
ada802bff8 | ||
|
|
44e1d140ca | ||
|
|
e0ef3fc1de | ||
|
|
a31ac66213 | ||
|
|
b444b2e96a | ||
|
|
8fcc4b5e50 | ||
|
|
33bfbee9cf | ||
|
|
d08e4e263b | ||
|
|
471b8c6a15 | ||
|
|
7dd080d907 | ||
|
|
69c81a3e90 | ||
|
|
d8ed987461 | ||
|
|
beb45c2656 | ||
|
|
e6241dfb5a | ||
|
|
1d71ca1511 | ||
|
|
65941c7f87 | ||
|
|
a37dc1c22f | ||
|
|
774f232390 | ||
|
|
12c19fc940 | ||
|
|
338f5421f4 | ||
|
|
e0daca300b | ||
|
|
5c76e37f14 | ||
|
|
0117d0c9b9 | ||
|
|
b90c766c05 | ||
|
|
262a36e456 | ||
|
|
cb1df65beb | ||
|
|
ea91e63ff2 | ||
|
|
8eae2eb31e | ||
|
|
c9044f5123 | ||
|
|
24340173fa | ||
|
|
53e88993a0 | ||
|
|
ece168878b | ||
|
|
cad84db52b | ||
|
|
342a385111 | ||
|
|
f87ba7d927 | ||
|
|
7c7f55b85c | ||
|
|
0e5b9f5292 | ||
|
|
2f5af3dece | ||
|
|
2c35e2ba85 | ||
|
|
0a4f79d5a4 | ||
|
|
43cb7abba7 | ||
|
|
25f76f6b02 | ||
|
|
6a56561c98 | ||
|
|
2ac31e7c51 | ||
|
|
1bbefab5a9 | ||
|
|
1143b32cf3 | ||
|
|
51ada27810 | ||
|
|
954ecb3984 | ||
|
|
05089270d9 | ||
|
|
fecc81111a | ||
|
|
4d3e7dbcd5 | ||
|
|
ee65f18fd9 | ||
|
|
bcbc4636ed | ||
|
|
8c323c4513 | ||
|
|
4103ea0c88 | ||
|
|
733ebec902 | ||
|
|
10a3834668 | ||
|
|
593c3aeb6e | ||
|
|
a55d71c28d | ||
|
|
c030c7a57e | ||
|
|
e5b4c0448a | ||
|
|
0d516a3c6a | ||
|
|
271ff3eb40 | ||
|
|
dcc836ff98 | ||
|
|
22da4ea136 | ||
|
|
80e86c92b2 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -7,11 +7,15 @@ docsTmp
|
||||
coverage
|
||||
.direnv
|
||||
|
||||
# Typescript
|
||||
**/*.tsbuildinfo
|
||||
|
||||
# Next.js
|
||||
**/.next
|
||||
|
||||
# Vite output
|
||||
**/dist
|
||||
__screenshots__
|
||||
|
||||
# Playwright
|
||||
test-results
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# chat-rn-clerk
|
||||
|
||||
## 1.0.72
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react-native@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-react-native-auth-clerk@0.10.7
|
||||
- jazz-react-native-media-images@0.10.7
|
||||
|
||||
## 1.0.71
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-react-native@0.10.6
|
||||
- jazz-react-native-auth-clerk@0.10.6
|
||||
- jazz-react-native-media-images@0.10.6
|
||||
|
||||
## 1.0.70
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "chat-rn-clerk",
|
||||
"main": "index.js",
|
||||
"version": "1.0.70",
|
||||
"version": "1.0.72",
|
||||
"scripts": {
|
||||
"build": "expo export -p ios",
|
||||
"start": "expo start",
|
||||
@@ -9,23 +9,22 @@
|
||||
"format-and-lint:fix": "biome check . --write",
|
||||
"android": "expo run:android",
|
||||
"ios": "expo run:ios",
|
||||
"web": "expo start --web",
|
||||
"test": "jest --watchAll"
|
||||
"web": "expo start --web"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-expo"
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@bacons/text-decoder": "0.0.0",
|
||||
"@bam.tech/react-native-image-resizer": "^3.0.11",
|
||||
"@craftzdog/react-native-buffer": "6.0.5",
|
||||
"@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",
|
||||
"base-64": "^1.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"clsx": "^2.0.0",
|
||||
"expo": "^52.0.0",
|
||||
"expo-build-properties": "~0.13.1",
|
||||
@@ -51,18 +50,14 @@
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-native": "~0.76.3",
|
||||
"react-native-fetch-api": "^3.0.0",
|
||||
"react-native-gesture-handler": "~2.20.2",
|
||||
"react-native-get-random-values": "^1.11.0",
|
||||
"react-native-polyfill-globals": "^3.1.0",
|
||||
"react-native-quick-base64": "^2.1.2",
|
||||
"react-native-reanimated": "~3.16.3",
|
||||
"react-native-safe-area-context": "4.12.0",
|
||||
"react-native-screens": "4.1.0",
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"react-native-web": "~0.19.13",
|
||||
"text-encoding": "^0.7.0",
|
||||
"web-streams-polyfill": "^3.2.1"
|
||||
"readable-stream": "4.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.0",
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
import "react-native-polyfill-globals/auto";
|
||||
import "@azure/core-asynciterator-polyfill";
|
||||
import { Buffer } from "buffer";
|
||||
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
|
||||
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
|
||||
/* eslint-disable import/order */
|
||||
|
||||
// @ts-expect-error - @types/react-native doesn't cover this file
|
||||
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
|
||||
|
||||
import { Buffer } from "@craftzdog/react-native-buffer";
|
||||
polyfillGlobal("Buffer", () => Buffer);
|
||||
|
||||
// @ts-expect-error - @types/readable-stream doesn't have ReadableStream type
|
||||
import { ReadableStream } from "readable-stream";
|
||||
polyfillGlobal("ReadableStream", () => ReadableStream);
|
||||
|
||||
import "@azure/core-asynciterator-polyfill";
|
||||
|
||||
import "@bacons/text-decoder/install";
|
||||
|
||||
import "react-native-get-random-values";
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# chat-rn
|
||||
|
||||
## 1.0.69
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react-native@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 1.0.68
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-react-native@0.10.6
|
||||
|
||||
## 1.0.67
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chat-rn",
|
||||
"version": "1.0.67",
|
||||
"version": "1.0.69",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "expo export -p ios",
|
||||
@@ -13,11 +13,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@bacons/text-decoder": "0.0.0",
|
||||
"@craftzdog/react-native-buffer": "6.0.5",
|
||||
"@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",
|
||||
"base-64": "^1.0.0",
|
||||
"clsx": "^2.0.0",
|
||||
"expo": "^52.0.0",
|
||||
"expo-build-properties": "~0.13.1",
|
||||
@@ -33,16 +34,13 @@
|
||||
"nativewind": "^4.1.21",
|
||||
"react": "^18.3.1",
|
||||
"react-native": "~0.76.3",
|
||||
"react-native-fetch-api": "^3.0.0",
|
||||
"react-native-get-random-values": "^1.11.0",
|
||||
"react-native-nitro-modules": "0.21.0",
|
||||
"react-native-polyfill-globals": "^3.1.0",
|
||||
"react-native-quick-crypto": "1.0.0-beta.12",
|
||||
"react-native-safe-area-context": "4.12.0",
|
||||
"react-native-screens": "4.1.0",
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"text-encoding": "^0.7.0",
|
||||
"web-streams-polyfill": "^3.2.1"
|
||||
"readable-stream": "4.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.0",
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import "react-native-polyfill-globals/auto";
|
||||
import "@azure/core-asynciterator-polyfill";
|
||||
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
|
||||
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
|
||||
/* eslint-disable import/order */
|
||||
|
||||
// @ts-expect-error - @types/react-native doesn't cover this file
|
||||
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
|
||||
|
||||
import { Buffer } from "@craftzdog/react-native-buffer";
|
||||
polyfillGlobal("Buffer", () => Buffer);
|
||||
|
||||
// @ts-expect-error - @types/readable-stream doesn't have ReadableStream type
|
||||
import { ReadableStream } from "readable-stream";
|
||||
polyfillGlobal("ReadableStream", () => ReadableStream);
|
||||
|
||||
import "@azure/core-asynciterator-polyfill";
|
||||
|
||||
import "@bacons/text-decoder/install";
|
||||
|
||||
import "react-native-get-random-values";
|
||||
|
||||
@@ -44,4 +44,5 @@ appId: com.jazz.chatrn
|
||||
|
||||
# logout
|
||||
- tapOn: "Logout"
|
||||
- assertVisible: "Anonymous user"
|
||||
- assertVisible: "boorad"
|
||||
- assertVisible: "bro, low key, it do be like that tho"
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# chat-vue
|
||||
|
||||
## 0.0.56
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [bf76d79]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-browser@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-vue@0.10.7
|
||||
|
||||
## 0.0.55
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-browser@0.10.6
|
||||
- jazz-vue@0.10.6
|
||||
|
||||
## 0.0.54
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chat-vue",
|
||||
"version": "0.0.54",
|
||||
"version": "0.0.56",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# jazz-example-chat
|
||||
|
||||
## 0.0.152
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-browser-media-images@0.10.7
|
||||
|
||||
## 0.0.151
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- hash-slash@0.2.2
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-browser-media-images@0.10.6
|
||||
|
||||
## 0.0.150
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-chat",
|
||||
"private": true,
|
||||
"version": "0.0.150",
|
||||
"version": "0.0.152",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -9,8 +9,8 @@
|
||||
"format-and-lint": "biome check .",
|
||||
"format-and-lint:fix": "biome check . --write",
|
||||
"preview": "vite preview",
|
||||
"test": "playwright test",
|
||||
"test:ui": "playwright test --ui"
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:ui": "playwright test --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"clsx": "^2.0.0",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# minimal-auth-clerk
|
||||
|
||||
## 0.0.51
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react-auth-clerk@0.10.7
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 0.0.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react-auth-clerk@0.10.6
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
|
||||
## 0.0.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "clerk",
|
||||
"private": true,
|
||||
"version": "0.0.49",
|
||||
"version": "0.0.51",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -13,7 +13,7 @@
|
||||
"dependencies": {
|
||||
"@clerk/clerk-react": "^5.4.1",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-react-auth-clerk": "workspace:0.10.5",
|
||||
"jazz-react-auth-clerk": "workspace:0.10.7",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# file-share-svelte
|
||||
|
||||
## 0.0.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-svelte@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 0.0.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-svelte@0.10.6
|
||||
|
||||
## 0.0.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "file-share-svelte",
|
||||
"version": "0.0.34",
|
||||
"version": "0.0.36",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -13,8 +13,8 @@
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format-and-lint": "pnpm run format && pnpm run lint",
|
||||
"format-and-lint:fix": "pnpm run format --write && pnpm run lint --fix",
|
||||
"test": "playwright test",
|
||||
"test:ui": "playwright test --ui"
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:ui": "playwright test --ui"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-vercel": "^5.5.0",
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# form
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-browser-media-images@0.10.7
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- hash-slash@0.2.2
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-browser-media-images@0.10.6
|
||||
|
||||
## 0.0.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "form",
|
||||
"private": true,
|
||||
"version": "0.0.45",
|
||||
"version": "0.0.47",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useIframeHashRouter } from "hash-slash";
|
||||
import { useAccount } from "jazz-react";
|
||||
import { ID } from "jazz-tools";
|
||||
import { CreateOrder } from "./CreateOrder.tsx";
|
||||
import { EditOrder } from "./EditOrder.tsx";
|
||||
@@ -7,25 +6,10 @@ import { Orders } from "./Orders.tsx";
|
||||
import { BubbleTeaOrder } from "./schema.ts";
|
||||
|
||||
function App() {
|
||||
const { me, logOut } = useAccount();
|
||||
const router = useIframeHashRouter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<nav className="container py-2 border-b flex items-center justify-between">
|
||||
<span>
|
||||
You're logged in as <strong>{me?.profile?.name}</strong>
|
||||
</span>
|
||||
<button
|
||||
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md dark:bg-stone-900 dark:text-white"
|
||||
onClick={() => logOut()}
|
||||
>
|
||||
Log out
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main className="container py-8 space-y-8">
|
||||
{router.route({
|
||||
"/": () => <Orders />,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
{"root":["./src/app.tsx","./src/createorder.tsx","./src/draftindicator.tsx","./src/editorder.tsx","./src/errors.tsx","./src/linktohome.tsx","./src/orderform.tsx","./src/orderthumbnail.tsx","./src/orders.tsx","./src/main.tsx","./src/schema.ts","./src/vite-env.d.ts"],"version":"5.6.3"}
|
||||
@@ -1,5 +1,25 @@
|
||||
# image-upload
|
||||
|
||||
## 0.0.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-browser-media-images@0.10.7
|
||||
|
||||
## 0.0.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-browser-media-images@0.10.6
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "image-upload",
|
||||
"private": true,
|
||||
"version": "0.0.47",
|
||||
"version": "0.0.49",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
import { useAccount } from "jazz-react";
|
||||
import ImageUpload from "./ImageUpload.tsx";
|
||||
|
||||
function App() {
|
||||
const { me, logOut } = useAccount();
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<nav className="container">
|
||||
<span>
|
||||
You're logged in as <strong>{me?.profile?.name}</strong>
|
||||
</span>
|
||||
<button onClick={() => logOut()}>Log out</button>
|
||||
</nav>
|
||||
</header>
|
||||
<main className="container">
|
||||
<ImageUpload />
|
||||
</main>
|
||||
|
||||
@@ -46,7 +46,12 @@ export default function ImageUpload() {
|
||||
) : (
|
||||
<div>
|
||||
<label>Upload image</label>
|
||||
<input ref={inputRef} type="file" onChange={onImageChange} />
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
accept="image/png, image/jpeg, image/gif"
|
||||
onChange={onImageChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -72,8 +72,7 @@ nav {
|
||||
.container {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding-right: 0.75rem;
|
||||
padding-left: 0.75rem;
|
||||
padding: 2rem 0.75rem;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# jazz-example-inspector
|
||||
|
||||
## 0.0.108
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [0f83320]
|
||||
- Updated dependencies [012022d]
|
||||
- cojson@0.10.7
|
||||
- cojson-transport-ws@0.10.7
|
||||
|
||||
## 0.0.107
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [5c76e37]
|
||||
- hash-slash@0.2.2
|
||||
- cojson@0.10.6
|
||||
- cojson-transport-ws@0.10.6
|
||||
|
||||
## 0.0.106
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-inspector-app",
|
||||
"private": true,
|
||||
"version": "0.0.106",
|
||||
"version": "0.0.108",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -16,9 +16,9 @@
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"cojson": "workspace:0.10.4",
|
||||
"cojson-transport-ws": "workspace:0.10.4",
|
||||
"hash-slash": "workspace:0.2.1",
|
||||
"cojson": "workspace:0.10.7",
|
||||
"cojson-transport-ws": "workspace:0.10.7",
|
||||
"hash-slash": "workspace:0.2.2",
|
||||
"lucide-react": "^0.274.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"react": "^18.3.1",
|
||||
|
||||
@@ -102,6 +102,7 @@ export default function CoJsonViewerApp() {
|
||||
if (coValueId) {
|
||||
setPage(coValueId);
|
||||
}
|
||||
setCoValueId("");
|
||||
};
|
||||
|
||||
if (
|
||||
@@ -118,8 +119,22 @@ export default function CoJsonViewerApp() {
|
||||
|
||||
return (
|
||||
<div className="w-full h-screen bg-gray-100 p-4 overflow-hidden flex flex-col">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<div className="flex items-center mb-4 gap-4">
|
||||
<Breadcrumbs path={path} onBreadcrumbClick={goToIndex} />
|
||||
<div className="flex-1">
|
||||
<form onSubmit={handleCoValueIdSubmit}>
|
||||
{path.length !== 0 && (
|
||||
<input
|
||||
className="border p-2 rounded-lg min-w-[21rem] font-mono"
|
||||
placeholder="co_z1234567890abcdef123456789"
|
||||
value={coValueId}
|
||||
onChange={(e) =>
|
||||
setCoValueId(e.target.value as CoID<RawCoValue>)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
<AccountSwitcher
|
||||
accounts={accounts}
|
||||
currentAccount={currentAccount}
|
||||
@@ -172,7 +187,6 @@ export default function CoJsonViewerApp() {
|
||||
type="button"
|
||||
className="border inline-block px-2 py-1.5 text-black rounded"
|
||||
onClick={() => {
|
||||
setCoValueId(currentAccount.id);
|
||||
setPage(currentAccount.id);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -18,6 +18,8 @@ export function ValueRenderer({
|
||||
compact?: boolean;
|
||||
onCoIDClick?: (childNode: CoID<RawCoValue>) => void;
|
||||
}) {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
if (typeof json === "undefined" || json === undefined) {
|
||||
return <span className="text-gray-400">undefined</span>;
|
||||
}
|
||||
@@ -85,15 +87,31 @@ export function ValueRenderer({
|
||||
return (
|
||||
<span
|
||||
title={JSON.stringify(json, null, 2)}
|
||||
className="inline-block max-w-64 truncate"
|
||||
className="inline-block max-w-64"
|
||||
>
|
||||
{compact ? (
|
||||
<span>
|
||||
Object{" "}
|
||||
<span className="text-gray-500">({Object.keys(json).length})</span>
|
||||
<pre className="mt-1 text-sm whitespace-pre-wrap">
|
||||
{isExpanded
|
||||
? JSON.stringify(json, null, 2)
|
||||
: JSON.stringify(json, null, 2)
|
||||
.split("\n")
|
||||
.slice(0, 3)
|
||||
.join("\n") + (Object.keys(json).length > 2 ? "\n..." : "")}
|
||||
</pre>
|
||||
<button
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
className="text-xs text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
{isExpanded ? "Show less" : "Show more"}
|
||||
</button>
|
||||
</span>
|
||||
) : (
|
||||
JSON.stringify(json, null, 2)
|
||||
<pre className="whitespace-pre-wrap">
|
||||
{JSON.stringify(json, null, 2)}
|
||||
</pre>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# jazz-example-musicplayer
|
||||
|
||||
## 0.0.73
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-inspector@0.10.7
|
||||
|
||||
## 0.0.72
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-inspector@0.10.6
|
||||
|
||||
## 0.0.71
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-music-player",
|
||||
"private": true,
|
||||
"version": "0.0.71",
|
||||
"version": "0.0.73",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -9,8 +9,8 @@
|
||||
"format-and-lint": "biome check .",
|
||||
"format-and-lint:fix": "biome check . --write",
|
||||
"preview": "vite preview",
|
||||
"test": "playwright test",
|
||||
"test:ui": "playwright test --ui"
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:ui": "playwright test --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dialog": "^1.1.4",
|
||||
@@ -22,8 +22,8 @@
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:0.10.5",
|
||||
"jazz-tools": "workspace:0.10.5",
|
||||
"jazz-react": "workspace:0.10.7",
|
||||
"jazz-tools": "workspace:0.10.7",
|
||||
"lucide-react": "^0.274.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# organization
|
||||
|
||||
## 0.0.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 0.0.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
|
||||
## 0.0.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "organization",
|
||||
"private": true,
|
||||
"version": "0.0.43",
|
||||
"version": "0.0.45",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
{"root":["./src/acceptinvitepage.tsx","./src/homepage.tsx","./src/layout.tsx","./src/organizationpage.tsx","./src/main.tsx","./src/schema.ts","./src/vite-env.d.ts","./src/components/createorganization.tsx","./src/components/createproject.tsx","./src/components/errors.tsx","./src/components/heading.tsx","./src/components/invitelink.tsx","./src/components/organizationform.tsx","./src/components/organizationmembers.tsx","./src/components/organizationselector.tsx"],"version":"5.6.3"}
|
||||
@@ -1,5 +1,18 @@
|
||||
# passkey-svelte
|
||||
|
||||
## 0.0.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- jazz-svelte@0.10.7
|
||||
|
||||
## 0.0.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-svelte@0.10.6
|
||||
|
||||
## 0.0.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "passkey-svelte",
|
||||
"version": "0.0.38",
|
||||
"version": "0.0.40",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# minimal-auth-passkey
|
||||
|
||||
## 0.0.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 0.0.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
|
||||
## 0.0.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "passkey",
|
||||
"private": true,
|
||||
"version": "0.0.48",
|
||||
"version": "0.0.50",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# passphrase
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
|
||||
## 0.0.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "passphrase",
|
||||
"private": true,
|
||||
"version": "0.0.45",
|
||||
"version": "0.0.47",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# jazz-password-manager
|
||||
|
||||
## 0.0.71
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 0.0.70
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
|
||||
## 0.0.69
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-password-manager",
|
||||
"private": true,
|
||||
"version": "0.0.69",
|
||||
"version": "0.0.71",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -12,8 +12,8 @@
|
||||
"clean-install": "rm -rf node_modules pnpm-lock.yaml && pnpm install"
|
||||
},
|
||||
"dependencies": {
|
||||
"jazz-react": "workspace:0.10.5",
|
||||
"jazz-tools": "workspace:0.10.5",
|
||||
"jazz-react": "workspace:0.10.7",
|
||||
"jazz-tools": "workspace:0.10.7",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hook-form": "^7.41.5",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# jazz-example-pets
|
||||
|
||||
## 0.0.169
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-browser-media-images@0.10.7
|
||||
|
||||
## 0.0.168
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-browser-media-images@0.10.6
|
||||
|
||||
## 0.0.167
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-pets",
|
||||
"private": true,
|
||||
"version": "0.0.167",
|
||||
"version": "0.0.169",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -10,8 +10,8 @@
|
||||
"format-and-lint:fix": "biome check . --write",
|
||||
"preview": "vite preview",
|
||||
"sync": "jazz-run sync",
|
||||
"test": "playwright test",
|
||||
"test:ui": "playwright test --ui"
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:ui": "playwright test --ui"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
@@ -19,9 +19,9 @@
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"jazz-browser-media-images": "workspace:0.10.5",
|
||||
"jazz-react": "workspace:0.10.5",
|
||||
"jazz-tools": "workspace:0.10.5",
|
||||
"jazz-browser-media-images": "workspace:0.10.7",
|
||||
"jazz-react": "workspace:0.10.7",
|
||||
"jazz-tools": "workspace:0.10.7",
|
||||
"lucide-react": "^0.274.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"react": "^18.3.1",
|
||||
@@ -41,7 +41,7 @@
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"is-ci": "^3.0.1",
|
||||
"jazz-run": "workspace:0.10.5",
|
||||
"jazz-run": "workspace:0.10.7",
|
||||
"postcss": "^8.4.27",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "~5.6.2",
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# reactions
|
||||
|
||||
## 0.0.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-browser-media-images@0.10.7
|
||||
|
||||
## 0.0.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- hash-slash@0.2.2
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-browser-media-images@0.10.6
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "reactions",
|
||||
"private": true,
|
||||
"version": "0.0.47",
|
||||
"version": "0.0.49",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# todo-vue
|
||||
|
||||
## 0.0.54
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [bf76d79]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-browser@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
- jazz-vue@0.10.7
|
||||
|
||||
## 0.0.53
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-tools@0.10.6
|
||||
- jazz-browser@0.10.6
|
||||
- jazz-vue@0.10.6
|
||||
|
||||
## 0.0.52
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "todo-vue",
|
||||
"version": "0.0.52",
|
||||
"version": "0.0.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# jazz-example-todo
|
||||
|
||||
## 0.0.168
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 0.0.167
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
|
||||
## 0.0.166
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-todo",
|
||||
"private": true,
|
||||
"version": "0.0.166",
|
||||
"version": "0.0.168",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -16,8 +16,8 @@
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"jazz-react": "workspace:0.10.5",
|
||||
"jazz-tools": "workspace:0.10.5",
|
||||
"jazz-react": "workspace:0.10.7",
|
||||
"jazz-tools": "workspace:0.10.7",
|
||||
"lucide-react": "^0.274.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"react": "^18.3.1",
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# version-history
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1136d9b]
|
||||
- Updated dependencies [0eed228]
|
||||
- jazz-react@0.10.7
|
||||
- jazz-tools@0.10.7
|
||||
|
||||
## 0.0.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1d71ca1]
|
||||
- Updated dependencies [ada802b]
|
||||
- jazz-react@0.10.6
|
||||
- jazz-tools@0.10.6
|
||||
|
||||
## 0.0.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "version-history",
|
||||
"private": true,
|
||||
"version": "0.0.44",
|
||||
"version": "0.0.46",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
6
flake.lock
generated
6
flake.lock
generated
@@ -20,11 +20,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1737885589,
|
||||
"narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=",
|
||||
"lastModified": 1739580444,
|
||||
"narHash": "sha256-+/bSz4EAVbqz8/HsIGLroF8aNaO8bLRL7WfACN+24g4=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8",
|
||||
"rev": "8bb37161a0488b89830168b81c48aed11569cb93",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -16,15 +16,19 @@
|
||||
{
|
||||
devShells.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
# General development
|
||||
git
|
||||
turbo
|
||||
|
||||
# JS development
|
||||
nodejs_22
|
||||
nodePackages.pnpm
|
||||
git
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
echo ""
|
||||
echo "Welcome to the Jazz development environment!"
|
||||
echo "Run 'pnpm install' to install the dependencies."
|
||||
echo "Run 'pnpm install' to install dependencies."
|
||||
echo ""
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
ChevronRight,
|
||||
CodeIcon,
|
||||
CopyIcon,
|
||||
FileLock2Icon,
|
||||
FileTextIcon,
|
||||
FingerprintIcon,
|
||||
FolderArchiveIcon,
|
||||
@@ -61,6 +62,7 @@ const icons = {
|
||||
newsletter: MailIcon,
|
||||
offline: WifiOffIcon,
|
||||
package: BoxIcon,
|
||||
permissions: FileLock2Icon,
|
||||
social: UsersIcon,
|
||||
spatialPresence: MousePointerSquareDashedIcon,
|
||||
tableOfContents: ScrollIcon,
|
||||
@@ -117,7 +119,7 @@ export function Icon({
|
||||
className?: string;
|
||||
} & React.SVGProps<SVGSVGElement>) {
|
||||
if (!icon && (!name || !icons.hasOwnProperty(name))) {
|
||||
throw new Error(`Icon not found`);
|
||||
throw new Error(`Icon not found: ${name}`);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
|
||||
@@ -36,7 +36,9 @@ export function Footer({
|
||||
<div className="container grid gap-8 md:gap-12">
|
||||
<div className="grid grid-cols-12 gap-y-3 sm:items-center pb-8 border-b">
|
||||
<div className="col-span-full sm:col-span-6 md:col-span-8">
|
||||
{logo}
|
||||
<Link href="https://garden.co" target="_blank">
|
||||
{logo}
|
||||
</Link>
|
||||
</div>
|
||||
<p className="col-span-full sm:col-span-6 md:col-span-4 text-sm sm:text-base">
|
||||
Playful software for serious problems.
|
||||
|
||||
@@ -47,12 +47,7 @@ Many of the packages provided are documented in the [API Reference](/api-referen
|
||||
|
||||
## LLM Docs
|
||||
|
||||
We support the [llms.txt](https://llmstxt.org/) convention for making documentation available to large language models and the applications that make use of them.
|
||||
|
||||
We currently have:
|
||||
|
||||
- [/llms.txt](/llms.txt) - A overview listing of the available packages and their documentation
|
||||
- [/llms-full.txt](/llms-full.txt) - Full documentation for our packages
|
||||
Get better results with AI by [importing the Jazz docs](/docs/ai-tools) into your context window.
|
||||
|
||||
## Get support
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { ContentByFramework, FileDownloadLink, CodeGroup } from '@/components/forMdx'
|
||||
|
||||
# Using AI to build Jazz apps
|
||||
|
||||
AI tools, particularly large language models (LLMs), can accelerate your development with Jazz. Searching docs, responding to questions and even helping you write code are all things that LLMs are starting to get good at.
|
||||
|
||||
However, Jazz is a rapidly evolving framework, so sometimes AI might get things a little wrong.
|
||||
|
||||
To help the LLMs, we provide the Jazz documentation in a txt file that is optimized for use with AI tools, like Cursor.
|
||||
|
||||
<FileDownloadLink href="/llms-full.txt">llms-full.txt</FileDownloadLink>
|
||||
|
||||
## Setting up AI tools
|
||||
|
||||
Every tool is different, but generally, you'll need to either paste the contents of the [llms-full.txt](https://jazz.tools/llms-full.txt) file directly in your prompt, or attach the file to the tool.
|
||||
|
||||
### ChatGPT and v0
|
||||
|
||||
Upload the txt file in your prompt.
|
||||
|
||||

|
||||
|
||||
### Cursor
|
||||
|
||||
1. Go to Settings > Cursor Settings > Features > Docs
|
||||
2. Click "Add new doc"
|
||||
3. Enter the following URL:
|
||||
|
||||
<CodeGroup>
|
||||
```
|
||||
https://jazz.tools/llms-full.txt
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## llms.txt convention
|
||||
|
||||
We follow the llms.txt [proposed standard](https://llmstxt.org/) for providing documentation to AI tools at inference time that helps them understand the context of the code you're writing.
|
||||
|
||||
## Limitations and considerations
|
||||
|
||||
AI is amazing, but it's not perfect. What works well this week could break next week (or be twice as good).
|
||||
|
||||
We're keen to keep up with changes in tooling to help support you building the best apps, but if you need help from humans (or you have issues getting set up), please let us know on [Discord](https://discord.gg/utDMjHYg42).
|
||||
@@ -34,15 +34,17 @@ Tested with:
|
||||
|
||||
<CodeGroup>
|
||||
```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
|
||||
npx expo install expo-linking expo-secure-store expo-file-system @react-native-community/netinfo @bam.tech/react-native-image-resizer
|
||||
|
||||
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 @azure/core-asynciterator-polyfill react-native-url-polyfill readable-stream react-native-get-random-values @craftzdog/react-native-buffer @op-engineering/op-sqlite
|
||||
|
||||
npm i -S jazz-tools jazz-react-native jazz-react-native-media-images
|
||||
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
> note: Hermes has added support for `atob` and `btoa` in React Native 0.74. If you are using earlier versions, you may also need to polyfill `atob` and `btoa` in your `package.json` . Packages to try include `text-encoding` and `base-64`, and you can drop `@bacons/text-decoder`.
|
||||
|
||||
### Fix incompatible dependencies
|
||||
|
||||
<CodeGroup>
|
||||
@@ -134,16 +136,21 @@ For more information, refer to [this](https://github.com/byCedric/expo-monorepo-
|
||||
Create a file `polyfills.js` at the project root with the following content:
|
||||
|
||||
<CodeGroup>
|
||||
```ts
|
||||
import "react-native-polyfill-globals/auto";
|
||||
import "@azure/core-asynciterator-polyfill";
|
||||
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
|
||||
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
|
||||
import { Buffer } from "buffer";
|
||||
```js
|
||||
import { polyfillGlobal } from 'react-native/Libraries/Utilities/PolyfillFunctions';
|
||||
|
||||
polyfillGlobal("Buffer", () => Buffer);
|
||||
polyfillGlobal("ReadableStream", () => ReadableStream);
|
||||
```
|
||||
import { Buffer } from '@craftzdog/react-native-buffer';
|
||||
polyfillGlobal('Buffer', () => Buffer);
|
||||
|
||||
import { ReadableStream } from 'readable-stream';
|
||||
polyfillGlobal('ReadableStream', () => ReadableStream);
|
||||
|
||||
import '@azure/core-asynciterator-polyfill';
|
||||
|
||||
import '@bacons/text-decoder/install';
|
||||
|
||||
import 'react-native-get-random-values';
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Update `index.js` based on whether you are using expo-router or not:
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Pizzazz } from "@/components/Pizzazz";
|
||||
import { JazzNav } from "@/components/nav";
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -10,7 +9,6 @@ export default function RootLayout({
|
||||
<div className="flex-1 w-full">
|
||||
<JazzNav />
|
||||
<main>{children}</main>
|
||||
<Pizzazz />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
31
homepage/homepage/components/FileDownloadLink.tsx
Normal file
31
homepage/homepage/components/FileDownloadLink.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { AnchorHTMLAttributes, DetailedHTMLProps } from "react";
|
||||
|
||||
import { Button } from "gcmp-design-system/src/app/components/atoms/Button";
|
||||
import { Icon } from "gcmp-design-system/src/app/components/atoms/Icon";
|
||||
|
||||
export function FileDownloadLink(
|
||||
props: DetailedHTMLProps<
|
||||
AnchorHTMLAttributes<HTMLAnchorElement>,
|
||||
HTMLAnchorElement
|
||||
>,
|
||||
) {
|
||||
if (!props.href) {
|
||||
return props.children;
|
||||
}
|
||||
|
||||
const { children, href } = props;
|
||||
|
||||
return (
|
||||
<div className="inline-flex items-center font-medium text-stone-900 rounded-md border p-3 shadow-sm dark:text-white dark:bg-stone-925 flex py-2 rounded-lg ">
|
||||
<Icon name="file" size="sm" className="mr-2" />
|
||||
{children}
|
||||
|
||||
<a href={href} download className="ml-12">
|
||||
Download
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
"use client";
|
||||
import { addPizzazz } from "@unicorn-poo/pizzazz";
|
||||
|
||||
import { useEffect } from "react";
|
||||
|
||||
export function Pizzazz() {
|
||||
useEffect(() => {
|
||||
addPizzazz(document?.body, { effectType: "valentines" });
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
} from "@/components/docs/ContentByFramework";
|
||||
import { JazzLogo as JazzLogoClient } from "gcmp-design-system/src/app/components/atoms/logos/JazzLogo";
|
||||
import { CodeGroup as CodeGroupClient } from "gcmp-design-system/src/app/components/molecules/CodeGroup";
|
||||
import { AnchorHTMLAttributes, DetailedHTMLProps } from "react";
|
||||
import { FileDownloadLink as FileDownloadLinkClient } from "./FileDownloadLink";
|
||||
import { ComingSoon as ComingSoonClient } from "./docs/ComingSoon";
|
||||
import { IssueTrackerPreview as IssueTrackerPreviewClient } from "./docs/IssueTrackerPreview";
|
||||
|
||||
@@ -35,3 +37,12 @@ export function IssueTrackerPreview() {
|
||||
export function JazzLogo(props: { className?: string }) {
|
||||
return <JazzLogoClient {...props} />;
|
||||
}
|
||||
|
||||
export function FileDownloadLink(
|
||||
props: DetailedHTMLProps<
|
||||
AnchorHTMLAttributes<HTMLAnchorElement>,
|
||||
HTMLAnchorElement
|
||||
>,
|
||||
) {
|
||||
return <FileDownloadLinkClient {...props} />;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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,
|
||||
|
||||
@@ -229,7 +229,10 @@ async function readMdxContent(url) {
|
||||
const relativePath = url.replace(/^\/docs\/?/, "");
|
||||
|
||||
// Base directory for docs
|
||||
const baseDir = path.join(process.cwd(), "app/docs/[framework]/[...slug]");
|
||||
const baseDir = path.join(
|
||||
process.cwd(),
|
||||
"app/(docs)/docs/[framework]/[...slug]",
|
||||
);
|
||||
|
||||
// If it's a directory, try to read all framework variants
|
||||
const fullPath = path.join(baseDir, relativePath);
|
||||
@@ -300,7 +303,6 @@ async function generateDetailedDocs(docs) {
|
||||
for (const page of section.pages) {
|
||||
output.push(`#### ${page.title}\n`);
|
||||
const content = await readMdxContent(page.url);
|
||||
console.log(content);
|
||||
if (content) {
|
||||
// If the content contains framework-specific implementations, they're already properly formatted
|
||||
// Otherwise, just add the content directly
|
||||
@@ -498,7 +500,9 @@ async function generateDetailedDocs(docs) {
|
||||
"- [Examples](https://jazz.tools/examples): Code examples and tutorials\n",
|
||||
);
|
||||
|
||||
await writeDocsFile("llms-full.txt", output.join("\n"));
|
||||
const content = output.join("\n");
|
||||
await writeDocsFile("llms.txt", content);
|
||||
await writeDocsFile("llms-full.txt", content);
|
||||
}
|
||||
|
||||
// Main execution
|
||||
|
||||
24
homepage/homepage/generate-docs/llms-full.test.mjs
Normal file
24
homepage/homepage/generate-docs/llms-full.test.mjs
Normal file
@@ -0,0 +1,24 @@
|
||||
import assert from "node:assert";
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { test } from "node:test";
|
||||
|
||||
test("Size test", async () => {
|
||||
const filePath = path.join(process.cwd(), "public", "llms-full.txt");
|
||||
const stats = await fs.stat(filePath);
|
||||
assert.ok(
|
||||
stats.size > 100 * 1024,
|
||||
"llms-full.txt should be larger than 100kb", // Somewhat arbitrary, but it's a good sanity check
|
||||
);
|
||||
});
|
||||
|
||||
test("Content test", async () => {
|
||||
const filePath = path.join(process.cwd(), "public", "llms-full.txt");
|
||||
const content = await fs.readFile(filePath, "utf-8");
|
||||
assert.ok(
|
||||
content.includes(
|
||||
'Jazz authentication is based on cryptographic keys ("Account keys").',
|
||||
),
|
||||
"Should contain authentication message", // From authentication, it's unlikely to change much
|
||||
);
|
||||
});
|
||||
@@ -1,80 +0,0 @@
|
||||
import { Deserializer } from "typedoc";
|
||||
import { DOC_SECTIONS, PACKAGES } from "./utils/config.mjs";
|
||||
import {
|
||||
cleanDescription,
|
||||
loadTypedocFiles,
|
||||
writeDocsFile,
|
||||
} from "./utils/index.mjs";
|
||||
|
||||
async function generateConciseDocs(docs) {
|
||||
const output = [];
|
||||
const deserializer = new Deserializer();
|
||||
|
||||
// Project title
|
||||
output.push("# Jazz\n");
|
||||
|
||||
// Documentation sections
|
||||
output.push("## Documentation\n");
|
||||
DOC_SECTIONS.forEach((section) => {
|
||||
output.push(`### ${section.title}\n`);
|
||||
section.pages.forEach((page) => {
|
||||
output.push(`- [${page.title}](https://jazz.tools${page.url})\n`);
|
||||
});
|
||||
output.push("\n");
|
||||
});
|
||||
|
||||
// API Reference by package
|
||||
for (const [packageName, packageDocs] of Object.entries(docs)) {
|
||||
const project = deserializer.reviveProject(packageDocs, packageName);
|
||||
|
||||
// Add package heading
|
||||
output.push(`## ${packageName}\n`);
|
||||
|
||||
// Process each category and its exports with direct links
|
||||
if (project.categories) {
|
||||
const seen = new Set(); // Track seen names to avoid duplicates
|
||||
project.categories.forEach((category) => {
|
||||
category.children.forEach((child) => {
|
||||
if (seen.has(child.name)) return;
|
||||
seen.add(child.name);
|
||||
|
||||
// Get and clean up description
|
||||
let description = child.comment?.summary
|
||||
? cleanDescription(child.comment.summary)
|
||||
: "";
|
||||
|
||||
// Truncate description if it's too long
|
||||
if (description && description.length > 150) {
|
||||
description = description.substring(0, 147) + "...";
|
||||
}
|
||||
|
||||
// Create the line without wrapping
|
||||
output.push(
|
||||
`- [${child.name}](https://jazz.tools/api-reference/${packageName}#${child.name})${description ? `: ${description}` : ""}\n`,
|
||||
);
|
||||
});
|
||||
});
|
||||
output.push("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Optional section for additional resources
|
||||
output.push("## Optional\n");
|
||||
output.push(
|
||||
"- [Documentation](https://jazz.tools/docs): Detailed documentation about Jazz\n",
|
||||
);
|
||||
output.push(
|
||||
"- [Examples](https://jazz.tools/examples): Code examples and tutorials\n",
|
||||
);
|
||||
|
||||
await writeDocsFile("llms.txt", output.join(""));
|
||||
}
|
||||
|
||||
// Main execution
|
||||
async function main() {
|
||||
console.log("Generating concise LLM docs...");
|
||||
const docs = await loadTypedocFiles();
|
||||
await generateConciseDocs(docs);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -24,6 +24,11 @@ export const docNavigationItems = [
|
||||
href: "/examples",
|
||||
done: 30,
|
||||
},
|
||||
{
|
||||
name: "AI tools",
|
||||
href: "/docs/ai-tools",
|
||||
done: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { DEFAULT_FRAMEWORK, isValidFramework } from "@/lib/framework";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
export const useFramework = () => {
|
||||
const pathname = usePathname();
|
||||
const framework = pathname.startsWith("/docs/")
|
||||
? pathname.split("/")[2]
|
||||
: null;
|
||||
const { framework } = useParams<{ framework?: string }>();
|
||||
|
||||
return framework && isValidFramework(framework)
|
||||
? framework
|
||||
: DEFAULT_FRAMEWORK;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { DocsLink } from "@/components/docs/DocsLink";
|
||||
import type { MDXComponents } from "mdx/types";
|
||||
|
||||
export function useMDXComponents(components: MDXComponents): MDXComponents {
|
||||
return {
|
||||
a: (props) => <DocsLink {...props} />,
|
||||
...components,
|
||||
CodeWithInterpolation: ({
|
||||
highlightedCode,
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "NODE_OPTIONS=--max-old-space-size=8192 next dev",
|
||||
"build:generate-docs": "pnpm run generate:docs && pnpm run generate:llm-docs:all",
|
||||
"build:generate-docs": "pnpm run generate:docs && pnpm run generate:llm-docs",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"format-and-lint": "biome check .",
|
||||
"format-and-lint:fix": "biome check . --write",
|
||||
"generate:docs": "node generate-docs/typedocs.mjs --build",
|
||||
"generate:llm-docs:all": "pnpm run generate:llm-docs:concise && pnpm run generate:llm-docs:full",
|
||||
"generate:llm-docs:concise": "node generate-docs/llms.mjs",
|
||||
"generate:llm-docs:full": "node generate-docs/llms-full.mjs"
|
||||
"generate:llm-docs": "node generate-docs/llms-full.mjs",
|
||||
"test": "pnpm run test:llm-docs",
|
||||
"test:llm-docs": "node generate-docs/llms-full.test.mjs"
|
||||
},
|
||||
"packageManager": "pnpm@9.14.0",
|
||||
"dependencies": {
|
||||
@@ -27,7 +27,6 @@
|
||||
"@turf/turf": "^7.1.0",
|
||||
"@types/mdx": "^2.0.8",
|
||||
"@types/topojson-client": "^3.1.5",
|
||||
"@unicorn-poo/pizzazz": "^1.0.13",
|
||||
"@vercel/analytics": "^1.3.1",
|
||||
"@vercel/speed-insights": "^1.0.12",
|
||||
"clsx": "^2.1.1",
|
||||
|
||||
BIN
homepage/homepage/public/chatgpt-with-llms-full-txt.jpg
Normal file
BIN
homepage/homepage/public/chatgpt-with-llms-full-txt.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
@@ -7,7 +7,7 @@
|
||||
},
|
||||
"build:generate-docs": {
|
||||
"inputs": ["../../../packages/*/src/**"],
|
||||
"outputs": ["typedoc/**"],
|
||||
"outputs": ["typedoc/**", "public/llms.txt", "public/llms-full.txt"],
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"dev": {
|
||||
|
||||
9
homepage/pnpm-lock.yaml
generated
9
homepage/pnpm-lock.yaml
generated
@@ -205,9 +205,6 @@ importers:
|
||||
'@types/topojson-client':
|
||||
specifier: ^3.1.5
|
||||
version: 3.1.5
|
||||
'@unicorn-poo/pizzazz':
|
||||
specifier: ^1.0.13
|
||||
version: 1.0.13
|
||||
'@vercel/analytics':
|
||||
specifier: ^1.3.1
|
||||
version: 1.3.1(next@14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
@@ -1326,10 +1323,6 @@ packages:
|
||||
'@typescript/vfs@1.3.5':
|
||||
resolution: {integrity: sha512-pI8Saqjupf9MfLw7w2+og+fmb0fZS0J6vsKXXrp4/PDXEFvntgzXmChCXC/KefZZS0YGS6AT8e0hGAJcTsdJlg==}
|
||||
|
||||
'@unicorn-poo/pizzazz@1.0.13':
|
||||
resolution: {integrity: sha512-vw4sHhGBD5R6gJlaW3QEcXBsKOQ4w7WMCmw/0ef5x4ie3u1tqK/3j/pMhxinu2ahatdgoEK7lSO/2qAfYicwhA==}
|
||||
engines: {node: '>=14.0.0', npm: '>=6.0.0'}
|
||||
|
||||
'@vercel/analytics@1.3.1':
|
||||
resolution: {integrity: sha512-xhSlYgAuJ6Q4WQGkzYTLmXwhYl39sWjoMA3nHxfkvG+WdBT25c563a7QhwwKivEOZtPJXifYHR1m2ihoisbWyA==}
|
||||
peerDependencies:
|
||||
@@ -4691,8 +4684,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@unicorn-poo/pizzazz@1.0.13': {}
|
||||
|
||||
'@vercel/analytics@1.3.1(next@14.2.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
server-only: 0.0.1
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
"lefthook": "^1.8.2",
|
||||
"pkg-pr-new": "^0.0.39",
|
||||
"playwright": "^1.50.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"turbo": "^2.3.1",
|
||||
"typedoc": "^0.25.13",
|
||||
"vitest": "3.0.5"
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# cojson-storage-indexeddb
|
||||
|
||||
## 0.10.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1e625f3: Improve rollback on error when failing to add new content
|
||||
- Updated dependencies [0f83320]
|
||||
- Updated dependencies [012022d]
|
||||
- Updated dependencies [1e625f3]
|
||||
- cojson@0.10.7
|
||||
- cojson-storage@0.10.7
|
||||
|
||||
## 0.10.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5c76e37]
|
||||
- cojson@0.10.6
|
||||
- cojson-storage@0.10.6
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cojson-storage-indexeddb",
|
||||
"version": "0.10.4",
|
||||
"version": "0.10.7",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"types": "src/index.ts",
|
||||
|
||||
111
packages/cojson-storage-indexeddb/src/CoJsonIDBTransaction.ts
Normal file
111
packages/cojson-storage-indexeddb/src/CoJsonIDBTransaction.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
export type StoreName =
|
||||
| "coValues"
|
||||
| "sessions"
|
||||
| "transactions"
|
||||
| "signatureAfter";
|
||||
|
||||
// A access unit for the IndexedDB Jazz database
|
||||
// It's a wrapper around the IDBTransaction object that helps on batching multiple operations
|
||||
// in a single transaction.
|
||||
export class CoJsonIDBTransaction {
|
||||
db: IDBDatabase;
|
||||
tx: IDBTransaction;
|
||||
|
||||
pendingRequests: ((txEntry: this) => void)[] = [];
|
||||
rejectHandlers: (() => void)[] = [];
|
||||
|
||||
id = Math.random();
|
||||
|
||||
running = false;
|
||||
failed = false;
|
||||
done = false;
|
||||
|
||||
constructor(db: IDBDatabase) {
|
||||
this.db = db;
|
||||
|
||||
this.tx = this.db.transaction(
|
||||
["coValues", "sessions", "transactions", "signatureAfter"],
|
||||
"readwrite",
|
||||
);
|
||||
|
||||
this.tx.oncomplete = () => {
|
||||
this.done = true;
|
||||
};
|
||||
this.tx.onabort = () => {
|
||||
this.done = true;
|
||||
};
|
||||
}
|
||||
|
||||
startedAt = performance.now();
|
||||
isReusable() {
|
||||
const delta = performance.now() - this.startedAt;
|
||||
return !this.done && delta <= 20;
|
||||
}
|
||||
|
||||
getObjectStore(name: StoreName) {
|
||||
return this.tx.objectStore(name);
|
||||
}
|
||||
|
||||
private pushRequest<T>(
|
||||
handler: (txEntry: this, next: () => void) => Promise<T>,
|
||||
) {
|
||||
const next = () => {
|
||||
const next = this.pendingRequests.shift();
|
||||
|
||||
if (next) {
|
||||
next(this);
|
||||
} else {
|
||||
this.running = false;
|
||||
this.done = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (this.running) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.rejectHandlers.push(reject);
|
||||
this.pendingRequests.push(async () => {
|
||||
try {
|
||||
const result = await handler(this, next);
|
||||
resolve(result);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.running = true;
|
||||
return handler(this, next);
|
||||
}
|
||||
|
||||
handleRequest<T>(handler: (txEntry: this) => IDBRequest<T>) {
|
||||
return this.pushRequest<T>((txEntry, next) => {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
const request = handler(txEntry);
|
||||
|
||||
request.onerror = () => {
|
||||
this.failed = true;
|
||||
this.tx.abort();
|
||||
console.error(request.error);
|
||||
reject(request.error);
|
||||
|
||||
// Don't leave any pending promise
|
||||
for (const handler of this.rejectHandlers) {
|
||||
handler();
|
||||
}
|
||||
};
|
||||
|
||||
request.onsuccess = () => {
|
||||
resolve(request.result as T);
|
||||
next();
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
commit() {
|
||||
if (!this.done) {
|
||||
this.tx.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CojsonInternalTypes, RawCoID } from "cojson";
|
||||
import type { CojsonInternalTypes, RawCoID, SessionID } from "cojson";
|
||||
import type {
|
||||
CoValueRow,
|
||||
DBClientInterface,
|
||||
@@ -8,119 +8,60 @@ import type {
|
||||
StoredSessionRow,
|
||||
TransactionRow,
|
||||
} from "cojson-storage";
|
||||
import { SyncPromise } from "./syncPromises.js";
|
||||
import { CoJsonIDBTransaction } from "./CoJsonIDBTransaction.js";
|
||||
|
||||
export class IDBClient implements DBClientInterface {
|
||||
private db;
|
||||
|
||||
currentTx:
|
||||
| {
|
||||
id: number;
|
||||
tx: IDBTransaction;
|
||||
stores: {
|
||||
coValues: IDBObjectStore;
|
||||
sessions: IDBObjectStore;
|
||||
transactions: IDBObjectStore;
|
||||
signatureAfter: IDBObjectStore;
|
||||
};
|
||||
startedAt: number;
|
||||
pendingRequests: ((txEntry: {
|
||||
stores: {
|
||||
coValues: IDBObjectStore;
|
||||
sessions: IDBObjectStore;
|
||||
transactions: IDBObjectStore;
|
||||
signatureAfter: IDBObjectStore;
|
||||
};
|
||||
}) => void)[];
|
||||
}
|
||||
| undefined;
|
||||
|
||||
currentTxID = 0;
|
||||
activeTransaction: CoJsonIDBTransaction | undefined;
|
||||
autoBatchingTransaction: CoJsonIDBTransaction | undefined;
|
||||
|
||||
constructor(db: IDBDatabase) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
makeRequest<T>(
|
||||
handler: (stores: {
|
||||
coValues: IDBObjectStore;
|
||||
sessions: IDBObjectStore;
|
||||
transactions: IDBObjectStore;
|
||||
signatureAfter: IDBObjectStore;
|
||||
}) => IDBRequest,
|
||||
): SyncPromise<T> {
|
||||
return new SyncPromise((resolve, reject) => {
|
||||
let txEntry = this.currentTx;
|
||||
handler: (txEntry: CoJsonIDBTransaction) => IDBRequest<T>,
|
||||
): Promise<T> {
|
||||
if (this.activeTransaction) {
|
||||
return this.activeTransaction.handleRequest<T>(handler);
|
||||
}
|
||||
|
||||
const requestEntry = ({
|
||||
stores,
|
||||
}: {
|
||||
stores: {
|
||||
coValues: IDBObjectStore;
|
||||
sessions: IDBObjectStore;
|
||||
transactions: IDBObjectStore;
|
||||
signatureAfter: IDBObjectStore;
|
||||
};
|
||||
}) => {
|
||||
const request = handler(stores);
|
||||
request.onerror = () => {
|
||||
console.error("Error in request", request.error);
|
||||
this.currentTx = undefined;
|
||||
reject(request.error);
|
||||
};
|
||||
request.onsuccess = () => {
|
||||
const value = request.result as T;
|
||||
resolve(value);
|
||||
if (this.autoBatchingTransaction?.isReusable()) {
|
||||
return this.autoBatchingTransaction.handleRequest<T>(handler);
|
||||
}
|
||||
|
||||
const next = txEntry?.pendingRequests.shift();
|
||||
const tx = new CoJsonIDBTransaction(this.db);
|
||||
|
||||
if (next) {
|
||||
next({ stores });
|
||||
} else {
|
||||
if (this.currentTx === txEntry) {
|
||||
this.currentTx = undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
this.autoBatchingTransaction = tx;
|
||||
|
||||
// Transaction batching
|
||||
if (!txEntry || performance.now() - txEntry.startedAt > 20) {
|
||||
const tx = this.db.transaction(
|
||||
["coValues", "sessions", "transactions", "signatureAfter"],
|
||||
"readwrite",
|
||||
);
|
||||
txEntry = {
|
||||
id: this.currentTxID++,
|
||||
tx,
|
||||
stores: {
|
||||
coValues: tx.objectStore("coValues"),
|
||||
sessions: tx.objectStore("sessions"),
|
||||
transactions: tx.objectStore("transactions"),
|
||||
signatureAfter: tx.objectStore("signatureAfter"),
|
||||
},
|
||||
startedAt: performance.now(),
|
||||
pendingRequests: [],
|
||||
};
|
||||
|
||||
this.currentTx = txEntry;
|
||||
|
||||
requestEntry(txEntry);
|
||||
} else {
|
||||
txEntry.pendingRequests.push(requestEntry);
|
||||
}
|
||||
});
|
||||
return tx.handleRequest<T>(handler);
|
||||
}
|
||||
|
||||
async getCoValue(coValueId: RawCoID): Promise<StoredCoValueRow | undefined> {
|
||||
return this.makeRequest<StoredCoValueRow | undefined>(({ coValues }) =>
|
||||
coValues.index("coValuesById").get(coValueId),
|
||||
return this.makeRequest<StoredCoValueRow | undefined>((tx) =>
|
||||
tx.getObjectStore("coValues").index("coValuesById").get(coValueId),
|
||||
);
|
||||
}
|
||||
|
||||
async getCoValueSessions(coValueRowId: number): Promise<StoredSessionRow[]> {
|
||||
return this.makeRequest<StoredSessionRow[]>(({ sessions }) =>
|
||||
sessions.index("sessionsByCoValue").getAll(coValueRowId),
|
||||
return this.makeRequest<StoredSessionRow[]>((tx) =>
|
||||
tx
|
||||
.getObjectStore("sessions")
|
||||
.index("sessionsByCoValue")
|
||||
.getAll(coValueRowId),
|
||||
);
|
||||
}
|
||||
|
||||
async getSingleCoValueSession(
|
||||
coValueRowId: number,
|
||||
sessionID: SessionID,
|
||||
): Promise<StoredSessionRow | undefined> {
|
||||
return this.makeRequest<StoredSessionRow>((tx) =>
|
||||
tx
|
||||
.getObjectStore("sessions")
|
||||
.index("uniqueSessions")
|
||||
.get([coValueRowId, sessionID]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -128,13 +69,15 @@ export class IDBClient implements DBClientInterface {
|
||||
sessionRowId: number,
|
||||
firstNewTxIdx: number,
|
||||
): Promise<TransactionRow[]> {
|
||||
return this.makeRequest<TransactionRow[]>(({ transactions }) =>
|
||||
transactions.getAll(
|
||||
IDBKeyRange.bound(
|
||||
[sessionRowId, firstNewTxIdx],
|
||||
[sessionRowId, Number.POSITIVE_INFINITY],
|
||||
return this.makeRequest<TransactionRow[]>((tx) =>
|
||||
tx
|
||||
.getObjectStore("transactions")
|
||||
.getAll(
|
||||
IDBKeyRange.bound(
|
||||
[sessionRowId, firstNewTxIdx],
|
||||
[sessionRowId, Number.POSITIVE_INFINITY],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -142,9 +85,10 @@ export class IDBClient implements DBClientInterface {
|
||||
sessionRowId: number,
|
||||
firstNewTxIdx: number,
|
||||
): Promise<SignatureAfterRow[]> {
|
||||
return this.makeRequest<SignatureAfterRow[]>(
|
||||
({ signatureAfter }: { signatureAfter: IDBObjectStore }) =>
|
||||
signatureAfter.getAll(
|
||||
return this.makeRequest<SignatureAfterRow[]>((tx) =>
|
||||
tx
|
||||
.getObjectStore("signatureAfter")
|
||||
.getAll(
|
||||
IDBKeyRange.bound(
|
||||
[sessionRowId, firstNewTxIdx],
|
||||
[sessionRowId, Number.POSITIVE_INFINITY],
|
||||
@@ -160,8 +104,8 @@ export class IDBClient implements DBClientInterface {
|
||||
throw new Error(`Header is required, coId: ${msg.id}`);
|
||||
}
|
||||
|
||||
return (await this.makeRequest<IDBValidKey>(({ coValues }) =>
|
||||
coValues.put({
|
||||
return (await this.makeRequest<IDBValidKey>((tx) =>
|
||||
tx.getObjectStore("coValues").put({
|
||||
id: msg.id,
|
||||
// biome-ignore lint/style/noNonNullAssertion: TODO(JAZZ-561): Review
|
||||
header: msg.header!,
|
||||
@@ -176,25 +120,26 @@ export class IDBClient implements DBClientInterface {
|
||||
sessionUpdate: SessionRow;
|
||||
sessionRow?: StoredSessionRow;
|
||||
}): Promise<number> {
|
||||
return this.makeRequest<number>(({ sessions }) =>
|
||||
sessions.put(
|
||||
sessionRow?.rowID
|
||||
? {
|
||||
rowID: sessionRow.rowID,
|
||||
...sessionUpdate,
|
||||
}
|
||||
: sessionUpdate,
|
||||
),
|
||||
return this.makeRequest<number>(
|
||||
(tx) =>
|
||||
tx.getObjectStore("sessions").put(
|
||||
sessionRow?.rowID
|
||||
? {
|
||||
rowID: sessionRow.rowID,
|
||||
...sessionUpdate,
|
||||
}
|
||||
: sessionUpdate,
|
||||
) as IDBRequest<number>,
|
||||
);
|
||||
}
|
||||
|
||||
addTransaction(
|
||||
async addTransaction(
|
||||
sessionRowID: number,
|
||||
idx: number,
|
||||
newTransaction: CojsonInternalTypes.Transaction,
|
||||
) {
|
||||
return this.makeRequest(({ transactions }) =>
|
||||
transactions.add({
|
||||
await this.makeRequest((tx) =>
|
||||
tx.getObjectStore("transactions").add({
|
||||
ses: sessionRowID,
|
||||
idx,
|
||||
tx: newTransaction,
|
||||
@@ -211,8 +156,8 @@ export class IDBClient implements DBClientInterface {
|
||||
idx: number;
|
||||
signature: CojsonInternalTypes.Signature;
|
||||
}) {
|
||||
return this.makeRequest(({ signatureAfter }) =>
|
||||
signatureAfter.put({
|
||||
return this.makeRequest((tx) =>
|
||||
tx.getObjectStore("signatureAfter").put({
|
||||
ses: sessionRowID,
|
||||
idx,
|
||||
signature,
|
||||
@@ -220,7 +165,24 @@ export class IDBClient implements DBClientInterface {
|
||||
);
|
||||
}
|
||||
|
||||
async unitOfWork(operationsCallback: () => unknown[]) {
|
||||
return Promise.all(operationsCallback());
|
||||
closeTransaction(tx: CoJsonIDBTransaction) {
|
||||
tx.commit();
|
||||
|
||||
if (tx === this.activeTransaction) {
|
||||
this.activeTransaction = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async transaction(operationsCallback: () => unknown) {
|
||||
const tx = new CoJsonIDBTransaction(this.db);
|
||||
|
||||
this.activeTransaction = tx;
|
||||
|
||||
try {
|
||||
await operationsCallback();
|
||||
tx.commit(); // Tells the browser to not wait for another possible request and commit the transaction immediately
|
||||
} finally {
|
||||
this.activeTransaction = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,18 +33,7 @@ export class IDBNode {
|
||||
}
|
||||
await this.syncManager.handleSyncMessage(msg);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
const isFunction = (func: any) => typeof func === "function";
|
||||
|
||||
const isObject = (supposedObject: any) =>
|
||||
typeof supposedObject === "object" &&
|
||||
supposedObject !== null &&
|
||||
!Array.isArray(supposedObject);
|
||||
|
||||
const isThenable = (obj: any) => isObject(obj) && isFunction(obj.then);
|
||||
|
||||
const identity = (co: any) => co;
|
||||
|
||||
export { identity, isFunction, isObject, isThenable };
|
||||
|
||||
enum States {
|
||||
PENDING = "PENDING",
|
||||
RESOLVED = "RESOLVED",
|
||||
REJECTED = "REJECTED",
|
||||
}
|
||||
|
||||
interface Handler<T, U> {
|
||||
onSuccess: HandlerOnSuccess<T, U>;
|
||||
onFail: HandlerOnFail<U>;
|
||||
}
|
||||
|
||||
type HandlerOnSuccess<T, U = any> = (value: T) => U | Thenable<U>;
|
||||
type HandlerOnFail<U = any> = (reason: any) => U | Thenable<U>;
|
||||
type Finally<U> = () => U | Thenable<U>;
|
||||
|
||||
interface Thenable<T> {
|
||||
then<U>(
|
||||
onSuccess?: HandlerOnSuccess<T, U>,
|
||||
onFail?: HandlerOnFail<U>,
|
||||
): Thenable<U>;
|
||||
then<U>(
|
||||
onSuccess?: HandlerOnSuccess<T, U>,
|
||||
onFail?: (reason: any) => void,
|
||||
): Thenable<U>;
|
||||
}
|
||||
|
||||
type Resolve<R> = (value?: R | Thenable<R>) => void;
|
||||
type Reject = (value?: any) => void;
|
||||
|
||||
export class SyncPromise<T> {
|
||||
private state: States = States.PENDING;
|
||||
private handlers: Handler<T, any>[] = [];
|
||||
private value: T | any;
|
||||
|
||||
public constructor(callback: (resolve: Resolve<T>, reject: Reject) => void) {
|
||||
try {
|
||||
callback(this.resolve as Resolve<T>, this.reject);
|
||||
} catch (e) {
|
||||
this.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
private resolve = (value: T) => {
|
||||
return this.setResult(value, States.RESOLVED);
|
||||
};
|
||||
|
||||
private reject = (reason: any) => {
|
||||
return this.setResult(reason, States.REJECTED);
|
||||
};
|
||||
|
||||
private setResult = (value: T | any, state: States) => {
|
||||
const set = () => {
|
||||
if (this.state !== States.PENDING) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isThenable(value)) {
|
||||
return (value as Thenable<T>).then(this.resolve, this.reject);
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
this.state = state;
|
||||
|
||||
return this.executeHandlers();
|
||||
};
|
||||
|
||||
void set();
|
||||
};
|
||||
|
||||
private executeHandlers = () => {
|
||||
if (this.state === States.PENDING) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const handler of this.handlers) {
|
||||
if (this.state === States.REJECTED) {
|
||||
handler.onFail(this.value);
|
||||
} else {
|
||||
handler.onSuccess(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
this.handlers = [];
|
||||
};
|
||||
|
||||
private attachHandler = (handler: Handler<T, any>) => {
|
||||
this.handlers = [...this.handlers, handler];
|
||||
|
||||
this.executeHandlers();
|
||||
};
|
||||
|
||||
// biome-ignore lint/suspicious/noThenProperty: TODO(JAZZ-561): Review
|
||||
public then<U>(onSuccess: HandlerOnSuccess<T, U>, onFail?: HandlerOnFail<U>) {
|
||||
return new SyncPromise<U>((resolve, reject) => {
|
||||
return this.attachHandler({
|
||||
onSuccess: (result) => {
|
||||
try {
|
||||
return resolve(onSuccess(result));
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
},
|
||||
onFail: (reason) => {
|
||||
if (!onFail) {
|
||||
return reject(reason);
|
||||
}
|
||||
|
||||
try {
|
||||
return resolve(onFail(reason));
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public catch<U>(onFail: HandlerOnFail<U>) {
|
||||
return this.then<U>(identity, onFail);
|
||||
}
|
||||
|
||||
// methods
|
||||
|
||||
public toString() {
|
||||
return "[object SyncPromise]";
|
||||
}
|
||||
|
||||
public finally<U>(cb: Finally<U>) {
|
||||
return new SyncPromise<U>((resolve, reject) => {
|
||||
let co: U | any;
|
||||
let isRejected: boolean;
|
||||
|
||||
return this.then(
|
||||
(value) => {
|
||||
isRejected = false;
|
||||
co = value;
|
||||
return cb();
|
||||
},
|
||||
(reason) => {
|
||||
isRejected = true;
|
||||
co = reason;
|
||||
return cb();
|
||||
},
|
||||
).then(() => {
|
||||
if (isRejected) {
|
||||
return reject(co);
|
||||
}
|
||||
|
||||
return resolve(co);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public spread<U>(handler: (...args: any[]) => U) {
|
||||
return this.then<U>((collection) => {
|
||||
if (Array.isArray(collection)) {
|
||||
return handler(...collection);
|
||||
}
|
||||
|
||||
return handler(collection);
|
||||
});
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
public static resolve<U = any>(value?: U | Thenable<U>) {
|
||||
return new SyncPromise<U>((resolve) => {
|
||||
return resolve(value);
|
||||
});
|
||||
}
|
||||
|
||||
public static reject<U>(reason?: any) {
|
||||
return new SyncPromise<U>((_resolve, reject) => {
|
||||
return reject(reason);
|
||||
});
|
||||
}
|
||||
|
||||
public static all<U = any>(collection: (U | Thenable<U>)[]) {
|
||||
return new SyncPromise<U[]>((resolve, reject) => {
|
||||
if (!Array.isArray(collection)) {
|
||||
return reject(new TypeError("An array must be provided."));
|
||||
}
|
||||
|
||||
if (collection.length === 0) {
|
||||
return resolve([]);
|
||||
}
|
||||
|
||||
let counter = collection.length;
|
||||
const resolvedCollection: U[] = [];
|
||||
|
||||
const tryResolve = (value: U, index: number) => {
|
||||
counter -= 1;
|
||||
resolvedCollection[index] = value;
|
||||
|
||||
if (counter !== 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return resolve(resolvedCollection);
|
||||
};
|
||||
|
||||
return collection.forEach((item, index) => {
|
||||
return SyncPromise.resolve(item)
|
||||
.then((value) => {
|
||||
return tryResolve(value, index);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
||||
import { CoJsonIDBTransaction } from "../CoJsonIDBTransaction";
|
||||
|
||||
const TEST_DB_NAME = "test-cojson-idb-transaction";
|
||||
|
||||
describe("CoJsonIDBTransaction", () => {
|
||||
let db: IDBDatabase;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create test database
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const request = indexedDB.open(TEST_DB_NAME, 1);
|
||||
|
||||
request.onerror = () => reject(request.error);
|
||||
|
||||
request.onupgradeneeded = (event) => {
|
||||
const db = request.result;
|
||||
// Create test stores
|
||||
db.createObjectStore("coValues", { keyPath: "id" });
|
||||
const sessions = db.createObjectStore("sessions", { keyPath: "id" });
|
||||
sessions.createIndex("uniqueSessions", ["coValue", "sessionID"], {
|
||||
unique: true,
|
||||
});
|
||||
db.createObjectStore("transactions", { keyPath: "id" });
|
||||
db.createObjectStore("signatureAfter", { keyPath: "id" });
|
||||
};
|
||||
|
||||
request.onsuccess = () => {
|
||||
db = request.result;
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Close and delete test database
|
||||
db.close();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const request = indexedDB.deleteDatabase(TEST_DB_NAME);
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve();
|
||||
});
|
||||
});
|
||||
|
||||
test("handles successful write and read operations", async () => {
|
||||
const tx = new CoJsonIDBTransaction(db);
|
||||
|
||||
// Write test
|
||||
await tx.handleRequest((tx) =>
|
||||
tx.getObjectStore("coValues").put({
|
||||
id: "test1",
|
||||
value: "hello",
|
||||
}),
|
||||
);
|
||||
|
||||
// Read test
|
||||
const readTx = new CoJsonIDBTransaction(db);
|
||||
const result = await readTx.handleRequest((tx) =>
|
||||
tx.getObjectStore("coValues").get("test1"),
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
id: "test1",
|
||||
value: "hello",
|
||||
});
|
||||
});
|
||||
|
||||
test("handles multiple operations in single transaction", async () => {
|
||||
const tx = new CoJsonIDBTransaction(db);
|
||||
|
||||
// Multiple writes
|
||||
await Promise.all([
|
||||
tx.handleRequest((tx) =>
|
||||
tx.getObjectStore("coValues").put({
|
||||
id: "test1",
|
||||
value: "hello",
|
||||
}),
|
||||
),
|
||||
tx.handleRequest((tx) =>
|
||||
tx.getObjectStore("coValues").put({
|
||||
id: "test2",
|
||||
value: "world",
|
||||
}),
|
||||
),
|
||||
]);
|
||||
|
||||
// Read results
|
||||
const readTx = new CoJsonIDBTransaction(db);
|
||||
const [result1, result2] = await Promise.all([
|
||||
readTx.handleRequest((tx) => tx.getObjectStore("coValues").get("test1")),
|
||||
readTx.handleRequest((tx) => tx.getObjectStore("coValues").get("test2")),
|
||||
]);
|
||||
|
||||
expect(result1).toEqual({
|
||||
id: "test1",
|
||||
value: "hello",
|
||||
});
|
||||
expect(result2).toEqual({
|
||||
id: "test2",
|
||||
value: "world",
|
||||
});
|
||||
});
|
||||
|
||||
test("handles transaction across multiple stores", async () => {
|
||||
const tx = new CoJsonIDBTransaction(db);
|
||||
|
||||
await Promise.all([
|
||||
tx.handleRequest((tx) =>
|
||||
tx.getObjectStore("coValues").put({
|
||||
id: "value1",
|
||||
data: "value data",
|
||||
}),
|
||||
),
|
||||
tx.handleRequest((tx) =>
|
||||
tx.getObjectStore("sessions").put({
|
||||
id: "session1",
|
||||
data: "session data",
|
||||
}),
|
||||
),
|
||||
]);
|
||||
|
||||
const readTx = new CoJsonIDBTransaction(db);
|
||||
const [valueResult, sessionResult] = await Promise.all([
|
||||
readTx.handleRequest((tx) => tx.getObjectStore("coValues").get("value1")),
|
||||
readTx.handleRequest((tx) =>
|
||||
tx.getObjectStore("sessions").get("session1"),
|
||||
),
|
||||
]);
|
||||
|
||||
expect(valueResult).toEqual({
|
||||
id: "value1",
|
||||
data: "value data",
|
||||
});
|
||||
expect(sessionResult).toEqual({
|
||||
id: "session1",
|
||||
data: "session data",
|
||||
});
|
||||
});
|
||||
|
||||
test("handles failed transactions", async () => {
|
||||
const tx = new CoJsonIDBTransaction(db);
|
||||
|
||||
await expect(
|
||||
tx.handleRequest((tx) =>
|
||||
tx.getObjectStore("sessions").put({
|
||||
id: 1,
|
||||
coValue: "value1",
|
||||
sessionID: "session1",
|
||||
data: "session data",
|
||||
}),
|
||||
),
|
||||
).resolves.toBe(1);
|
||||
|
||||
expect(tx.failed).toBe(false);
|
||||
|
||||
const badTx = new CoJsonIDBTransaction(db);
|
||||
await expect(
|
||||
badTx.handleRequest((tx) =>
|
||||
tx.getObjectStore("sessions").put({
|
||||
id: 2,
|
||||
coValue: "value1",
|
||||
sessionID: "session1",
|
||||
data: "session data",
|
||||
}),
|
||||
),
|
||||
).rejects.toThrow();
|
||||
|
||||
expect(badTx.failed).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,24 @@
|
||||
# cojson-storage-sqlite
|
||||
|
||||
## 0.8.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1e625f3: Improve rollback on error when failing to add new content
|
||||
- Updated dependencies [0f83320]
|
||||
- Updated dependencies [012022d]
|
||||
- Updated dependencies [1e625f3]
|
||||
- cojson@0.10.7
|
||||
- cojson-storage@0.10.7
|
||||
|
||||
## 0.8.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5c76e37]
|
||||
- cojson@0.10.6
|
||||
- cojson-storage@0.10.6
|
||||
|
||||
## 0.8.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "cojson-storage-rn-sqlite",
|
||||
"type": "module",
|
||||
"version": "0.8.63",
|
||||
"version": "0.8.65",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { type DB as DatabaseT } from "@op-engineering/op-sqlite";
|
||||
import { CojsonInternalTypes, type OutgoingSyncQueue, RawCoID } from "cojson";
|
||||
import {
|
||||
CojsonInternalTypes,
|
||||
type OutgoingSyncQueue,
|
||||
RawCoID,
|
||||
SessionID,
|
||||
} from "cojson";
|
||||
import type {
|
||||
DBClientInterface,
|
||||
SessionRow,
|
||||
@@ -48,6 +53,17 @@ export class SQLiteClient implements DBClientInterface {
|
||||
return rows as StoredSessionRow[];
|
||||
}
|
||||
|
||||
async getSingleCoValueSession(
|
||||
coValueRowId: number,
|
||||
sessionID: SessionID,
|
||||
): Promise<StoredSessionRow | undefined> {
|
||||
const { rows } = await this.db.execute(
|
||||
"SELECT * FROM sessions WHERE coValue = ? AND sessionID = ?",
|
||||
[coValueRowId, sessionID],
|
||||
);
|
||||
return rows[0] as StoredSessionRow | undefined;
|
||||
}
|
||||
|
||||
async getNewTransactionInSession(
|
||||
sessionRowId: number,
|
||||
firstNewTxIdx: number,
|
||||
@@ -142,12 +158,10 @@ export class SQLiteClient implements DBClientInterface {
|
||||
);
|
||||
}
|
||||
|
||||
async unitOfWork(
|
||||
operationsCallback: () => Promise<unknown>[],
|
||||
): Promise<void> {
|
||||
async transaction(operationsCallback: () => unknown) {
|
||||
try {
|
||||
await this.db.transaction(async () => {
|
||||
await Promise.all(operationsCallback());
|
||||
await operationsCallback();
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Transaction failed:", e);
|
||||
|
||||
@@ -42,18 +42,6 @@ export class SQLiteReactNative {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# cojson-storage-sqlite
|
||||
|
||||
## 0.10.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1e625f3: Improve rollback on error when failing to add new content
|
||||
- Updated dependencies [0f83320]
|
||||
- Updated dependencies [012022d]
|
||||
- Updated dependencies [1e625f3]
|
||||
- cojson@0.10.7
|
||||
- cojson-storage@0.10.7
|
||||
|
||||
## 0.10.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5c76e37]
|
||||
- cojson@0.10.6
|
||||
- cojson-storage@0.10.6
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "cojson-storage-sqlite",
|
||||
"type": "module",
|
||||
"version": "0.10.4",
|
||||
"version": "0.10.7",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"better-sqlite3": "^11.7.0",
|
||||
"cojson": "workspace:0.10.4",
|
||||
"cojson": "workspace:0.10.7",
|
||||
"cojson-storage": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -71,6 +71,17 @@ export class SQLiteClient implements DBClientInterface {
|
||||
.all(coValueRowId) as StoredSessionRow[];
|
||||
}
|
||||
|
||||
getSingleCoValueSession(
|
||||
coValueRowId: number,
|
||||
sessionID: SessionID,
|
||||
): StoredSessionRow | undefined {
|
||||
return this.db
|
||||
.prepare<[number, string]>(
|
||||
`SELECT * FROM sessions WHERE coValue = ? AND sessionID = ?`,
|
||||
)
|
||||
.get(coValueRowId, sessionID) as StoredSessionRow | undefined;
|
||||
}
|
||||
|
||||
getNewTransactionInSession(
|
||||
sessionRowId: number,
|
||||
firstNewTxIdx: number,
|
||||
@@ -159,7 +170,7 @@ export class SQLiteClient implements DBClientInterface {
|
||||
.run(sessionRowID, idx, signature);
|
||||
}
|
||||
|
||||
unitOfWork(operationsCallback: () => any[]) {
|
||||
transaction(operationsCallback: () => unknown) {
|
||||
this.db.transaction(operationsCallback)();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# cojson-storage
|
||||
|
||||
## 0.10.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1e625f3: Improve rollback on error when failing to add new content
|
||||
- Updated dependencies [0f83320]
|
||||
- Updated dependencies [012022d]
|
||||
- cojson@0.10.7
|
||||
|
||||
## 0.10.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5c76e37]
|
||||
- cojson@0.10.6
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cojson-storage",
|
||||
"version": "0.10.4",
|
||||
"version": "0.10.7",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"types": "src/index.ts",
|
||||
|
||||
@@ -200,15 +200,6 @@ export class SyncManager {
|
||||
? coValueRow.rowID
|
||||
: await this.dbClient.addCoValue(msg);
|
||||
|
||||
const allOurSessionsEntries =
|
||||
await this.dbClient.getCoValueSessions(storedCoValueRowID);
|
||||
|
||||
const allOurSessions: {
|
||||
[sessionID: SessionID]: StoredSessionRow;
|
||||
} = Object.fromEntries(
|
||||
allOurSessionsEntries.map((row) => [row.sessionID, row]),
|
||||
);
|
||||
|
||||
const ourKnown: CojsonInternalTypes.CoValueKnownState = {
|
||||
id: msg.id,
|
||||
header: true,
|
||||
@@ -217,9 +208,13 @@ export class SyncManager {
|
||||
|
||||
let invalidAssumptions = false;
|
||||
|
||||
await this.dbClient.unitOfWork(() =>
|
||||
(Object.keys(msg.new) as SessionID[]).map((sessionID) => {
|
||||
const sessionRow = allOurSessions[sessionID];
|
||||
for (const sessionID of Object.keys(msg.new) as SessionID[]) {
|
||||
await this.dbClient.transaction(async () => {
|
||||
const sessionRow = await this.dbClient.getSingleCoValueSession(
|
||||
storedCoValueRowID,
|
||||
sessionID,
|
||||
);
|
||||
|
||||
if (sessionRow) {
|
||||
ourKnown.sessions[sessionRow.sessionID] = sessionRow.lastIdx;
|
||||
}
|
||||
@@ -229,8 +224,8 @@ export class SyncManager {
|
||||
} else {
|
||||
return this.putNewTxs(msg, sessionID, sessionRow, storedCoValueRowID);
|
||||
}
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (invalidAssumptions) {
|
||||
this.sendStateMessage({
|
||||
|
||||
@@ -45,9 +45,11 @@ describe("DB sync manager", () => {
|
||||
const DBClient = vi.fn();
|
||||
DBClient.prototype.getCoValue = vi.fn();
|
||||
DBClient.prototype.getCoValueSessions = vi.fn();
|
||||
DBClient.prototype.getSingleCoValueSession = vi.fn();
|
||||
DBClient.prototype.getNewTransactionInSession = vi.fn();
|
||||
DBClient.prototype.addSessionUpdate = vi.fn();
|
||||
DBClient.prototype.addTransaction = vi.fn();
|
||||
DBClient.prototype.unitOfWork = vi.fn((callback) => Promise.all(callback()));
|
||||
DBClient.prototype.transaction = vi.fn((callback) => callback());
|
||||
|
||||
beforeEach(async () => {
|
||||
const idbClient = new DBClient() as unknown as Mocked<DBClientInterface>;
|
||||
|
||||
@@ -41,6 +41,11 @@ export interface DBClientInterface {
|
||||
coValueRowId: number,
|
||||
): Promise<StoredSessionRow[]> | StoredSessionRow[];
|
||||
|
||||
getSingleCoValueSession(
|
||||
coValueRowId: number,
|
||||
sessionID: SessionID,
|
||||
): Promise<StoredSessionRow | undefined> | StoredSessionRow | undefined;
|
||||
|
||||
getNewTransactionInSession(
|
||||
sessionRowId: number,
|
||||
firstNewTxIdx: number,
|
||||
@@ -79,5 +84,5 @@ export interface DBClientInterface {
|
||||
signature: Signature;
|
||||
}): Promise<number> | void | unknown;
|
||||
|
||||
unitOfWork(operationsCallback: () => unknown[]): Promise<unknown> | void;
|
||||
transaction(callback: () => unknown): Promise<unknown> | void;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# cojson-transport-nodejs-ws
|
||||
|
||||
## 0.10.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [0f83320]
|
||||
- Updated dependencies [012022d]
|
||||
- cojson@0.10.7
|
||||
|
||||
## 0.10.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5c76e37]
|
||||
- cojson@0.10.6
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "cojson-transport-ws",
|
||||
"type": "module",
|
||||
"version": "0.10.4",
|
||||
"version": "0.10.7",
|
||||
"main": "dist/index.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# cojson
|
||||
|
||||
## 0.10.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 0f83320: Use jazz-crypto-rs isomorphic bundle
|
||||
- 012022d: Improve error logging on sync errors
|
||||
|
||||
## 0.10.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 5c76e37: Ports Wasm crypto functions to use exported library `jazz-crypto-rs`
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -25,20 +25,19 @@
|
||||
},
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "0.10.4",
|
||||
"version": "0.10.7",
|
||||
"devDependencies": {
|
||||
"@opentelemetry/sdk-metrics": "^1.29.0",
|
||||
"typescript": "~5.6.2",
|
||||
"vitest": "3.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hazae41/berith": "^1.2.6",
|
||||
"@noble/ciphers": "^0.1.3",
|
||||
"@noble/curves": "^1.3.0",
|
||||
"@noble/hashes": "^1.4.0",
|
||||
"@opentelemetry/api": "^1.0.0",
|
||||
"@scure/base": "1.2.1",
|
||||
"hash-wasm": "^4.9.0",
|
||||
"jazz-crypto-rs": "0.0.6",
|
||||
"neverthrow": "^7.0.1",
|
||||
"queueueue": "^4.1.2"
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user