Compare commits

...

45 Commits

Author SHA1 Message Date
pax-k
849c2b9ffc fix(useCoState): requested changes 2025-03-10 16:30:07 +02:00
pax-k
56860d406b chore: changeset 2025-02-28 13:12:48 +02:00
pax-k
357d1b4c8d fix: useCoState stale data 2025-02-28 13:11:47 +02:00
Guido D'Orsi
4373e290fe Merge pull request #1543 from garden-co/typecheck-tests
fix: include tests in the typescript validation on cojson and jazz-tools
2025-02-28 11:19:18 +01:00
Guido D'Orsi
037ed4d59d fix: include tests in the typescript validation on cojson and jazz-tools 2025-02-28 11:01:57 +01:00
Benjamin S. Leveritt
4fcc8edc70 Merge pull request #1539 from garden-co/1538-fix-linting-for-cojson-transport-ws
1538-fix-linting-for-cojson-transport-ws
2025-02-28 08:24:47 +00:00
Benjamin S. Leveritt
0f8ba9966b Fix resolve returning void (which biome doesn't like)
Closes #1538
2025-02-27 17:18:57 +00:00
Benjamin S. Leveritt
91fa2e092a Add comment about using any 2025-02-27 17:08:06 +00:00
Benjamin S. Leveritt
ff52d6df3e Adds linting to cojson-transport-ws
Fixes #1538
2025-02-27 17:08:06 +00:00
Benjamin S. Leveritt
a539b9e26b Merge pull request #1536 from garden-co/1533-fix-linting-for-cojson-storage-packages
Closes #1533
2025-02-27 17:05:44 +00:00
Benjamin S. Leveritt
f3129a7914 Fix return on transaction 2025-02-27 16:40:25 +00:00
Guido D'Orsi
d349b794e1 Merge pull request #1534 from boorad/feat/clerk-expo-offline
feat: Clerk and Expo offline support
2025-02-27 17:24:20 +01:00
Benjamin S. Leveritt
fad14dcff6 Fix imports in jazz-nodejs 2025-02-27 16:21:54 +00:00
Benjamin S. Leveritt
b99f13c948 Adds a few more tweaks to the linter, and fixes 2025-02-27 16:21:54 +00:00
Benjamin S. Leveritt
e7cb337a24 Fix linting issues in cojson-storage-rn-sqlite 2025-02-27 16:21:54 +00:00
Benjamin S. Leveritt
85c9a432c3 Adds linting checks and fixes to cojson-storage 2025-02-27 16:21:54 +00:00
Brad Anderson
c28d1c331c feat: Clerk and Expo offline support 2025-02-27 10:01:46 -05:00
Guido D'Orsi
474ea89b81 Merge pull request #1532 from juliusv/patch-2
Fix missing useAccount import + incorrect "old" marker in React guide
2025-02-27 15:10:48 +01:00
Julius Volz
4772309fb6 Fix missing useAccount import + incorrect "old" marker in React guide 2025-02-27 13:43:20 +01:00
pax
1501510cfc Merge pull request #1493 from garden-co/cursor-rules-with-create-jazz-app
Cursor rules with create-jazz-app
2025-02-27 12:09:01 +02:00
Guido D'Orsi
eda1588907 Merge pull request #1527 from garden-co/changeset-release/main
Version Packages
2025-02-27 09:56:16 +01:00
github-actions[bot]
b14e0bfe24 Version Packages 2025-02-26 17:58:41 +00:00
Guido D'Orsi
87aa43b46b Merge pull request #1507 from garden-co/jazz-747-passphrase-auth-restore-support-for-rerolling-the-passphrase
feat(PasskeyAuth): support random passphrase generation
2025-02-26 18:54:42 +01:00
Guido D'Orsi
b93ce9fb7e chore: rever to use property initializers 2025-02-26 18:54:32 +01:00
Guido D'Orsi
a7d83e1c10 feat(passphrase-example): inline the UI and implement the passphrase reroll flow 2025-02-26 16:29:05 +01:00
Guido D'Orsi
76a693da15 Update packages/jazz-tools/src/tests/PassphraseAuth.test.ts
Co-authored-by: Giordano Ricci <me@giordanoricci.com>
2025-02-26 16:23:02 +01:00
pax
df2f021cfd Merge pull request #1509 from garden-co/changeset-release/main
Version Packages
2025-02-26 16:25:01 +02:00
github-actions[bot]
50b15d2d1d Version Packages 2025-02-26 13:43:02 +00:00
pax
48bf7cb188 Merge pull request #1519 from garden-co/create-jazz-app-dev-deps-handling
fix(create-jazz-app): handle workspace devDependencies
2025-02-26 15:40:53 +02:00
pax-k
e2e0af34b5 chore: changeset 2025-02-26 15:04:57 +02:00
Trisha Lim
6a5bcd3063 Fix missing og meta tags 2025-02-26 19:34:15 +07:00
pax-k
bf7e62ec76 fix(create-jazz-app): handle workspace devDependencies 2025-02-26 11:58:44 +02:00
Guido D'Orsi
71dda6b10b docs(contributing): fix the build step 2025-02-25 21:33:35 +01:00
Emil Sayahi
4612e0545e fix: type inference on useCoState (#1489)
* fix: type inference on `useCoState`

The `id` parameter should be `ID<CoValue>` so the type inference picks up the CoValue type only from the `Schema` parameter.

See: #1476

* fix: type inference on loading & subscribing API

* test: add type inference `useCoState` tests

* chore: changeset
2025-02-25 10:35:53 -05:00
Guido D'Orsi
07feedd641 feat(PasskeyAuth): support random passphrase generation 2025-02-25 15:35:48 +01:00
Guido D'Orsi
edbd567f11 Merge pull request #1491 from garden-co/remove-neverthrow-from-agent
chore: remove neverthrow from the agent/sealer id getters
2025-02-25 15:22:07 +01:00
pax-k
6a8ce1e32d chore(create-jazz-app): only copy .cursor dir 2025-02-24 23:58:32 +02:00
pax-k
10a4b0e888 Merge branch 'main' into cursor-rules-with-create-jazz-app 2025-02-24 23:44:06 +02:00
pax-k
3c973c84ce fix(create-jazz-app): git init inside new project 2025-02-24 23:40:50 +02:00
pax-k
21e74998e8 fix(cursor-docs): markdown references to examples 2025-02-24 20:53:17 +02:00
pax-k
a2e9ae4731 chore: refactored cursor rule name 2025-02-24 20:47:39 +02:00
pax-k
0514a7e64b chore: run pre-publish workflow when PR labels change 2025-02-24 20:35:40 +02:00
pax-k
b063cccdfc chore: changeset 2025-02-24 19:16:37 +02:00
pax-k
d89d2978ff feat: added cursor-docs to create-jazz-app 2025-02-24 19:16:00 +02:00
Guido D'Orsi
221ca30790 chore: remove neverthrow from the agent/sealer id getters 2025-02-24 18:11:06 +01:00
135 changed files with 1820 additions and 459 deletions

View File

@@ -0,0 +1,5 @@
---
"jazz-react-core": patch
---
Fix useCoState stale data

View File

@@ -0,0 +1,5 @@
---
"create-jazz-app": patch
---
Added Cursor docs to create-jazz-app

View File

@@ -1,7 +1,7 @@
name: Pre-Publish tagged Pull Requests
on:
pull_request:
types: [opened, synchronize, reopened]
types: [opened, synchronize, reopened, labeled]
jobs:
pre-release:
@@ -99,4 +99,4 @@ jobs:
);
await logPublishInfo();
}
}
}

View File

