Compare commits

..

84 Commits

Author SHA1 Message Date
Guido D'Orsi
3baa951bb9 Merge pull request #1424 from garden-co/changeset-release/main
Version Packages
2025-02-20 14:46:21 +01:00
github-actions[bot]
b726e31669 Version Packages 2025-02-20 13:44:04 +00:00
Guido D'Orsi
63bb31e0ad Merge pull request #1431 from garden-co/auth-state-sync
fix: isAuthenticated out-of-sync with the account state
2025-02-20 14:42:07 +01:00
Guido D'Orsi
d059460abd Merge pull request #1414 from garden-co/fix/examples-auth
Remove log out button in form and image upload example
2025-02-20 14:32:12 +01:00
Guido D'Orsi
ba81951331 test: fix the mobile e2e tests 2025-02-20 14:22:21 +01:00
Guido D'Orsi
bd132bb9ad Merge pull request #1437 from garden-co/feat/enable-cmd-j-default
enable Cmd+J by default to launch inspector on dev
2025-02-20 14:10:31 +01:00
Benjamin S. Leveritt
1ee435ad95 Merge pull request #1439 from garden-co/feat/big-llms-txt
Make llms.txt more complete
2025-02-20 12:51:42 +00:00
Guido D'Orsi
646ad330ae Merge pull request #1430 from garden-co/tests/cloudflare
test: add a cloudflare workers integration test
2025-02-20 13:06:58 +01:00
Guido D'Orsi
af8e6e3f82 chore: inline callbacks
Co-authored-by: Giordano Ricci <me@giordanoricci.com>
2025-02-20 13:05:05 +01:00
Guido D'Orsi
f247525dfe test: fix cloudflare tests on CI 2025-02-20 13:01:42 +01:00
Guido D'Orsi
012022db2b chore: changeset 2025-02-20 12:46:58 +01:00
Guido D'Orsi
da92891498 test: add cloudflare integration tests 2025-02-20 12:46:24 +01:00
Guido D'Orsi
b0c55720f8 feat: crypto option to provide PureJSCrypto on the runtimes where wasm is not supported 2025-02-20 12:45:59 +01:00
Trisha Lim
a3d825fc6f make llms.txt more complete 2025-02-20 18:34:01 +07:00
Guido D'Orsi
29ca2e6f65 update lockfile again 2025-02-20 12:07:29 +01:00
Guido D'Orsi
07a683c13d chore: remove cloudflare tests for compat issues with Vitest 3 2025-02-20 12:07:28 +01:00
Guido D'Orsi
e53f02d6d7 chore: update lockfile and format vitest config 2025-02-20 12:07:28 +01:00
Guido D'Orsi
4915bfa26d test: add a cloudflare workers integration test 2025-02-20 12:07:27 +01:00
Guido D'Orsi
af45aac5f2 feat: improve error logging on sync errors 2025-02-20 12:07:27 +01:00
Guido D'Orsi
1136d9b744 chore: changeset 2025-02-20 12:01:35 +01:00
Guido D'Orsi
92e78dc262 chore: clean up debug code 2025-02-20 11:54:57 +01:00
Trisha Lim
bf76d798c4 add changeset 2025-02-20 17:54:21 +07:00
Benjamin S. Leveritt
627f8c4c28 Merge pull request #1413 from garden-co/jazz-720-fix-jazz-crypto-rs-imports-for-nextjs
Bumps crypto version
2025-02-20 10:52:41 +00:00
Trisha Lim
a1e0410863 enable Cmd+J to launch inspector on dev 2025-02-20 17:52:41 +07:00
Guido D'Orsi
03897a2689 fix: clean up AuthSecretStorage notification management and fix the tests 2025-02-20 11:45:25 +01:00
Guido D'Orsi
823f546028 test: cover the logOut and authenticate updates with tests 2025-02-20 11:45:24 +01:00
Guido D'Orsi
9bc54d1939 chore: clean up the useCoState code 2025-02-20 11:45:24 +01:00
Guido D'Orsi
30780c05f0 fix: initial fix for logIn/logOut state sync 2025-02-20 11:45:24 +01:00
Guido D'Orsi
118b6294ac Merge pull request #1435 from garden-co/jazz-725-react-starter-profile-name-is-lost-on-signup
Fix wrong name field on form in starter app
2025-02-20 11:45:08 +01:00
Trisha Lim
6dc9b9d2ec Improve llms.txt documentation (#1436)
* Make download link to llms-full.txt more prominent

* add separate section for llms.txt convention
2025-02-20 17:41:38 +07:00
Benjamin S. Leveritt
ccbcee5102 Bumps crypto version 2025-02-20 10:41:31 +00:00
Giordano Ricci
0ae2067c3c Merge pull request #1403 from garden-co/gio/auth-fixes
fix: fixes clerk auth flow
2025-02-20 11:33:17 +01:00
Trisha Lim
2137938ead Fix wrong name field on form in starter app 2025-02-20 16:31:08 +07:00
Benjamin S. Leveritt
d14bb57ff5 Tweaks LLMs docs copy (#1423) 2025-02-20 11:17:19 +07:00
Giordano Ricci
3f42a4ddf9 add test 2025-02-19 15:25:02 +00:00
Giordano Ricci
0eed228170 add changeset 2025-02-19 14:32:48 +00:00
Giordano Ricci
a519537701 remove unused import 2025-02-19 13:52:14 +00:00
Giordano Ricci
43c79cac2a add simple test 2025-02-19 13:46:37 +00:00
Giordano Ricci
44dbaa00d4 revert wrong change 2025-02-19 12:12:01 +00:00
Giordano Ricci
a0df32e81a add types test 2025-02-19 12:08:42 +00:00
Giordano Ricci
236d8226d8 remove prevContext promise 2025-02-19 10:39:32 +00:00
Giordano Ricci
1220fa5d97 remove reset 2025-02-19 10:37:33 +00:00
Benjamin S. Leveritt
f3a5f83f25 Initializes the wasm module on creation 2025-02-19 10:36:29 +00:00
Benjamin S. Leveritt
a1bd6fc79b Bumps crypto version 2025-02-19 10:36:29 +00:00
Benjamin S. Leveritt
0f83320222 Chore: changeset 2025-02-19 10:36:29 +00:00
Benjamin S. Leveritt
a3c4067de3 Bumps crypto version 2025-02-19 10:36:29 +00:00
Benjamin S. Leveritt
3042627748 Merge pull request #1419 from garden-co/docs/llms
Add LLM page to docs
2025-02-19 10:18:44 +00:00
Guido D'Orsi
8cea1e96cf Merge pull request #1418 from garden-co/fix/idb-transactions
fix: improve the rollback on failure when handling new content in storage
2025-02-19 11:12:25 +01:00
Trisha Lim
64bb9ba90e Fix typo 2025-02-19 10:04:26 +00:00
Trisha Lim
f136dfe39b Update docs intro LLM section 2025-02-19 10:04:26 +00:00
Trisha Lim
b32ae6240c Use llms-full.txt, add chatgpt screenshot 2025-02-19 10:04:26 +00:00
Trisha Lim
fc4a89f77f Add llms section to docs 2025-02-19 10:04:26 +00:00
Guido D'Orsi
7a6f8db509 Merge pull request #1420 from garden-co/mini-inspector-improvements
[inspector] Add global search and json viewer
2025-02-19 10:42:28 +01:00
Guido D'Orsi
086b9af565 Merge pull request #1422 from garden-co/jazz-723-docs-intro-broken-links
Fix missing framework param in docs links
2025-02-19 08:56:12 +01:00
Trisha Lim
5e95d8b76e Refactor useFramework 2025-02-19 14:25:11 +07:00
Trisha Lim
47e0b68c2e Fix missing framework param in docs links 2025-02-19 14:22:04 +07:00
Giordano Ricci
5cc58c8e02 whoopsie 2025-02-18 22:40:01 +00:00
Giordano Ricci
9df644c578 fix 2025-02-18 22:35:35 +00:00
Tobias Lins
a20e430e7f Add global search and json viewer 2025-02-18 22:15:54 +01:00
Guido D'Orsi
1e625f3c12 chore: changeset 2025-02-18 18:14:39 +01:00
Guido D'Orsi
8b3686c7ce feat: use the uniqueSessions index to get the single coValue session 2025-02-18 18:12:47 +01:00
Guido D'Orsi
bce04ee06d chore: restore the transactions autobatching 2025-02-18 18:05:53 +01:00
Guido D'Orsi
f2e9115f4c fix: improve transactions management on IDB 2025-02-18 17:51:32 +01:00
Giordano Ricci
6854f9930c wip: fix clerk auth flow 2025-02-18 16:47:49 +00:00
Guido D'Orsi
ee0897d9a8 fix: improve the rollback on failure when handling new content in storage 2025-02-18 14:42:29 +01:00
Trisha Lim
243ab074eb Remove non-functional nav from image upload example 2025-02-18 20:21:55 +07:00
Trisha Lim
385659b243 Link to garden from footer 2025-02-18 18:32:43 +07:00
Trisha Lim
938f9256db Remove non-functional nav from form example 2025-02-18 15:31:53 +07:00
Anselm
88521721bf unpizzazz 😔 2025-02-17 20:35:01 +00:00
Guido D'Orsi
2701630582 Merge pull request #1385 from boorad/fix/rn-polyfills
fix: reduce RN polyfills
2025-02-17 18:50:22 +01:00
Guido D'Orsi
07ce619fa2 Merge pull request #1411 from garden-co/jazz-719-exclued-tsbuildinfo-files
Removes tsbuildinfo files from repo
2025-02-17 18:44:22 +01:00
Guido D'Orsi
895de1a470 Merge pull request #1372 from garden-co/jazz-705-rename-e2e-test-scripts
Jazz 705 rename e2e test scripts
2025-02-17 18:43:59 +01:00
Benjamin S. Leveritt
4450761a7b Removes tsbuildinfo files from repo 2025-02-17 17:14:02 +00:00
Benjamin S. Leveritt
08b3d65c0b Removes onboarding app 2025-02-17 17:08:28 +00:00
Benjamin S. Leveritt
5dac731f26 Gitignore test failure screenshots 2025-02-17 17:06:56 +00:00
Benjamin S. Leveritt
e99308cda2 Revert vite test workspace
...for now...
2025-02-17 17:05:10 +00:00
Benjamin S. Leveritt
44e1d140ca Builds dependencies for tests (rather than the package; read: faster) 2025-02-17 15:39:05 +00:00
Benjamin S. Leveritt
e0ef3fc1de Removes browser-integration from vite workspace
Vite treats it as a src package, and that breaks turbo's test task resolution (running tests at the root level). Vitest doesn't need it to be there to run the tests.
2025-02-17 15:39:05 +00:00
Benjamin S. Leveritt
a31ac66213 Fixes headless run of browser-integration tests 2025-02-17 15:39:05 +00:00
Benjamin S. Leveritt
b444b2e96a Renames e2e tests to separate from test task 2025-02-17 15:39:05 +00:00
Benjamin S. Leveritt
8fcc4b5e50 Runs turbo tests as in CI (ie. no watching) 2025-02-17 15:39:05 +00:00
Benjamin S. Leveritt
33bfbee9cf Removes unused test command 2025-02-17 15:39:05 +00:00
Benjamin S. Leveritt
d08e4e263b Fixes project jazz-auth-clerk name for tests 2025-02-17 15:39:05 +00:00
Brad Anderson
e6241dfb5a fix: reduce RN polyfills 2025-02-17 09:39:01 -05:00
185 changed files with 3253 additions and 1059 deletions

4
.gitignore vendored
View File

@@ -7,11 +7,15 @@ docsTmp
coverage
.direnv
# Typescript
**/*.tsbuildinfo
# Next.js
**/.next
# Vite output
**/dist
__screenshots__
# Playwright
test-results

View File

@@ -1,5 +1,16 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-clerk",
"main": "index.js",
"version": "1.0.71",
"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",

View File

@@ -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";

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.68",
"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",

View File

@@ -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";

View File

@@ -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"

View File

@@ -1,5 +1,16 @@
# 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

View File

@@ -1,6 +1,6 @@
{
"name": "chat-vue",
"version": "0.0.55",
"version": "0.0.56",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,15 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.151",
"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",

View File

@@ -1,5 +1,15 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.50",
"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.6",
"jazz-react-auth-clerk": "workspace:0.10.7",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.35",
"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",

View File

@@ -1,5 +1,15 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.0.46",
"version": "0.0.47",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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

View File

@@ -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"}

View File

@@ -1,5 +1,15 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "image-upload",
"private": true,
"version": "0.0.48",
"version": "0.0.49",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector-app",
"private": true,
"version": "0.0.107",
"version": "0.0.108",
"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",
"cojson": "workspace:0.10.6",
"cojson-transport-ws": "workspace:0.10.6",
"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",

View File

@@ -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);
}}
>