@@ -36,7 +36,7 @@ We welcome all ideas! If you have suggestions, feel free to open an issue marked
### 5. Local Setup
You'll need Node.js 20.x or 22.x installed (we're working on support for 23.x), and pnpm 9.x installed. If you're using nix, run `nix develop` to get a shell with the correct versions of everything installed.
You'll need Node.js 22.x installed (we're working on support for 23.x), and pnpm 9.x installed. If you're using nix, run `nix develop` to get a shell with the correct versions of everything installed.
1. **Clone the repository**:
```bash
@@ -54,6 +54,12 @@ You'll need Node.js 20.x or 22.x installed (we're working on support for 23.x),
cd homepage && pnpm install
```
4. **Go back to the project root**:
```bash
cd ..
```
4. **Build the packages**:
```bash

View File

@@ -12,7 +12,9 @@
"**/ios/**",
"**/android/**",
"packages/jazz-svelte/**",
"examples/*svelte*/**"
"examples/*svelte*/**",
"homepage/homepage/**",
"**/package.json"
]
},
"formatter": {
@@ -42,15 +44,6 @@
}
},
"overrides": [
{
"include": ["**/package.json"],
"linter": {
"enabled": false
},
"formatter": {
"enabled": false
}
},
{
"include": ["packages/**/src/**"],
"linter": {
@@ -61,21 +54,24 @@
}
},
{
"include": ["packages/**/src/tests/**", "packages/**/src/test/**"],
"include": ["packages/cojson-storage*/**", "cojson-transport-ws/**"],
"linter": {
"enabled": true,
"rules": {
"correctness": {
"useImportExtensions": "off"
}
"recommended": true
}
}
},
{
"include": ["packages/cojson-storage-indexeddb/**"],
"include": ["packages/**/src/tests/**"],
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"useImportExtensions": "off"
},
"style": {
"noNonNullAssertion": "off"
},
"suspicious": {
"noExplicitAny": "info"
}

View File

@@ -1,5 +1,25 @@
# chat-rn-clerk
## 1.0.78
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react-native@0.10.13
- jazz-react-native-auth-clerk@0.10.13
- jazz-react-native-media-images@0.10.13
## 1.0.77
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react-native@0.10.12
- jazz-react-native-auth-clerk@0.10.12
- jazz-react-native-media-images@0.10.12
## 1.0.76
### Patch Changes

View File

@@ -1,5 +1,6 @@
import "../global.css";
import { ClerkLoaded, ClerkProvider } from "@clerk/clerk-expo";
import { secureStore } from "@clerk/clerk-expo/secure-store";
import { useFonts } from "expo-font";
import { Slot } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
@@ -33,7 +34,11 @@ export default function RootLayout() {
}
return (
<ClerkProvider tokenCache={tokenCache} publishableKey={publishableKey}>
<ClerkProvider
tokenCache={tokenCache}
publishableKey={publishableKey}
__experimental_resourceCache={secureStore}
>
<ClerkLoaded>
<JazzAndAuth>
<Slot />

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-clerk",
"main": "index.js",
"version": "1.0.76",
"version": "1.0.78",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",

View File

@@ -1,5 +1,21 @@
# chat-rn
## 1.0.74
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react-native@0.10.13
## 1.0.73
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react-native@0.10.12
## 1.0.72
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.72",
"version": "1.0.74",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",

View File

@@ -1,5 +1,23 @@
# chat-vue
## 0.0.60
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser@0.10.13
- jazz-vue@0.10.13
## 0.0.59
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-vue@0.10.12
- jazz-browser@0.10.12
## 0.0.58
### Patch Changes

View File

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

View File

@@ -1,5 +1,23 @@
# jazz-example-chat
## 0.0.156
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.155
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.154
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.154",
"version": "0.0.156",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,23 @@
# minimal-auth-clerk
## 0.0.55
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
- jazz-react-auth-clerk@0.10.13
## 0.0.54
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-react-auth-clerk@0.10.12
## 0.0.53
### Patch Changes

View File

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

View File

@@ -1,5 +1,21 @@
# file-share-svelte
## 0.0.40
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-svelte@0.10.13
## 0.0.39
### Patch Changes
- Updated dependencies [4612e05]
- jazz-svelte@0.10.12
- jazz-tools@0.10.12
## 0.0.38
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.38",
"version": "0.0.40",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,23 @@
# form
## 0.0.51
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.50
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.49
### Patch Changes

View File

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

View File

@@ -1,5 +1,23 @@
# image-upload
## 0.0.53
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.52
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.51
### Patch Changes

View File

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

View File

@@ -1,5 +1,23 @@
# jazz-example-musicplayer
## 0.0.77
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-inspector@0.10.10
- jazz-react@0.10.13
## 0.0.76
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-inspector@0.10.9
- jazz-react@0.10.12
## 0.0.75
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.75",
"version": "0.0.77",
"type": "module",
"scripts": {
"dev": "vite",
@@ -22,8 +22,8 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"jazz-inspector": "workspace:*",
"jazz-react": "workspace:0.10.9",
"jazz-tools": "workspace:0.10.8",
"jazz-react": "workspace:0.10.13",
"jazz-tools": "workspace:0.10.13",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",

View File

@@ -1,5 +1,21 @@
# organization
## 0.0.49
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
## 0.0.48
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
## 0.0.47
### Patch Changes

View File

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

View File

@@ -1,5 +1,18 @@
# passkey-svelte
## 0.0.44
### Patch Changes
- jazz-svelte@0.10.13
## 0.0.43
### Patch Changes
- Updated dependencies [4612e05]
- jazz-svelte@0.10.12
## 0.0.42
### Patch Changes

View File

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

View File

@@ -1,5 +1,21 @@
# minimal-auth-passkey
## 0.0.54
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
## 0.0.53
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
## 0.0.52
### Patch Changes

View File

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

View File

@@ -1,5 +1,21 @@
# passphrase
## 0.0.51
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
## 0.0.50
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
## 0.0.49
### Patch Changes

View File

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

View File

@@ -66,3 +66,72 @@ main {
margin: 0 auto;
text-align: center;
}
.auth-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: #f3f4f6;
}
.auth-card {
background-color: white;
padding: 2rem;
border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px
rgba(0, 0, 0, 0.06);
width: 28rem;
}
.auth-button-primary,
.auth-button-secondary {
width: 100%;
padding: 0.5rem 1rem;
border-radius: 0.25rem;
font-weight: bold;
cursor: pointer;
margin-bottom: 1rem;
}
.auth-button-primary {
background-color: black;
color: white;
border: none;
}
.auth-button-secondary {
background-color: white;
color: black;
border: 1px solid black;
}
.auth-heading {
color: black;
font-size: 1.5rem;
font-weight: bold;
text-align: center;
margin-bottom: 1rem;
}
.auth-textarea {
width: 100%;
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 0.25rem;
margin-bottom: 1rem;
box-sizing: border-box;
}
.auth-description {
font-size: 0.875rem;
color: #4b5563;
text-align: center;
margin-bottom: 1rem;
}
.auth-button-group {
display: flex;
justify-content: space-between;
gap: 1rem;
}

View File

@@ -1,10 +1,142 @@
import { JazzProvider, PassphraseAuthBasicUI } from "jazz-react";
import { StrictMode } from "react";
import { JazzProvider, usePassphraseAuth } from "jazz-react";
import { StrictMode, useState } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { wordlist } from "./wordlist.ts";
function PassphraseAuthBasicUI(props: {
appName: string;
wordlist: string[];
children?: React.ReactNode;
}) {
const auth = usePassphraseAuth({
wordlist: props.wordlist,
});
const [step, setStep] = useState<"initial" | "create" | "login">("initial");
const [loginPassphrase, setLoginPassphrase] = useState("");
const [isCopied, setIsCopied] = useState(false);
const [currentPassphrase, setCurrentPassphrase] = useState(() =>
auth.generateRandomPassphrase(),
);
if (auth.state === "signedIn") {
return props.children ?? null;
}
const handleCreateAccount = async () => {
setStep("create");
};
const handleLogin = () => {
setStep("login");
};
const handleReroll = () => {
const newPassphrase = auth.generateRandomPassphrase();
setCurrentPassphrase(newPassphrase);
setIsCopied(false);
};
const handleBack = () => {
setStep("initial");
setLoginPassphrase("");
};
const handleCopy = async () => {
await navigator.clipboard.writeText(auth.passphrase);
setIsCopied(true);
};
const handleLoginSubmit = async () => {
await auth.logIn(loginPassphrase);
setStep("initial");
setLoginPassphrase("");
};
const handleNext = async () => {
await auth.registerNewAccount(currentPassphrase, "My Account");
setStep("initial");
setLoginPassphrase("");
};
return (
<div className="auth-container">
<div className="auth-card">
{step === "initial" && (
<div>
<h1 className="auth-heading">{props.appName}</h1>
<button
onClick={handleCreateAccount}
className="auth-button-primary"
>
Create new account
</button>
<button onClick={handleLogin} className="auth-button-secondary">
Log in
</button>
</div>
)}
{step === "create" && (
<>
<h1 className="auth-heading">Your Passphrase</h1>
<p className="auth-description">
Please copy and store this passphrase somewhere safe. You'll need
it to log in.
</p>
<textarea
readOnly
value={currentPassphrase}
className="auth-textarea"
rows={5}
/>
<button onClick={handleCopy} className="auth-button-primary">
{isCopied ? "Copied!" : "Copy"}
</button>
<div className="auth-button-group">
<button onClick={handleBack} className="auth-button-secondary">
Back
</button>
<button onClick={handleReroll} className="auth-button-secondary">
Generate New Passphrase
</button>
<button onClick={handleNext} className="auth-button-primary">
Register
</button>
</div>
</>
)}
{step === "login" && (
<div>
<h1 className="auth-heading">Log In</h1>
<textarea
value={loginPassphrase}
onChange={(e) => setLoginPassphrase(e.target.value)}
placeholder="Enter your passphrase"
className="auth-textarea"
rows={5}
/>
<div className="auth-button-group">
<button onClick={handleBack} className="auth-button-secondary">
Back
</button>
<button
onClick={handleLoginSubmit}
className="auth-button-primary"
>
Log In
</button>
</div>
</div>
)}
</div>
</div>
);
}
function JazzAndAuth({ children }: { children: React.ReactNode }) {
return (
<JazzProvider

View File

@@ -1,5 +1,21 @@
# jazz-password-manager
## 0.0.75
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
## 0.0.74
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
## 0.0.73
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-password-manager",
"private": true,
"version": "0.0.73",
"version": "0.0.75",
"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.9",
"jazz-tools": "workspace:0.10.8",
"jazz-react": "workspace:0.10.13",
"jazz-tools": "workspace:0.10.13",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.41.5",

View File

@@ -1,5 +1,23 @@
# jazz-example-pets
## 0.0.173
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.172
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.171
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.171",
"version": "0.0.173",
"type": "module",
"scripts": {
"dev": "vite",
@@ -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.9",
"jazz-react": "workspace:0.10.9",
"jazz-tools": "workspace:0.10.8",
"jazz-browser-media-images": "workspace:0.10.13",
"jazz-react": "workspace:0.10.13",
"jazz-tools": "workspace:0.10.13",
"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.8",
"jazz-run": "workspace:0.10.13",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.2",

View File

@@ -1,5 +1,23 @@
# reactions
## 0.0.53
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser-media-images@0.10.13
- jazz-react@0.10.13
## 0.0.52
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-browser-media-images@0.10.12
## 0.0.51
### Patch Changes

View File

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

View File

@@ -1,5 +1,23 @@
# todo-vue
## 0.0.58
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser@0.10.13
- jazz-vue@0.10.13
## 0.0.57
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-vue@0.10.12
- jazz-browser@0.10.12
## 0.0.56
### Patch Changes

View File

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

View File

@@ -1,5 +1,21 @@
# jazz-example-todo
## 0.0.172
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
## 0.0.171
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
## 0.0.170
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.170",
"version": "0.0.172",
"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.9",
"jazz-tools": "workspace:0.10.8",
"jazz-react": "workspace:0.10.13",
"jazz-tools": "workspace:0.10.13",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.3.1",

View File

@@ -1,5 +1,21 @@
# version-history
## 0.0.50
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react@0.10.13
## 0.0.49
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
## 0.0.48
### Patch Changes

View File

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

View File

@@ -1,8 +1,16 @@
import { packages } from "@/lib/packages";
import { clsx } from "clsx";
import { Icon } from "gcmp-design-system/src/app/components/atoms/Icon";
import type { Metadata } from "next";
import Link from "next/link";
export const metadata: Metadata = {
title: "API reference",
openGraph: {
title: "API reference",
},
};
const CardHeading = ({
children,
className,

View File

@@ -1,5 +1,12 @@
import { CodeGroup, ContentByFramework, JazzLogo } from '@/components/forMdx'
export const metadata = {
title: "Learn some Jazz",
openGraph: {
title: "Learn some Jazz",
},
};
# Learn some <span className="sr-only">Jazz</span> <JazzLogo className="h-[41px] -ml-0.5 -mt-[3px] inline" />
Welcome to the Jazz documentation!

View File

@@ -211,7 +211,7 @@ The clerk provider is not built into `jazz-react` and needs the `jazz-react-auth
</ContentByFramework>
<ContentByFramework framework="react-native">
The clerk provider is not built into `jazz-react-native` and needs the `jazz-react-native-auth-clerk` package to be installed.
The clerk provider is not built into `jazz-react-native` and needs the `jazz-react-native-auth-clerk` package to be installed. Note the `__experimental_resourceCache` option. This helps render Clerk components when offline.
</ContentByFramework>
After installing the package you can use the `JazzProviderWithClerk` component to wrap your app:
@@ -249,6 +249,7 @@ createRoot(document.getElementById("root")!).render(
<CodeGroup>
```tsx
import { JazzProviderWithClerk } from "jazz-react-native-auth-clerk";
import { secureStore } from "@clerk/clerk-expo/secure-store";
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const clerk = useClerk();
@@ -275,7 +276,11 @@ export default function RootLayout() {
}
return (
<ClerkProvider tokenCache={tokenCache} publishableKey={publishableKey}>
<ClerkProvider
tokenCache={tokenCache}
publishableKey={publishableKey}
__experimental_resourceCache={secureStore}
>
<ClerkLoaded>
<JazzAndAuth>
<Slot />
@@ -380,7 +385,7 @@ export async function onAnonymousAccountDiscarded(
```
</CodeGroup>
To see how this works in reality we suggest you to try
To see how this works in reality we suggest you to try
to upload a song in the [music player demo](https://music-demo.jazz.tools/) and then
try to log in with an existing account.

View File

@@ -442,11 +442,11 @@ All we have to do is create a new group to own each new issue and add "everyone"
import { useState } from "react"; // old
import { Issue } from "./schema"; // old
import { IssueComponent } from "./components/Issue.tsx"; // old
import { useCoState } from "jazz-react"; // old
import { useAccount, useCoState } from "jazz-react";
import { ID, Group } from "jazz-tools"
// old
function App() { // old
const { me } = useAccount(); // old
const { me } = useAccount();
const [issueID, setIssueID] = useState<ID<Issue> | undefined>(// old
(window.location.search?.replace("?issue=", "") || undefined) as ID<Issue> | undefined,// old
); // old

View File

@@ -6,6 +6,38 @@ import { Framework, frameworks } from "@/lib/framework";
import type { Toc } from "@stefanprobst/rehype-extract-toc";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
async function getMdxSource(slugPath: string, framework: string) {
try {
return await import(`./${slugPath}.mdx`);
} catch (error) {
return await import(`./${slugPath}/${framework}.mdx`);
}
}
export async function generateMetadata({
params: { slug, framework },
}: { params: { slug: string[]; framework: string } }) {
const slugPath = slug.join("/");
try {
const mdxSource = await getMdxSource(slugPath, framework);
const title = mdxSource.tableOfContents?.[0].value || "Documentation";
return {
title,
openGraph: {
title,
},
};
} catch (error) {
return {
title: "Documentation",
openGraph: {
title: "Documentation",
},
};
}
}
export default async function Page({
params: { slug, framework },
}: { params: { slug: string[]; framework: string } }) {
@@ -13,13 +45,7 @@ export default async function Page({
const bodyClassName = "overflow-x-hidden lg:flex-1 py-10 max-w-3xl mx-auto";
try {
let mdxSource;
try {
mdxSource = await import(`./${slugPath}.mdx`);
} catch (error) {
mdxSource = await import(`./${slugPath}/${framework}.mdx`);
}
const mdxSource = await getMdxSource(slugPath, framework);
const { default: Content, tableOfContents } = mdxSource;
// Exclude h1 from table of contents

View File

@@ -1,25 +1,27 @@
import { Pricing } from "@/components/Pricing";
import { LatencyMap } from "@/components/cloud/latencyMap";
import { GridCard } from "gcmp-design-system/src/app/components/atoms/GridCard";
import {
H2,
H3,
H4,
} from "gcmp-design-system/src/app/components/atoms/Headings";
import { LI } from "gcmp-design-system/src/app/components/atoms/ListItem";
import { H2, H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { P } from "gcmp-design-system/src/app/components/atoms/Paragraph";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { HeroHeader } from "gcmp-design-system/src/app/components/molecules/HeroHeader";
import { UL } from "gcmp-design-system/src/app/components/molecules/List";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
import type { Metadata } from "next";
import CloudPlusBackup from "./cloudPlusBackup.mdx";
import CloudPlusDIY from "./cloudPlusDIY.mdx";
import CompletelyDIY from "./completelyDIY.mdx";
export const metadata = {
title: "Jazz Cloud",
description: "Serverless sync & storage for Jazz apps.",
const title = "Jazz Cloud";
const description = "Serverless sync & storage for Jazz apps.";
export const metadata: Metadata = {
title,
description,
openGraph: {
title,
description,
},
};
export default function Cloud() {

View File

@@ -11,6 +11,20 @@ import { H2 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { Icon } from "gcmp-design-system/src/app/components/atoms/Icon";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { HeroHeader } from "gcmp-design-system/src/app/components/molecules/HeroHeader";
import type { Metadata } from "next";
const title = "Examples";
const description =
"Find an example app with code most similar to what you want to build.";
export const metadata: Metadata = {
title,
description,
openGraph: {
title,
description,
},
};
const MockButton = ({ children }: { children: React.ReactNode }) => (
<p className="bg-blue-100 text-blue-800 py-1 px-3 rounded-full font-medium text-xs inline-flex items-center justify-center">

View File

@@ -1,11 +1,19 @@
import { products } from "@/lib/showcase";
import { HeroHeader } from "gcmp-design-system/src/app/components/molecules/HeroHeader";
import type { Metadata } from "next";
import Image from "next/image";
import Link from "next/link";
export const metadata = {
title: "Built with Jazz",
description: "Great apps by smart people.",
const title = "Built with Jazz";
const description = "Great apps by smart people.";
export const metadata: Metadata = {
title,
description,
openGraph: {
title,
description,
},
};
export default function Page() {

View File

@@ -1,8 +1,18 @@
import { clsx } from "clsx";
import { HeroHeader } from "gcmp-design-system/src/app/components/molecules/HeroHeader";
import type { Metadata } from "next";
import dynamic from "next/dynamic";
import { Fragment } from "react";
const title = "Status";
export const metadata: Metadata = {
title,
openGraph: {
title,
},
};
const LatencyChart = dynamic(() => import("@/components/LatencyChart"), {
ssr: false,
});
@@ -133,11 +143,6 @@ const query = async () => {
return byRegion;
};
export const metadata = {
title: "Status",
description: "Great apps by smart people.",
};
export default async function Page() {
const byRegion = await query();

View File

@@ -1,7 +1,7 @@
import { type DB as DatabaseT } from "@op-engineering/op-sqlite";
import {
import type { DB as DatabaseT } from "@op-engineering/op-sqlite";
import type {
CojsonInternalTypes,
type OutgoingSyncQueue,
OutgoingSyncQueue,
RawCoID,
SessionID,
} from "cojson";
@@ -29,14 +29,25 @@ export class SQLiteClient implements DBClientInterface {
if (!rows || rows.length === 0) return;
const coValueRow = rows[0] as any & { rowID: number };
type DbCoValueRow = {
id: string;
header: string;
rowID: number;
[key: string]: unknown;
};
const coValueRow = rows[0] as DbCoValueRow;
try {
const parsedHeader =
coValueRow?.header &&
(JSON.parse(coValueRow.header) as CojsonInternalTypes.CoValueHeader);
coValueRow?.header && coValueRow.header.trim() !== ""
? (JSON.parse(coValueRow.header) as CojsonInternalTypes.CoValueHeader)
: undefined;
if (!parsedHeader) return undefined;
return {
...coValueRow,
id: coValueId,
header: parsedHeader,
};
} catch (e) {
@@ -76,10 +87,13 @@ export class SQLiteClient implements DBClientInterface {
if (!rows || rows.length === 0) return [];
try {
return rows.map((row: any) => ({
...row,
tx: JSON.parse(row.tx) as CojsonInternalTypes.Transaction,
}));
return rows.map((row) => {
const rowData = row as { ses: number; idx: number; tx: string };
return {
...rowData,
tx: JSON.parse(rowData.tx) as CojsonInternalTypes.Transaction,
};
});
} catch (e) {
console.warn("Invalid JSON in transaction", e);
return [];
@@ -126,7 +140,7 @@ export class SQLiteClient implements DBClientInterface {
sessionUpdate.sessionID,
sessionUpdate.lastIdx,
sessionUpdate.lastSignature,
sessionUpdate.bytesSinceLastSignature!,
sessionUpdate.bytesSinceLastSignature ?? 0,
],
);
return rows[0]?.rowID as number;

View File

@@ -113,7 +113,7 @@ export class SQLiteReactNative {
);
await db.execute(
`CREATE INDEX IF NOT EXISTS sessionsByCoValue ON sessions (coValue);`,
"CREATE INDEX IF NOT EXISTS sessionsByCoValue ON sessions (coValue);",
);
await db.execute(
@@ -125,7 +125,7 @@ export class SQLiteReactNative {
);
await db.execute(
`CREATE INDEX IF NOT EXISTS coValuesByID ON coValues (id);`,
"CREATE INDEX IF NOT EXISTS coValuesByID ON coValues (id);",
);
await db.execute("PRAGMA user_version = 1");
@@ -142,7 +142,7 @@ export class SQLiteReactNative {
);
await db.execute(
`ALTER TABLE sessions ADD COLUMN bytesSinceLastSignature INTEGER;`,
"ALTER TABLE sessions ADD COLUMN bytesSinceLastSignature INTEGER;",
);
await db.execute("PRAGMA user_version = 3");

View File

@@ -1,14 +1,11 @@
import { Database as DatabaseT } from "better-sqlite3";
import type { Database as DatabaseT } from "better-sqlite3";
import {
CojsonInternalTypes,
OutgoingSyncQueue,
SessionID,
type CojsonInternalTypes,
type OutgoingSyncQueue,
type SessionID,
logger,
} from "cojson";
import RawCoID = CojsonInternalTypes.RawCoID;
import Signature = CojsonInternalTypes.Signature;
import Transaction = CojsonInternalTypes.Transaction;
import {
import type {
DBClientInterface,
SessionRow,
SignatureAfterRow,
@@ -17,6 +14,10 @@ import {
TransactionRow,
} from "cojson-storage";
type RawCoID = CojsonInternalTypes.RawCoID;
type Signature = CojsonInternalTypes.Signature;
type Transaction = CojsonInternalTypes.Transaction;
export type RawCoValueRow = {
id: CojsonInternalTypes.RawCoID;
header: string;
@@ -43,7 +44,7 @@ export class SQLiteClient implements DBClientInterface {
getCoValue(coValueId: RawCoID): StoredCoValueRow | undefined {
const coValueRow = this.db
.prepare(`SELECT * FROM coValues WHERE id = ?`)
.prepare("SELECT * FROM coValues WHERE id = ?")
.get(coValueId) as RawCoValueRow & { rowID: number };
if (!coValueRow) return;
@@ -58,7 +59,7 @@ export class SQLiteClient implements DBClientInterface {
};
} catch (e) {
const headerValue = coValueRow?.header ?? "";
logger.warn("Invalid JSON in header: " + headerValue, {
logger.warn(`Invalid JSON in header: ${headerValue}`, {
id: coValueId,
});
return;
@@ -67,7 +68,7 @@ export class SQLiteClient implements DBClientInterface {
getCoValueSessions(coValueRowId: number): StoredSessionRow[] {
return this.db
.prepare<number>(`SELECT * FROM sessions WHERE coValue = ?`)
.prepare<number>("SELECT * FROM sessions WHERE coValue = ?")
.all(coValueRowId) as StoredSessionRow[];
}
@@ -77,7 +78,7 @@ export class SQLiteClient implements DBClientInterface {
): StoredSessionRow | undefined {
return this.db
.prepare<[number, string]>(
`SELECT * FROM sessions WHERE coValue = ? AND sessionID = ?`,
"SELECT * FROM sessions WHERE coValue = ? AND sessionID = ?",
)
.get(coValueRowId, sessionID) as StoredSessionRow | undefined;
}
@@ -88,7 +89,7 @@ export class SQLiteClient implements DBClientInterface {
): TransactionRow[] {
const txs = this.db
.prepare<[number, number]>(
`SELECT * FROM transactions WHERE ses = ? AND idx >= ?`,
"SELECT * FROM transactions WHERE ses = ? AND idx >= ?",
)
.all(sessionRowId, firstNewTxIdx) as RawTransactionRow[];
@@ -109,7 +110,7 @@ export class SQLiteClient implements DBClientInterface {
): SignatureAfterRow[] {
return this.db
.prepare<[number, number]>(
`SELECT * FROM signatureAfter WHERE ses = ? AND idx >= ?`,
"SELECT * FROM signatureAfter WHERE ses = ? AND idx >= ?",
)
.all(sessionRowId, firstNewTxIdx) as SignatureAfterRow[];
}
@@ -117,7 +118,7 @@ export class SQLiteClient implements DBClientInterface {
addCoValue(msg: CojsonInternalTypes.NewContentMessage): number {
return this.db
.prepare<[CojsonInternalTypes.RawCoID, string]>(
`INSERT INTO coValues (id, header) VALUES (?, ?)`,
"INSERT INTO coValues (id, header) VALUES (?, ?)",
)
.run(msg.id, JSON.stringify(msg.header)).lastInsertRowid as number;
}
@@ -153,7 +154,7 @@ export class SQLiteClient implements DBClientInterface {
) {
this.db
.prepare<[number, number, string]>(
`INSERT INTO transactions (ses, idx, tx) VALUES (?, ?, ?)`,
"INSERT INTO transactions (ses, idx, tx) VALUES (?, ?, ?)",
)
.run(sessionRowID, nextIdx, JSON.stringify(newTransaction));
}
@@ -165,12 +166,13 @@ export class SQLiteClient implements DBClientInterface {
}: { sessionRowID: number; idx: number; signature: Signature }) {
this.db
.prepare<[number, number, string]>(
`INSERT INTO signatureAfter (ses, idx, signature) VALUES (?, ?, ?)`,
"INSERT INTO signatureAfter (ses, idx, signature) VALUES (?, ?, ?)",
)
.run(sessionRowID, idx, signature);
}
transaction(operationsCallback: () => unknown) {
this.db.transaction(operationsCallback)();
return undefined;
}
}

View File

@@ -1,12 +1,12 @@
import Database, { Database as DatabaseT } from "better-sqlite3";
import Database, { type Database as DatabaseT } from "better-sqlite3";
import {
IncomingSyncStream,
OutgoingSyncQueue,
Peer,
type IncomingSyncStream,
type OutgoingSyncQueue,
type Peer,
cojsonInternals,
logger,
} from "cojson";
import { SyncManager, TransactionRow } from "cojson-storage";
import { SyncManager, type TransactionRow } from "cojson-storage";
import { SQLiteClient } from "./sqliteClient.js";
export class SQLiteNode {
@@ -46,7 +46,7 @@ export class SQLiteNode {
msg,
(k, v) =>
k === "changes" || k === "encryptedChanges"
? v.slice(0, 20) + "..."
? `${v.slice(0, 20)}...`
: v,
)}`,
);
@@ -117,7 +117,7 @@ export class SQLiteNode {
).run();
db.prepare(
`CREATE INDEX IF NOT EXISTS sessionsByCoValue ON sessions (coValue);`,
"CREATE INDEX IF NOT EXISTS sessionsByCoValue ON sessions (coValue);",
).run();
db.prepare(
@@ -129,7 +129,7 @@ export class SQLiteNode {
).run();
db.prepare(
`CREATE INDEX IF NOT EXISTS coValuesByID ON coValues (id);`,
"CREATE INDEX IF NOT EXISTS coValuesByID ON coValues (id);",
).run();
db.pragma("user_version = 1");
@@ -138,17 +138,17 @@ export class SQLiteNode {
if (oldVersion <= 1) {
// fix embarrassing off-by-one error for transaction indices
const txs = db
.prepare(`SELECT * FROM transactions`)
.prepare("SELECT * FROM transactions")
.all() as TransactionRow[];
for (const tx of txs) {
db.prepare(`DELETE FROM transactions WHERE ses = ? AND idx = ?`).run(
db.prepare("DELETE FROM transactions WHERE ses = ? AND idx = ?").run(
tx.ses,
tx.idx,
);
tx.idx -= 1;
db.prepare(
`INSERT INTO transactions (ses, idx, tx) VALUES (?, ?, ?)`,
"INSERT INTO transactions (ses, idx, tx) VALUES (?, ?, ?)",
).run(tx.ses, tx.idx, tx.tx);
}
@@ -166,7 +166,7 @@ export class SQLiteNode {
).run();
db.prepare(
`ALTER TABLE sessions ADD COLUMN bytesSinceLastSignature INTEGER;`,
"ALTER TABLE sessions ADD COLUMN bytesSinceLastSignature INTEGER;",
).run();
db.pragma("user_version = 3");

View File

@@ -1,15 +1,15 @@
import {
CojsonInternalTypes,
MAX_RECOMMENDED_TX_SIZE,
OutgoingSyncQueue,
SessionID,
SyncMessage,
type OutgoingSyncQueue,
type SessionID,
type SyncMessage,
cojsonInternals,
emptyKnownState,
logger,
} from "cojson";
import { collectNewTxs, getDependedOnCoValues } from "./syncUtils.js";
import { DBClientInterface, StoredSessionRow } from "./types.js";
import type { DBClientInterface, StoredSessionRow } from "./types.js";
import NewContentMessage = CojsonInternalTypes.NewContentMessage;
import KnownStateMessage = CojsonInternalTypes.KnownStateMessage;
import RawCoID = CojsonInternalTypes.RawCoID;
@@ -82,12 +82,15 @@ export class SyncManager {
// reverse it to send the top level id the last in the order
const collectedMessages = Object.values(outputMessages).reverse();
collectedMessages.forEach(({ knownMessage, contentMessages }) => {
for (const { knownMessage, contentMessages } of collectedMessages) {
this.sendStateMessage(knownMessage);
contentMessages?.length &&
contentMessages.forEach((msg) => this.sendStateMessage(msg));
});
if (contentMessages?.length) {
for (const msg of contentMessages) {
this.sendStateMessage(msg);
}
}
}
}
private async collectCoValueData(
@@ -106,7 +109,9 @@ export class SyncManager {
action: "known",
...emptyKnownState(peerKnownState.id),
};
asDependencyOf && (emptyKnownMessage.asDependencyOf = asDependencyOf);
if (asDependencyOf) {
emptyKnownMessage.asDependencyOf = asDependencyOf;
}
messageMap[peerKnownState.id] = { knownMessage: emptyKnownMessage };
return messageMap;
}
@@ -153,7 +158,9 @@ export class SyncManager {
action: "known",
...newCoValueKnownState,
};
asDependencyOf && (knownMessage.asDependencyOf = asDependencyOf);
if (asDependencyOf) {
knownMessage.asDependencyOf = asDependencyOf;
}
messageMap[newCoValueKnownState.id] = {
knownMessage: knownMessage,
contentMessages: newContentMessages,
@@ -272,11 +279,13 @@ export class SyncManager {
const nextIdx = sessionRow?.lastIdx || 0;
if (!msg.new[sessionID]) throw new Error("Session ID not found");
const sessionUpdate = {
coValue: storedCoValueRowID,
sessionID,
lastIdx: newLastIdx,
lastSignature: msg.new[sessionID]!.lastSignature,
lastSignature: msg.new[sessionID].lastSignature,
bytesSinceLastSignature: newBytesSinceLastSignature,
};
@@ -289,7 +298,7 @@ export class SyncManager {
await this.dbClient.addSignatureAfter({
sessionRowID,
idx: newLastIdx - 1,
signature: msg.new[sessionID]!.lastSignature,
signature: msg.new[sessionID].lastSignature,
});
}
@@ -306,7 +315,11 @@ export class SyncManager {
handleDone(_msg: CojsonInternalTypes.DoneMessage) {}
async sendStateMessage(msg: any): Promise<unknown> {
async sendStateMessage(
msg:
| CojsonInternalTypes.KnownStateMessage
| CojsonInternalTypes.NewContentMessage,
): Promise<unknown> {
return this.toLocalNode
.push(msg)
.catch((e) =>

View File

@@ -1,11 +1,15 @@
import {
CojsonInternalTypes,
JsonValue,
SessionID,
Stringified,
type CojsonInternalTypes,
type JsonValue,
type SessionID,
type Stringified,
cojsonInternals,
} from "cojson";
import { StoredCoValueRow, StoredSessionRow, TransactionRow } from "./types.js";
import type {
StoredCoValueRow,
StoredSessionRow,
TransactionRow,
} from "./types.js";
export function collectNewTxs({
newTxsInSession,
@@ -19,19 +23,17 @@ export function collectNewTxs({
firstNewTxIdx: number;
}) {
for (const tx of newTxsInSession) {
let sessionEntry =
newContentMessages[newContentMessages.length - 1]!.new[
sessionRow.sessionID
];
const lastMessage = newContentMessages[newContentMessages.length - 1];
if (!lastMessage) return;
let sessionEntry = lastMessage.new[sessionRow.sessionID];
if (!sessionEntry) {
sessionEntry = {
after: firstNewTxIdx,
lastSignature: "WILL_BE_REPLACED" as CojsonInternalTypes.Signature,
newTransactions: [],
};
newContentMessages[newContentMessages.length - 1]!.new[
sessionRow.sessionID
] = sessionEntry;
lastMessage.new[sessionRow.sessionID] = sessionEntry;
}
sessionEntry.newTransactions.push(tx.tx);

View File

@@ -1,5 +1,5 @@
import {
Mocked,
type Mocked,
afterEach,
beforeEach,
describe,
@@ -8,7 +8,7 @@ import {
vi,
} from "vitest";
import {
import type {
CojsonInternalTypes,
OutgoingSyncQueue,
SessionID,
@@ -16,11 +16,12 @@ import {
} from "cojson";
import { SyncManager } from "../syncManager.js";
import { getDependedOnCoValues } from "../syncUtils.js";
import { DBClientInterface } from "../types.js";
import type { DBClientInterface } from "../types.js";
import { fixtures } from "./fixtureMessages.js";
import RawCoID = CojsonInternalTypes.RawCoID;
import NewContentMessage = CojsonInternalTypes.NewContentMessage;
type RawCoID = CojsonInternalTypes.RawCoID;
type NewContentMessage = CojsonInternalTypes.NewContentMessage;
type Transaction = CojsonInternalTypes.Transaction;
vi.mock("../syncUtils");
const coValueIdToLoad = "co_zKwG8NyfZ8GXqcjDHY4NS3SbU2m";
@@ -40,7 +41,7 @@ const incomingContentMessage = fixtures[coValueIdToLoad].getContent({
describe("DB sync manager", () => {
let syncManager: SyncManager;
let queue: OutgoingSyncQueue = {} as unknown as OutgoingSyncQueue;
const queue: OutgoingSyncQueue = {} as unknown as OutgoingSyncQueue;
const DBClient = vi.fn();
DBClient.prototype.getCoValue = vi.fn();
@@ -154,11 +155,11 @@ describe("DB sync manager", () => {
header: true,
id: coValueIdToLoad,
sessions: sessionsData.reduce(
(acc, sessionRow) => ({
...acc,
[sessionRow.sessionID]: sessionRow.lastIdx,
}),
{},
(acc, sessionRow) => {
acc[sessionRow.sessionID] = sessionRow.lastIdx;
return acc;
},
{} as Record<string, number>,
),
});
@@ -167,15 +168,22 @@ describe("DB sync manager", () => {
header: coValueHeader,
id: coValueIdToLoad,
new: sessionsData.reduce(
(acc, sessionRow) => ({
...acc,
[sessionRow.sessionID]: {
(acc, sessionRow) => {
acc[sessionRow.sessionID] = {
after: expect.any(Number),
lastSignature: expect.any(String),
newTransactions: expect.any(Array),
},
}),
{},
};
return acc;
},
{} as Record<
string,
{
after: number;
lastSignature: string;
newTransactions: Transaction[];
}
>,
),
priority: 0,
});

View File

@@ -1,7 +1,8 @@
import { CojsonInternalTypes, SessionID } from "cojson";
import RawCoID = CojsonInternalTypes.RawCoID;
import Transaction = CojsonInternalTypes.Transaction;
import Signature = CojsonInternalTypes.Signature;
import type { CojsonInternalTypes, SessionID } from "cojson";
type RawCoID = CojsonInternalTypes.RawCoID;
type Transaction = CojsonInternalTypes.Transaction;
type Signature = CojsonInternalTypes.Signature;
export type CoValueRow = {
id: CojsonInternalTypes.RawCoID;
@@ -72,7 +73,7 @@ export interface DBClientInterface {
sessionRowID: number,
idx: number,
newTransaction: Transaction,
): Promise<number> | void | unknown;
): Promise<number> | undefined | unknown;
addSignatureAfter({
sessionRowID,
@@ -82,7 +83,7 @@ export interface DBClientInterface {
sessionRowID: number;
idx: number;
signature: Signature;
}): Promise<number> | void | unknown;
}): Promise<number> | undefined | unknown;
transaction(callback: () => unknown): Promise<unknown> | void;
transaction(callback: () => unknown): Promise<unknown> | undefined;
}

View File

@@ -1,10 +1,10 @@
import { SyncMessage } from "cojson";
import type { SyncMessage } from "cojson";
import { addMessageToBacklog } from "./serialization.js";
export const MAX_OUTGOING_MESSAGES_CHUNK_BYTES = 25_000;
export class BatchedOutgoingMessages {
private backlog: string = "";
private backlog = "";
private timeout: ReturnType<typeof setTimeout> | null = null;
constructor(private send: (messages: string) => void) {}

View File

@@ -1,4 +1,4 @@
import { Peer, logger } from "cojson";
import { type Peer, logger } from "cojson";
import { createWebSocketPeer } from "./createWebSocketPeer.js";
export class WebSocketPeerWithReconnection {
@@ -61,7 +61,7 @@ export class WebSocketPeerWithReconnection {
const timeout = this.reconnectionTimeout * this.reconnectionAttempts;
logger.debug(
"Websocket disconnected, trying to reconnect in " + timeout + "ms",
`Websocket disconnected, trying to reconnect in ${timeout}ms`,
);
await this.waitForOnline(timeout);

View File

@@ -1,14 +1,14 @@
import {
DisconnectedError,
Peer,
PingTimeoutError,
SyncMessage,
type DisconnectedError,
type Peer,
type PingTimeoutError,
type SyncMessage,
cojsonInternals,
logger,
} from "cojson";
import { BatchedOutgoingMessages } from "./BatchedOutgoingMessages.js";
import { deserializeMessages, getErrorMessage } from "./serialization.js";
import { AnyWebSocket } from "./types.js";
import type { AnyWebSocket } from "./types.js";
export const BUFFER_LIMIT = 100_000;
export const BUFFER_LIMIT_POLLING_INTERVAL = 10;
@@ -52,7 +52,7 @@ function waitForWebSocketOpen(websocket: AnyWebSocket) {
if (websocket.readyState === 1) {
resolve();
} else {
websocket.addEventListener("open", resolve, { once: true });
websocket.addEventListener("open", () => resolve(), { once: true });
}
});
}
@@ -144,6 +144,8 @@ export function createWebSocketPeer({
}
websocket.addEventListener("close", handleClose);
// TODO (#1537): Remove this any once the WebSocket error event type is fixed
// biome-ignore lint/suspicious/noExplicitAny: WebSocket error event type
websocket.addEventListener("error" as any, (err) => {
if (err.message) {
logger.warn(err.message);
@@ -174,7 +176,7 @@ export function createWebSocketPeer({
if (!result.ok) {
logger.warn(
"Error while deserializing messages: " + getErrorMessage(result.error),
`Error while deserializing messages: ${getErrorMessage(result.error)}`,
);
return;
}
@@ -227,7 +229,7 @@ export function createWebSocketPeer({
},
{ once: true },
);
} else if (websocket.readyState == 1) {
} else if (websocket.readyState === 1) {
websocket.close();
}
},

View File

@@ -1,5 +1,5 @@
import { SyncMessage, logger } from "cojson";
import { PingMsg } from "./types.js";
import { type SyncMessage, logger } from "cojson";
import type { PingMsg } from "./types.js";
export function getErrorMessage(error: unknown) {
return error instanceof Error ? error.message : "Unknown error";
@@ -28,7 +28,7 @@ export function deserializeMessages(messages: unknown) {
| PingMsg[],
} as const;
} catch (e) {
logger.error("Error while deserializing messages: " + getErrorMessage(e));
logger.error(`Error while deserializing messages: ${getErrorMessage(e)}`);
return {
ok: false,
error: e,

View File

@@ -1,5 +1,5 @@
import { SyncMessage } from "cojson";
import { CojsonInternalTypes } from "cojson";
import type { SyncMessage } from "cojson";
import type { CojsonInternalTypes } from "cojson";
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import {
BatchedOutgoingMessages,

View File

@@ -1,14 +1,14 @@
import { SyncMessage } from "cojson";
import type { SyncMessage } from "cojson";
import type { Channel } from "queueueue";
import { Mocked, describe, expect, test, vi } from "vitest";
import { type Mocked, describe, expect, test, vi } from "vitest";
import { MAX_OUTGOING_MESSAGES_CHUNK_BYTES } from "../BatchedOutgoingMessages.js";
import {
BUFFER_LIMIT,
BUFFER_LIMIT_POLLING_INTERVAL,
CreateWebSocketPeerOpts,
type CreateWebSocketPeerOpts,
createWebSocketPeer,
} from "../createWebSocketPeer.js";
import { AnyWebSocket } from "../types.js";
import type { AnyWebSocket } from "../types.js";
function setup(opts: Partial<CreateWebSocketPeerOpts> = {}) {
const listeners = new Map<string, (event: MessageEvent) => void>();
@@ -472,6 +472,7 @@ describe("createWebSocketPeer", () => {
});
});
// biome-ignore lint/suspicious/noConfusingVoidType: Test helper
function waitFor(callback: () => boolean | void) {
return new Promise<void>((resolve, reject) => {
const checkPassed = () => {

View File

@@ -1,7 +1,7 @@
import { createServer } from "http";
import { createServer } from "node:http";
import { ControlledAgent, LocalNode } from "cojson";
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
import { WebSocket, WebSocketServer } from "ws";
import { type WebSocket, WebSocketServer } from "ws";
import { createWebSocketPeer } from "../createWebSocketPeer";
export const startSyncServer = async (port?: number) => {
@@ -75,16 +75,18 @@ export const startSyncServer = async (port?: number) => {
server.listen(port ?? 0);
port = (server.address() as { port: number }).port;
const syncServer = `ws://localhost:${port}`;
const actualPort = (server.address() as { port: number }).port;
const syncServer = `ws://localhost:${actualPort}`;
return {
close: () => {
connections.forEach((ws) => ws.close());
for (const ws of connections) {
ws.close();
}
server.close();
},
syncServer,
port,
port: actualPort,
localNode,
};
};

View File

@@ -1,3 +1,4 @@
// biome-ignore lint/suspicious/noConfusingVoidType: Test helper
export function waitFor(callback: () => boolean | void) {
return new Promise<void>((resolve, reject) => {
const checkPassed = () => {

View File

@@ -1,7 +1,7 @@
export interface WebsocketEvents {
close: { code: number; reason: string };
message: { data: unknown };
open: void;
open: unknown;
}
export interface PingMsg {

View File

@@ -184,9 +184,7 @@ export class CoValueCore {
this.header.meta?.type === "account"
? (this.node.currentSessionID.replace(
this.node.account.id,
this.node.account
.currentAgentID()
._unsafeUnwrap({ withStackTrace: true }),
this.node.account.currentAgentID(),
) as SessionID)
: this.node.currentSessionID;
@@ -455,9 +453,7 @@ export class CoValueCore {
this.header.meta?.type === "account"
? (this.node.currentSessionID.replace(
this.node.account.id,
this.node.account
.currentAgentID()
._unsafeUnwrap({ withStackTrace: true }),
this.node.account.currentAgentID(),
) as SessionID)
: this.node.currentSessionID;
@@ -639,9 +635,7 @@ export class CoValueCore {
// Try to find key revelation for us
const lookupAccountOrAgentID =
this.header.meta?.type === "account"
? this.node.account
.currentAgentID()
._unsafeUnwrap({ withStackTrace: true })
? this.node.account.currentAgentID()
: this.node.account.id;
const lastReadyKeyEdit = content.lastEditAt(

View File

@@ -1,4 +1,3 @@
import { Result, ok } from "neverthrow";
import { CoID, RawCoValue } from "../coValue.js";
import {
CoValueCore,
@@ -47,10 +46,11 @@ export class RawAccount<
> extends RawGroup<Meta> {
_cachedCurrentAgentID: AgentID | undefined;
currentAgentID(): Result<AgentID, InvalidAccountAgentIDError> {
currentAgentID(): AgentID {
if (this._cachedCurrentAgentID) {
return ok(this._cachedCurrentAgentID);
return this._cachedCurrentAgentID;
}
const agents = this.keys()
.filter((k): k is AgentID => k.startsWith("sealer_"))
.sort(
@@ -65,7 +65,7 @@ export class RawAccount<
this._cachedCurrentAgentID = agents[0];
return ok(agents[0]!);
return agents[0]!;
}
createInvite(_: AccountRole): InviteSecret {
@@ -77,10 +77,10 @@ export interface ControlledAccountOrAgent {
id: RawAccountID | AgentID;
agentSecret: AgentSecret;
currentAgentID: () => Result<AgentID, InvalidAccountAgentIDError>;
currentSignerID: () => Result<SignerID, InvalidAccountAgentIDError>;
currentAgentID: () => AgentID;
currentSignerID: () => SignerID;
currentSignerSecret: () => SignerSecret;
currentSealerID: () => Result<SealerID, InvalidAccountAgentIDError>;
currentSealerID: () => SealerID;
currentSealerSecret: () => SealerSecret;
}
@@ -116,17 +116,17 @@ export class RawControlledAccount<Meta extends AccountMeta = AccountMeta>
return this.core.node.acceptInvite(groupOrOwnedValueID, inviteSecret);
}
currentAgentID(): Result<AgentID, InvalidAccountAgentIDError> {
currentAgentID(): AgentID {
if (this._cachedCurrentAgentID) {
return ok(this._cachedCurrentAgentID);
return this._cachedCurrentAgentID;
}
const agentID = this.crypto.getAgentID(this.agentSecret);
this._cachedCurrentAgentID = agentID;
return ok(agentID);
return agentID;
}
currentSignerID() {
return this.currentAgentID().map((id) => this.crypto.getAgentSignerID(id));
return this.crypto.getAgentSignerID(this.currentAgentID());
}
currentSignerSecret(): SignerSecret {
@@ -134,7 +134,7 @@ export class RawControlledAccount<Meta extends AccountMeta = AccountMeta>
}
currentSealerID() {
return this.currentAgentID().map((id) => this.crypto.getAgentSealerID(id));
return this.crypto.getAgentSealerID(this.currentAgentID());
}
currentSealerSecret(): SealerSecret {
@@ -153,11 +153,11 @@ export class ControlledAgent implements ControlledAccountOrAgent {
}
currentAgentID() {
return ok(this.crypto.getAgentID(this.agentSecret));
return this.crypto.getAgentID(this.agentSecret);
}
currentSignerID() {
return this.currentAgentID().map((id) => this.crypto.getAgentSignerID(id));
return this.crypto.getAgentSignerID(this.currentAgentID());
}
currentSignerSecret(): SignerSecret {
@@ -165,7 +165,7 @@ export class ControlledAgent implements ControlledAccountOrAgent {
}
currentSealerID() {
return this.currentAgentID().map((id) => this.crypto.getAgentSealerID(id));
return this.crypto.getAgentSealerID(this.currentAgentID());
}
currentSealerSecret(): SealerSecret {

View File

@@ -251,9 +251,7 @@ export class RawGroup<
const memberKey = typeof account === "string" ? account : account.id;
const agent =
typeof account === "string"
? account
: account.currentAgentID()._unsafeUnwrap({ withStackTrace: true });
typeof account === "string" ? account : account.currentAgentID();
/**
* WriteOnly members can only see their own changes.

View File

@@ -530,7 +530,7 @@ export class LocalNode {
} satisfies UnexpectedlyNotAccountError);
}
return (coValue.getCurrentContent() as RawAccount).currentAgentID();
return ok((coValue.getCurrentContent() as RawAccount).currentAgentID());
}
resolveAccountAgentAsync(
@@ -573,7 +573,7 @@ export class LocalNode {
} satisfies UnexpectedlyNotAccountError);
}
return (coValue.getCurrentContent() as RawAccount).currentAgentID();
return ok((coValue.getCurrentContent() as RawAccount).currentAgentID());
});
}
@@ -601,9 +601,7 @@ export class LocalNode {
this.crypto.seal({
message: readKey.secret,
from: this.account.currentSealerSecret(),
to: this.account
.currentSealerID()
._unsafeUnwrap({ withStackTrace: true }),
to: this.account.currentSealerID(),
nOnceMaterial: {
in: groupCoValue.id,
tx: groupCoValue.nextTransactionID(),

View File

@@ -476,16 +476,7 @@ function agentInAccountOrMemberInGroup(
groupAtTime: RawGroup,
): RawAccountID | AgentID | undefined {
if (transactor === groupAtTime.id && groupAtTime instanceof RawAccount) {
return groupAtTime.currentAgentID().match(
(agentID) => agentID,
(e) => {
logger.error(
"Error while determining current agent ID in valid transactions",
e,
);
return undefined;
},
);
return groupAtTime.currentAgentID();
}
return transactor;
}

View File

@@ -155,7 +155,7 @@ test("New transactions in a group correctly update owned values, including subsc
map.subscribe(listener);
expect(listener.mock.calls[0][0].get("hello")).toBe("world");
expect(listener.mock.calls[0]?.[0].get("hello")).toBe("world");
const resignationThatWeJustLearnedAbout = {
privacy: "trusting",
@@ -192,7 +192,7 @@ test("New transactions in a group correctly update owned values, including subsc
expect(manuallyAdddedTxSuccess).toBe(true);
expect(listener.mock.calls.length).toBe(2);
expect(listener.mock.calls[1][0].get("hello")).toBe(undefined);
expect(listener.mock.calls[1]?.[0].get("hello")).toBe(undefined);
expect(map.core.getValidSortedTransactions().length).toBe(0);
});

View File

@@ -358,7 +358,7 @@ test("Admins can set group read key and then use it to create and read private t
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -412,7 +412,7 @@ test("Admins can set group read key and then writers can use it to create and re
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -424,7 +424,7 @@ test("Admins can set group read key and then writers can use it to create and re
const revelation2 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: writer.currentSealerID()._unsafeUnwrap(),
to: writer.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -491,7 +491,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -503,7 +503,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation2 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader.currentSealerID()._unsafeUnwrap(),
to: reader.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -578,7 +578,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -590,7 +590,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation2 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader1.currentSealerID()._unsafeUnwrap(),
to: reader1.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -629,7 +629,7 @@ test("Admins can set group read key and then use it to create private transactio
const revelation3 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader2.currentSealerID()._unsafeUnwrap(),
to: reader2.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -694,7 +694,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -724,7 +724,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation2 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -777,7 +777,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -804,7 +804,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation2 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -816,7 +816,7 @@ test("Admins can set group read key, make a private transaction in an owned obje
const revelation3 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: reader.currentSealerID()._unsafeUnwrap(),
to: reader.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -912,7 +912,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const revelation1 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -924,7 +924,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const revelation2 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader.currentSealerID()._unsafeUnwrap(),
to: reader.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -936,7 +936,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const revelation3 = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: reader2.currentSealerID()._unsafeUnwrap(),
to: reader2.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -982,7 +982,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const newRevelation1 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -994,7 +994,7 @@ test("Admins can set group read rey, make a private transaction in an owned obje
const newRevelation2 = Crypto.seal({
message: readKey2,
from: admin.currentSealerSecret(),
to: reader2.currentSealerID()._unsafeUnwrap(),
to: reader2.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1119,7 +1119,7 @@ test("Admins can create an adminInvite, which can add an admin", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1229,7 +1229,7 @@ test("Admins can create a writerInvite, which can add a writer", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1332,7 +1332,7 @@ test("Admins can create a readerInvite, which can add a reader", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1425,7 +1425,7 @@ test("WriterInvites can not invite admins", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1479,7 +1479,7 @@ test("ReaderInvites can not invite admins", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1533,7 +1533,7 @@ test("ReaderInvites can not invite writers", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1587,7 +1587,7 @@ test("WriteOnlyInvites can not invite writers", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1641,7 +1641,7 @@ test("WriteOnlyInvites can not invite admins", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1695,7 +1695,7 @@ test("WriteOnlyInvites can invite writeOnly", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1749,7 +1749,7 @@ test("WriteOnlyInvites can set writeKeys", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1800,7 +1800,7 @@ test("Invites can't override key revelations", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1855,7 +1855,7 @@ test("WriteOnlyInvites can't override writeKeys", () => {
const revelation = Crypto.seal({
message: readKey,
from: admin.currentSealerSecret(),
to: admin.currentSealerID()._unsafeUnwrap(),
to: admin.currentSealerID(),
nOnceMaterial: {
in: groupCore.id,
tx: groupCore.nextTransactionID(),
@@ -1929,7 +1929,7 @@ test("Can give read permission to 'everyone'", () => {
childObject
.testWithDifferentAccount(
newAccount,
Crypto.newRandomSessionID(newAccount.currentAgentID()._unsafeUnwrap()),
Crypto.newRandomSessionID(newAccount.currentAgentID()),
)
.getCurrentContent(),
);
@@ -1955,7 +1955,7 @@ test("Can give read permissions to 'everyone' (high-level)", async () => {
childObject.core
.testWithDifferentAccount(
new ControlledAgent(Crypto.newRandomAgentSecret(), Crypto),
Crypto.newRandomSessionID(newAccount.currentAgentID()._unsafeUnwrap()),
Crypto.newRandomSessionID(newAccount.currentAgentID()),
)
.getCurrentContent(),
);
@@ -1993,7 +1993,7 @@ test("Can give write permission to 'everyone'", async () => {
childObject
.testWithDifferentAccount(
newAccount,
Crypto.newRandomSessionID(newAccount.currentAgentID()._unsafeUnwrap()),
Crypto.newRandomSessionID(newAccount.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2025,7 +2025,7 @@ test("Can give write permissions to 'everyone' (high-level)", async () => {
childObject.core
.testWithDifferentAccount(
newAccount,
Crypto.newRandomSessionID(newAccount.currentAgentID()._unsafeUnwrap()),
Crypto.newRandomSessionID(newAccount.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2087,7 +2087,7 @@ test("Writers, readers and invitees can not set parent extensions", () => {
group.core
.testWithDifferentAccount(
adminInvite,
Crypto.newRandomSessionID(adminInvite.currentAgentID()._unsafeUnwrap()),
Crypto.newRandomSessionID(adminInvite.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2099,9 +2099,7 @@ test("Writers, readers and invitees can not set parent extensions", () => {
group.core
.testWithDifferentAccount(
writerInvite,
Crypto.newRandomSessionID(
writerInvite.currentAgentID()._unsafeUnwrap(),
),
Crypto.newRandomSessionID(writerInvite.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2113,9 +2111,7 @@ test("Writers, readers and invitees can not set parent extensions", () => {
group.core
.testWithDifferentAccount(
readerInvite,
Crypto.newRandomSessionID(
readerInvite.currentAgentID()._unsafeUnwrap(),
),
Crypto.newRandomSessionID(readerInvite.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2209,7 +2205,7 @@ test("Invitees can not set child extensions", () => {
group.core
.testWithDifferentAccount(
adminInvite,
Crypto.newRandomSessionID(adminInvite.currentAgentID()._unsafeUnwrap()),
Crypto.newRandomSessionID(adminInvite.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2221,9 +2217,7 @@ test("Invitees can not set child extensions", () => {
group.core
.testWithDifferentAccount(
writerInvite,
Crypto.newRandomSessionID(
writerInvite.currentAgentID()._unsafeUnwrap(),
),
Crypto.newRandomSessionID(writerInvite.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2235,9 +2229,7 @@ test("Invitees can not set child extensions", () => {
group.core
.testWithDifferentAccount(
readerInvite,
Crypto.newRandomSessionID(
readerInvite.currentAgentID()._unsafeUnwrap(),
),
Crypto.newRandomSessionID(readerInvite.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2422,7 +2414,7 @@ test("Writers, readers and invites can't reveal parent read keys to child groups
group.core
.testWithDifferentAccount(
adminInvite,
Crypto.newRandomSessionID(adminInvite.currentAgentID()._unsafeUnwrap()),
Crypto.newRandomSessionID(adminInvite.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2440,9 +2432,7 @@ test("Writers, readers and invites can't reveal parent read keys to child groups
group.core
.testWithDifferentAccount(
writerInvite,
Crypto.newRandomSessionID(
writerInvite.currentAgentID()._unsafeUnwrap(),
),
Crypto.newRandomSessionID(writerInvite.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2460,9 +2450,7 @@ test("Writers, readers and invites can't reveal parent read keys to child groups
group.core
.testWithDifferentAccount(
readerInvite,
Crypto.newRandomSessionID(
readerInvite.currentAgentID()._unsafeUnwrap(),
),
Crypto.newRandomSessionID(readerInvite.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2941,7 +2929,7 @@ test("Can revoke read permission from 'everyone'", async () => {
childObject.core
.testWithDifferentAccount(
newAccount,
Crypto.newRandomSessionID(newAccount.currentAgentID()._unsafeUnwrap()),
Crypto.newRandomSessionID(newAccount.currentAgentID()),
)
.getCurrentContent(),
);
@@ -2963,7 +2951,7 @@ test("Can revoke read permission from 'everyone'", async () => {
childObject.core
.testWithDifferentAccount(
newAccount2,
Crypto.newRandomSessionID(newAccount2.currentAgentID()._unsafeUnwrap()),
Crypto.newRandomSessionID(newAccount2.currentAgentID()),
)
.getCurrentContent(),
);

View File

@@ -12,5 +12,5 @@
"esModuleInterop": true
},
"include": ["./src/**/*.ts"],
"exclude": ["./node_modules", "./src/tests"]
"exclude": ["./node_modules"]
}

View File

@@ -1,5 +1,11 @@
# create-jazz-app
## 0.1.12
### Patch Changes
- e2e0af3: Handle workspace devDependencies of cloned apps when using create-jazz-app
## 0.1.11
### Patch Changes

View File

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

View File

@@ -136,19 +136,30 @@ async function scaffoldProject({
const packageJsonPath = `${projectName}/package.json`;
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
// Replace workspace: dependencies with latest
if (packageJson.dependencies) {
const latestVersions = await getLatestPackageVersions(
packageJson.dependencies,
);
// Helper function to update workspace dependencies
async function updateWorkspaceDependencies(
dependencyType: "dependencies" | "devDependencies",
) {
if (packageJson[dependencyType]) {
const latestVersions = await getLatestPackageVersions(
packageJson[dependencyType],
);
Object.entries(packageJson.dependencies).forEach(([pkg, version]) => {
if (typeof version === "string" && version.includes("workspace:")) {
packageJson.dependencies[pkg] = latestVersions[pkg];
}
});
Object.entries(packageJson[dependencyType]).forEach(
([pkg, version]) => {
if (typeof version === "string" && version.includes("workspace:")) {
packageJson[dependencyType][pkg] = latestVersions[pkg];
}
},
);
}
}
await Promise.all([
updateWorkspaceDependencies("dependencies"),
updateWorkspaceDependencies("devDependencies"),
]);
packageJson.name = projectName;
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
depsSpinner.succeed(chalk.green("Dependencies updated"));
@@ -238,6 +249,56 @@ module.exports = withNativeWind(config, { input: "./src/global.css" });
}
}
// Step 5: Clone cursor-docs
const docsSpinner = ora({
text: chalk.blue(`Adding .cursor directory...`),
spinner: "dots",
}).start();
try {
// Create a temporary directory for cursor-docs
const tempDocsDir = `${projectName}-cursor-docs-temp`;
const emitter = degit("garden-co/jazz/packages/cursor-docs", {
cache: false,
force: true,
verbose: true,
});
// Clone cursor-docs to temp directory
await emitter.clone(tempDocsDir);
// Copy only the .cursor directory to project root
const cursorDirSource = `${tempDocsDir}/.cursor`;
const cursorDirTarget = `${projectName}/.cursor`;
if (fs.existsSync(cursorDirSource)) {
fs.cpSync(cursorDirSource, cursorDirTarget, { recursive: true });
docsSpinner.succeed(chalk.green(".cursor directory added successfully"));
} else {
docsSpinner.fail(chalk.red(".cursor directory not found in cursor-docs"));
}
// Clean up temp directory
fs.rmSync(tempDocsDir, { recursive: true, force: true });
} catch (error) {
docsSpinner.fail(chalk.red("Failed to add .cursor directory"));
throw error;
}
// Step 6: Git init
const gitSpinner = ora({
text: chalk.blue("Initializing git repository..."),
spinner: "dots",
}).start();
try {
execSync(`cd "${projectName}" && git init`, { stdio: "pipe" });
gitSpinner.succeed(chalk.green("Git repository initialized"));
} catch (error) {
gitSpinner.fail(chalk.red("Failed to initialize git repository"));
throw error;
}
// Final success message
console.log("\n" + chalk.green.bold("✨ Project setup completed! ✨\n"));
console.log(chalk.cyan("To get started:"));

View File

@@ -1,5 +1,21 @@
# jazz-browser-media-images
## 0.10.13
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser@0.10.13
## 0.10.12
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-browser@0.10.12
## 0.10.9
### Patch Changes

View File

@@ -1,14 +1,14 @@
{
"name": "jazz-auth-clerk",
"version": "0.10.9",
"version": "0.10.13",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"cojson": "workspace:0.10.8",
"jazz-browser": "workspace:0.10.9",
"jazz-tools": "workspace:0.10.8"
"jazz-browser": "workspace:0.10.13",
"jazz-tools": "workspace:0.10.13"
},
"scripts": {
"format-and-lint": "biome check .",

View File

@@ -1,5 +1,21 @@
# jazz-browser-media-images
## 0.10.13
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-browser@0.10.13
## 0.10.12
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-browser@0.10.12
## 0.10.9
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser-media-images",
"version": "0.10.9",
"version": "0.10.13",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",
@@ -8,8 +8,8 @@
"dependencies": {
"@types/image-blob-reduce": "^4.1.1",
"image-blob-reduce": "^4.1.0",
"jazz-browser": "workspace:0.10.9",
"jazz-tools": "workspace:0.10.8",
"jazz-browser": "workspace:0.10.13",
"jazz-tools": "workspace:0.10.13",
"pica": "^9.0.1",
"typescript": "~5.6.2"
},

View File

@@ -1,5 +1,19 @@
# jazz-browser
## 0.10.13
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
## 0.10.12
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
## 0.10.9
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser",
"version": "0.10.9",
"version": "0.10.13",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,21 @@
# jazz-inspector
## 0.10.10
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react-core@0.10.10
## 0.10.9
### Patch Changes
- Updated dependencies [4612e05]
- jazz-react-core@0.10.9
- jazz-tools@0.10.12
## 0.10.8
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-inspector",
"version": "0.10.8",
"version": "0.10.10",
"type": "module",
"main": "./dist/app.js",
"types": "./dist/app.d.ts",

View File

@@ -1,5 +1,19 @@
# jazz-autosub
## 0.10.13
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
## 0.10.12
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
## 0.10.8
### Patch Changes

View File

@@ -5,7 +5,7 @@
"types": "src/index.ts",
"type": "module",
"license": "MIT",
"version": "0.10.8",
"version": "0.10.13",
"dependencies": {
"cojson": "workspace:*",
"cojson-transport-ws": "workspace:*",

View File

@@ -5,7 +5,7 @@ import { createWorkerAccount } from "jazz-run/createWorkerAccount";
import { startSyncServer } from "jazz-run/startSyncServer";
import { CoMap, co } from "jazz-tools";
import { describe, expect, test } from "vitest";
import { startWorker } from "../index";
import { startWorker } from "../index.js";
class TestMap extends CoMap {
value = co.string;

View File

@@ -9,7 +9,7 @@ import {
co,
} from "jazz-tools";
import { describe, expect, onTestFinished, test } from "vitest";
import { startWorker } from "../index";
import { startWorker } from "../index.js";
async function setup<Acc extends Account>(AccountSchema?: AccountClass<Acc>) {
const { server, port } = await setupSyncServer();

View File

@@ -1,6 +1,6 @@
import { createWebSocketPeer } from "cojson-transport-ws";
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import { webSocketWithReconnection } from "../webSocketWithReconnection";
import { webSocketWithReconnection } from "../webSocketWithReconnection.js";
// Mock dependencies
vi.mock("cojson-transport-ws", () => ({

View File

@@ -1,5 +1,25 @@
# jazz-browser-media-images
## 0.10.13
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-auth-clerk@0.10.13
- jazz-browser@0.10.13
- jazz-react@0.10.13
## 0.10.12
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react@0.10.12
- jazz-auth-clerk@0.10.12
- jazz-browser@0.10.12
## 0.10.9
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react-auth-clerk",
"version": "0.10.9",
"version": "0.10.13",
"type": "module",
"main": "dist/index.js",
"types": "src/index.tsx",

View File

@@ -1,5 +1,20 @@
# jazz-react-core
## 0.10.10
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
## 0.10.9
### Patch Changes
- 4612e05: Fix type inference on `useCoState`
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
## 0.10.8
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-react-core",
"version": "0.10.8",
"version": "0.10.10",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

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