View File

@@ -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>
);

View File

@@ -1,5 +1,15 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.72",
"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.6",
"jazz-tools": "workspace:0.10.6",
"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",

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "organization",
"private": true,
"version": "0.0.44",
"version": "0.0.45",
"type": "module",
"scripts": {
"dev": "vite",

File diff suppressed because one or more lines are too long

View File

@@ -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"}

View File

@@ -1,5 +1,12 @@
# passkey-svelte
## 0.0.40
### Patch Changes
- Updated dependencies [1136d9b]
- jazz-svelte@0.10.7
## 0.0.39
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "passkey-svelte",
"version": "0.0.39",
"version": "0.0.40",
"type": "module",
"private": true,
"scripts": {

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "passkey",
"private": true,
"version": "0.0.49",
"version": "0.0.50",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "passphrase",
"private": true,
"version": "0.0.46",
"version": "0.0.47",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-password-manager",
"private": true,
"version": "0.0.70",
"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.6",
"jazz-tools": "workspace:0.10.6",
"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",

View File

@@ -1,5 +1,15 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.168",
"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.6",
"jazz-react": "workspace:0.10.6",
"jazz-tools": "workspace:0.10.6",
"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.6",
"jazz-run": "workspace:0.10.7",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2",

View File

@@ -1,5 +1,15 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "reactions",
"private": true,
"version": "0.0.48",
"version": "0.0.49",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,16 @@
# 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

View File

@@ -1,6 +1,6 @@
{
"name": "todo-vue",
"version": "0.0.53",
"version": "0.0.54",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.167",
"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.6",
"jazz-tools": "workspace:0.10.6",
"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",

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "version-history",
"private": true,
"version": "0.0.45",
"version": "0.0.46",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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.

View File

@@ -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

View File

@@ -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.
![ChatGPT prompt with llms-full.txt attached](/chatgpt-with-llms-full-txt.jpg)
### 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).

View File

@@ -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:

View File

@@ -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>
);
}

View 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>
);
}

View File

@@ -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;
}

View File

@@ -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} />;
}

View File

@@ -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,

View File

@@ -500,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

View File

@@ -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);

View File

@@ -24,6 +24,11 @@ export const docNavigationItems = [
href: "/examples",
done: 30,
},
{
name: "AI tools",
href: "/docs/ai-tools",
done: 100,
},
],
},
{

View File

@@ -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;

View File

@@ -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,

View File

@@ -5,15 +5,13 @@
"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"
},
@@ -29,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",

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -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

View File

@@ -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"

View File

@@ -1,5 +1,16 @@
# 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

View File

@@ -1,6 +1,6 @@
{
"name": "cojson-storage-indexeddb",
"version": "0.10.6",
"version": "0.10.7",
"main": "dist/index.js",
"type": "module",
"types": "src/index.ts",

View 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();
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
};

View File

@@ -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);
});
});
}
}

View File

@@ -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);
});
});

View File

@@ -1,5 +1,16 @@
# 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

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-storage-rn-sqlite",
"type": "module",
"version": "0.8.64",
"version": "0.8.65",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -1,5 +1,16 @@
# 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

View File

@@ -1,13 +1,13 @@
{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.10.6",
"version": "0.10.7",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"better-sqlite3": "^11.7.0",
"cojson": "workspace:0.10.6",
"cojson": "workspace:0.10.7",
"cojson-storage": "workspace:*"
},
"devDependencies": {

View File

@@ -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)();
}
}

View File

@@ -1,5 +1,14 @@
# 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

View File

@@ -1,6 +1,6 @@
{
"name": "cojson-storage",
"version": "0.10.6",
"version": "0.10.7",
"main": "dist/index.js",
"type": "module",
"types": "src/index.ts",

View File

@@ -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({

View File

@@ -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>;

View File

@@ -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;
}

View File

@@ -1,5 +1,13 @@
# cojson-transport-nodejs-ws
## 0.10.7
### Patch Changes
- Updated dependencies [0f83320]
- Updated dependencies [012022d]
- cojson@0.10.7
## 0.10.6
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-transport-ws",
"type": "module",
"version": "0.10.6",
"version": "0.10.7",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",

View File

@@ -1,5 +1,12 @@
# 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

View File

@@ -25,7 +25,7 @@
},
"type": "module",
"license": "MIT",
"version": "0.10.6",
"version": "0.10.7",
"devDependencies": {
"@opentelemetry/sdk-metrics": "^1.29.0",
"typescript": "~5.6.2",
@@ -37,7 +37,7 @@
"@noble/hashes": "^1.4.0",
"@opentelemetry/api": "^1.0.0",
"@scure/base": "1.2.1",
"jazz-crypto-rs": "0.0.3",
"jazz-crypto-rs": "0.0.6",
"neverthrow": "^7.0.1",
"queueueue": "^4.1.2"
},

View File

@@ -7,6 +7,7 @@ import {
encrypt,
get_sealer_id,
get_signer_id,
initialize,
new_ed25519_signing_key,
new_x25519_private_key,
seal,
@@ -49,6 +50,7 @@ export class WasmCrypto extends CryptoProvider<Blake3State> {
}
static async create(): Promise<WasmCrypto> {
await initialize();
return new WasmCrypto();
}

View File

@@ -341,20 +341,8 @@ export class SyncManager {
});
return;
}
try {
await this.handleSyncMessage(msg, peerState);
} catch (e) {
throw new Error(
`Error reading from peer ${
peer.id
}, handling msg\n\n${JSON.stringify(msg, (k, v) =>
k === "changes" || k === "encryptedChanges"
? v.slice(0, 20) + "..."
: v,
)}`,
{ cause: e },
);
}
await this.handleSyncMessage(msg, peerState);
}
};

View File

@@ -4,6 +4,7 @@ import { ControlledAgent } from "../coValues/account.js";
import { WasmCrypto } from "../crypto/WasmCrypto.js";
import { expectGroup } from "../typeUtils/expectGroup.js";
import {
connectTwoPeers,
createTwoConnectedNodes,
groupWithTwoAdmins,
groupWithTwoAdminsHighLevel,
@@ -2029,9 +2030,13 @@ test("Can give write permissions to 'everyone' (high-level)", async () => {
.getCurrentContent(),
);
connectTwoPeers(group.core.node, childContent2.core.node, "server", "server");
// Ensure that the group is available to newAccount
await group.core.waitForSync();
expect(childContent2.get("foo")).toEqual("bar");
console.log("Before anon set");
childContent2.set("foo", "bar2", "private");
expect(childContent2.get("foo")).toEqual("bar2");
});

View File

@@ -1,5 +1,20 @@
# jazz-browser-media-images
## 0.10.7
### Patch Changes
- 1136d9b: Fixed isAuthenticated out-of-sync with the account state during the logOut and authenticate flows
- 0eed228: Fixes clerk auth flow
- Updated dependencies [0f83320]
- Updated dependencies [012022d]
- Updated dependencies [1136d9b]
- Updated dependencies [bf76d79]
- Updated dependencies [0eed228]
- cojson@0.10.7
- jazz-browser@0.10.7
- jazz-tools@0.10.7
## 0.10.6
### Patch Changes

View File

@@ -1,22 +1,22 @@
{
"name": "jazz-auth-clerk",
"version": "0.10.6",
"version": "0.10.7",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"cojson": "workspace:0.10.6",
"jazz-browser": "workspace:0.10.6",
"jazz-tools": "workspace:0.10.6"
"cojson": "workspace:0.10.7",
"jazz-browser": "workspace:0.10.7",
"jazz-tools": "workspace:0.10.7"
},
"scripts": {
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"build": "rm -rf ./dist && tsc --sourceMap --outDir dist",
"prepublishOnly": "npm run build",
"test": "vitest --run --root ../../ --project jazz-browser-auth-clerk",
"test:watch": "vitest --watch --root ../../ --project jazz-browser-auth-clerk"
"test": "vitest --run --root ../../ --project jazz-auth-clerk",
"test:watch": "vitest --watch --root ../../ --project jazz-auth-clerk"
},
"devDependencies": {
"typescript": "~5.6.2"

Some files were not shown because too many files have changed in this diff Show More