Compare commits

...

72 Commits

Author SHA1 Message Date
Anselm Eickhoff
ae6f3a39c7 Merge pull request #888 from garden-co/changeset-release/main 2024-11-28 07:00:44 +00:00
github-actions[bot]
5d72d0a5a0 Version Packages 2024-11-27 14:25:17 +00:00
Anselm Eickhoff
bb874490c5 Write initial "Defining Schemas" docs (#826)
* Document most of CoValue schemas

* Fix typo and broken links

---------

Co-authored-by: Trisha Lim <hello@trishalim.com>
2024-11-27 14:24:05 +00:00
Anselm Eickhoff
a2c6d0cb16 Merge pull request #883 from garden-co/trishalim-jazz-441
Redesign footer
2024-11-27 14:06:46 +00:00
Trisha Lim
fe6648b3a5 Remove github stars iframe 2024-11-27 13:37:20 +00:00
Anselm Eickhoff
c1ab97d976 Merge pull request #886 from bradstdev/patch-1 2024-11-27 09:05:03 +00:00
Benjamin S. Leveritt
3cb27e11dd Chore: Add changeset 2024-11-27 08:14:38 +00:00
bradstdev
50f94c2b81 Make passkeys discoverable
Reference: https://web.dev/articles/webauthn-discoverable-credentials

"To ensure your credentials are created as passkeys (discoverable credentials), specify residentKey and requireResidentKey when the credential is created."

Bitwarden (and possibly other password managers) won't find passkeys created on other devices unless they are discoverable.
2024-11-27 06:32:26 +10:00
Anselm Eickhoff
3937781246 Merge pull request #885 from garden-co/benjamin-jazz-536
Fix comment regarding localStorage
2024-11-26 19:42:54 +00:00
Benjamin S. Leveritt
44bcf6e411 Fix comment regarding localStorage 2024-11-26 19:25:31 +00:00
Trisha Lim
b66206f1a6 Change footer links for jazz 2024-11-26 13:56:13 +00:00
Trisha Lim
973824795e Redesign footer 2024-11-26 13:53:42 +00:00
Trisha Lim
f4974e5975 Fix inconsistent social icons size 2024-11-26 13:29:43 +00:00
Trisha Lim
9099bbf75f Fix grid layout on mobile 2024-11-26 11:41:52 +00:00
Anselm Eickhoff
e1a40b41eb Merge pull request #879 from sventies/patch-1
Check for clerk.user before rendering the app
2024-11-26 11:29:36 +00:00
sventies
9683e24237 Check for clerk.user
Check if we're actually authed before navigating to the app. (as per the code in the docs as well: https://jazz.tools/docs/authentication/auth-methods#clerk)
2024-11-26 12:12:58 +01:00
Anselm Eickhoff
0ff381b8d5 Merge pull request #872 from garden-co/changeset-release/main 2024-11-25 21:46:23 +00:00
github-actions[bot]
ef7931761a Version Packages 2024-11-25 21:08:25 +00:00
Anselm Eickhoff
da30641856 Merge pull request #829 from garden-co/benjamin-jazz-514 2024-11-25 21:05:46 +00:00
Anselm Eickhoff
01435dc20b Merge pull request #843 from garden-co/benjamin-jazz-494 2024-11-25 21:05:04 +00:00
Anselm Eickhoff
506256e291 Merge pull request #868 from garden-co/jazz-run/json 2024-11-25 21:03:50 +00:00
Anselm Eickhoff
6bb0d38b26 Merge pull request #860 from garden-co/trishalim-jazz-509 2024-11-25 21:03:30 +00:00
Anselm Eickhoff
397ff9ce09 Merge pull request #874 from garden-co/aeplay-jazz-532 2024-11-25 21:02:38 +00:00
Anselm
df42b2b295 Add changesets 2024-11-25 14:43:37 +00:00
Anselm
aae280b7da Implement and test getting all CoMap edits 2024-11-25 14:41:40 +00:00
Anselm Eickhoff
d1e4ee0fe4 Merge pull request #840 from garden-co/benjamin-jazz-524
Fix `jazz-*-auth-clerk` readmes
2024-11-25 13:35:35 +00:00
Benjamin S. Leveritt
7cfd47b7f3 Add minimal example links 2024-11-25 12:37:47 +00:00
Benjamin S. Leveritt
c34ce695ea Improves navigation links 2024-11-25 12:37:47 +00:00
Benjamin S. Leveritt
7666dc6da2 Add documentation for authentication hooks 2024-11-25 12:37:47 +00:00
Benjamin S. Leveritt
be3ac8aa63 Fix formatting 2024-11-25 12:37:47 +00:00
Benjamin S. Leveritt
b759668022 Improve browser auth typedocs 2024-11-25 12:37:47 +00:00
Benjamin S. Leveritt
1ada04f6f4 Add Passphrase section to Auth Methods 2024-11-25 12:37:47 +00:00
Benjamin S. Leveritt
f3455bc691 Add stub typedocs to browser auth 2024-11-25 12:37:47 +00:00
Benjamin S. Leveritt
044f61e3d7 Add authentication method page stub 2024-11-25 12:37:47 +00:00
Trisha Lim
6d63f4cf2e Reuse FeatureCard on Coming Soon section 2024-11-25 12:34:23 +00:00
Trisha Lim
b828f41cf0 Renamed LabelledFeatureIcon to FeatureCard 2024-11-25 12:34:23 +00:00
Trisha Lim
14d24888e1 Make coming soon section 4-col 2024-11-25 12:34:23 +00:00
Trisha Lim
29bdb0a120 Add cols prop to GappedGrid component 2024-11-25 12:34:23 +00:00
Trisha Lim
c7ec6baba8 Create card component 2024-11-25 12:34:23 +00:00
Anselm Eickhoff
f8cf198a27 Merge pull request #709 from garden-co/benjamin-jazz-438 2024-11-25 12:32:59 +00:00
Benjamin S. Leveritt
720435e2f2 Add examples to access coFeed 2024-11-25 12:29:57 +00:00
Benjamin S. Leveritt
2dcf6925b4 Add explanation and example for coFeed.push 2024-11-25 12:29:57 +00:00
Benjamin S. Leveritt
55d49a3435 Update CoFeed ensureLoaded
To clarify depth and undefined states
2024-11-25 12:29:57 +00:00
Benjamin S. Leveritt
33d1c11909 Update packages/jazz-tools/src/coValues/coStream.ts
Co-authored-by: Anselm Eickhoff <anselm.eickhoff@gmail.com>
2024-11-25 12:29:57 +00:00
Benjamin S. Leveritt
02ee69672d Update packages/jazz-tools/src/coValues/interfaces.ts
Co-authored-by: Anselm Eickhoff <anselm.eickhoff@gmail.com>
2024-11-25 12:29:57 +00:00
Benjamin S. Leveritt
743f7d068b Tweak CoList docs 2024-11-25 11:51:01 +00:00
Benjamin S. Leveritt
c0a1bb272e Add docs for type ID 2024-11-25 11:49:49 +00:00
Benjamin S. Leveritt
a9f08ebbbe Add a few more notes for coMaps 2024-11-25 11:49:49 +00:00
Benjamin S. Leveritt
0d86b132ea Add more docs to BinaryCoStream docs 2024-11-25 11:49:46 +00:00
Benjamin S. Leveritt
5114bbec88 Add FileStream docs 2024-11-25 11:46:38 +00:00
Benjamin S. Leveritt
29deedb163 Add coStream docs 2024-11-25 11:39:05 +00:00
Benjamin S. Leveritt
a322a0e3b5 Add more coStream docs 2024-11-25 11:35:19 +00:00
Benjamin S. Leveritt
4fea86141f Fix description 2024-11-25 11:34:47 +00:00
Benjamin S. Leveritt
d923d45a82 Add some initial coStream docs 2024-11-25 11:34:11 +00:00
Trisha Lim
ff52fb3275 Add loading state to button 2024-11-25 10:42:16 +00:00
Anselm
c65a8806f6 Test current CoMap _edits behavior 2024-11-25 10:16:00 +00:00
Trisha Lim
8c8a5b242a Add Gio to team page 2024-11-25 10:03:25 +00:00
Benjamin S. Leveritt
d020ee2825 Merge pull request #856 from garden-co/trishalim-jazz-522
API Reference: typography and spacing adjustments
2024-11-23 07:26:36 +00:00
Guido D'Orsi
2e2a13f22d feat(account): add --json option to output the account info as json 2024-11-22 22:49:05 +01:00
Trisha Lim
b1056c2ed3 Add env var names to turbo.json 2024-11-22 19:31:37 +00:00
Guido D'Orsi
e00489d8ee Merge pull request #865 from garden-co/fix/less-reads-on-known-state
chore(SyncStateSubscriptionManager): improve the internal API
2024-11-22 18:21:39 +01:00
Guido D'Orsi
5a5f886bdf chore: formatting 2024-11-22 18:20:41 +01:00
Guido D'Orsi
e5c575ec10 chore(SyncStateSubscriptionManager): improve the internal API 2024-11-22 18:18:44 +01:00
Trisha Lim
3e0493f88f Create social links component 2024-11-22 17:07:17 +00:00
Trisha Lim
0fa017d148 Add newsletter subscription form to jazz footer 2024-11-22 16:42:31 +00:00
Trisha Lim
7c4f519ca1 Move NewsletterForm component to design system 2024-11-22 16:18:42 +00:00
Trisha Lim
94e3922efc Adjust scroll margin in API Reference pages; fixes #830 2024-11-22 15:00:50 +00:00
Trisha Lim
a18ed077ca API Ref: make headings more prominent 2024-11-22 14:48:16 +00:00
Benjamin S. Leveritt
28fea37446 Fix comment block for rendering with TypeDoc 2024-11-21 20:23:24 +00:00
Benjamin S. Leveritt
61915fe3ed Split doc-generation scripts into separate commands
Easier to run individually
2024-11-21 20:23:24 +00:00
Benjamin S. Leveritt
1a4bda09ca Chore: Add changesets to bump Npm 2024-11-21 08:24:18 +00:00
Benjamin S. Leveritt
815f54fafb Fix readmes 2024-11-21 08:20:49 +00:00
128 changed files with 1951 additions and 775 deletions

View File

@@ -1,5 +1,21 @@
# @jazz-e2e/binarycostream
## 0.0.110
### Patch Changes
- jazz-react@0.8.33
## 0.0.109
### Patch Changes
- Updated dependencies [df42b2b]
- Updated dependencies [df42b2b]
- cojson@0.8.32
- jazz-tools@0.8.32
- jazz-react@0.8.32
## 0.0.108
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "@jazz-e2e/filestream",
"private": true,
"version": "0.0.108",
"version": "0.0.110",
"type": "module",
"scripts": {
"dev": "vite",
@@ -13,11 +13,11 @@
"test:ui": "playwright test --ui"
},
"dependencies": {
"cojson": "workspace:0.8.31",
"cojson": "workspace:0.8.32",
"hash-slash": "workspace:0.2.1",
"is-ci": "^3.0.1",
"jazz-react": "workspace:0.8.31",
"jazz-tools": "workspace:0.8.31",
"jazz-react": "workspace:0.8.33",
"jazz-tools": "workspace:0.8.32",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},

View File

@@ -1,5 +1,21 @@
# @jazz-e2e/covalues
## 0.0.109
### Patch Changes
- jazz-react@0.8.33
## 0.0.108
### Patch Changes
- Updated dependencies [df42b2b]
- Updated dependencies [df42b2b]
- cojson@0.8.32
- jazz-tools@0.8.32
- jazz-react@0.8.32
## 0.0.107
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "@jazz-e2e/covalues",
"private": true,
"version": "0.0.107",
"version": "0.0.109",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,21 @@
# jazz-example-book-shelf
## 0.1.25
### Patch Changes
- jazz-browser-media-images@0.8.33
- jazz-react@0.8.33
## 0.1.24
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react@0.8.32
- jazz-browser-media-images@0.8.32
## 0.1.23
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-example-book-shelf",
"version": "0.1.23",
"version": "0.1.25",
"private": true,
"scripts": {
"dev": "next dev",
@@ -11,9 +11,9 @@
},
"dependencies": {
"clsx": "^2.0.0",
"jazz-browser-media-images": "workspace:0.8.31",
"jazz-react": "workspace:0.8.31",
"jazz-tools": "workspace:0.8.31",
"jazz-browser-media-images": "workspace:0.8.33",
"jazz-react": "workspace:0.8.33",
"jazz-tools": "workspace:0.8.32",
"next": "14.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"

View File

@@ -1,5 +1,24 @@
# jazz-example-chat
## 0.0.109
### Patch Changes
- jazz-react@0.8.33
- jazz-react-auth-clerk@0.8.33
## 0.0.108
### Patch Changes
- Updated dependencies [df42b2b]
- Updated dependencies [1a4bda0]
- Updated dependencies [df42b2b]
- cojson@0.8.32
- jazz-react-auth-clerk@0.8.32
- jazz-tools@0.8.32
- jazz-react@0.8.32
## 0.0.107
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat-clerk",
"private": true,
"version": "0.0.107",
"version": "0.0.109",
"type": "module",
"scripts": {
"dev": "vite",
@@ -17,11 +17,11 @@
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"cojson": "workspace:0.8.31",
"cojson": "workspace:0.8.32",
"hash-slash": "workspace:0.2.1",
"jazz-react": "workspace:0.8.31",
"jazz-react-auth-clerk": "workspace:0.8.31",
"jazz-tools": "workspace:0.8.31",
"jazz-react": "workspace:0.8.33",
"jazz-react-auth-clerk": "workspace:0.8.33",
"jazz-tools": "workspace:0.8.32",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.2.0",

View File

@@ -18,7 +18,7 @@ function JazzAndAuth({ children }: { children: React.ReactNode }) {
{state.errors.map((error) => (
<div key={error}>{error}</div>
))}
{auth ? (
{clerk.user && auth ? (
<Jazz.Provider
auth={auth}
peer="wss://cloud.jazz.tools/?key=chat-example-jazz-clerk@gcmp.io"

View File

@@ -1,5 +1,22 @@
# chat-rn-clerk
## 1.0.25
### Patch Changes
- jazz-react-auth-clerk@0.8.33
## 1.0.24
### Patch Changes
- Updated dependencies [1a4bda0]
- Updated dependencies [df42b2b]
- jazz-react-auth-clerk@0.8.32
- jazz-tools@0.8.32
- jazz-react-native@0.8.32
- jazz-react-native-media-images@0.8.24
## 1.0.23
### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# chat-rn
## 1.0.23
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react-native@0.8.32
## 1.0.22
### Patch Changes

View File

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

View File

@@ -1,5 +1,22 @@
# chat-vue
## 0.0.16
### Patch Changes
- Updated dependencies [3cb27e1]
- jazz-browser@0.8.33
- jazz-vue@0.8.21
## 0.0.15
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-browser@0.8.32
- jazz-vue@0.8.20
## 0.0.14
### Patch Changes

View File

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

View File

@@ -1,5 +1,21 @@
# jazz-example-chat
## 0.0.111
### Patch Changes
- jazz-react@0.8.33
## 0.0.110
### Patch Changes
- Updated dependencies [df42b2b]
- Updated dependencies [df42b2b]
- cojson@0.8.32
- jazz-tools@0.8.32
- jazz-react@0.8.32
## 0.0.109
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.109",
"version": "0.0.111",
"type": "module",
"scripts": {
"dev": "vite",
@@ -18,10 +18,10 @@
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"cojson": "workspace:0.8.31",
"cojson": "workspace:0.8.32",
"hash-slash": "workspace:0.2.1",
"jazz-react": "workspace:0.8.31",
"jazz-tools": "workspace:0.8.31",
"jazz-react": "workspace:0.8.33",
"jazz-tools": "workspace:0.8.32",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.2.0",

View File

@@ -1,5 +1,13 @@
# jazz-example-inspector
## 0.0.80
### Patch Changes
- Updated dependencies [df42b2b]
- cojson@0.8.32
- cojson-transport-ws@0.8.32
## 0.0.79
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector",
"private": true,
"version": "0.0.79",
"version": "0.0.80",
"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.8.31",
"cojson-transport-ws": "workspace:0.8.31",
"cojson": "workspace:0.8.32",
"cojson-transport-ws": "workspace:0.8.32",
"hash-slash": "workspace:0.2.1",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",

View File

@@ -1,5 +1,22 @@
# minimal-auth-clerk
## 0.0.10
### Patch Changes
- jazz-react@0.8.33
- jazz-react-auth-clerk@0.8.33
## 0.0.9
### Patch Changes
- Updated dependencies [1a4bda0]
- Updated dependencies [df42b2b]
- jazz-react-auth-clerk@0.8.32
- jazz-tools@0.8.32
- jazz-react@0.8.32
## 0.0.8
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "minimal-auth-clerk",
"private": true,
"version": "0.0.8",
"version": "0.0.10",
"type": "module",
"scripts": {
"dev": "vite",
@@ -14,7 +14,7 @@
"@clerk/clerk-react": "^5.4.1",
"jazz-tools": "workspace:*",
"jazz-react": "workspace:*",
"jazz-react-auth-clerk": "workspace:0.8.31",
"jazz-react-auth-clerk": "workspace:0.8.33",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},

View File

@@ -1,5 +1,19 @@
# minimal-auth-passkey
## 0.0.9
### Patch Changes
- jazz-react@0.8.33
## 0.0.8
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react@0.8.32
## 0.0.7
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "minimal-auth-passkey",
"private": true,
"version": "0.0.7",
"version": "0.0.9",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,19 @@
# jazz-example-musicplayer
## 0.0.31
### Patch Changes
- jazz-react@0.8.33
## 0.0.30
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react@0.8.32
## 0.0.29
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.29",
"version": "0.0.31",
"type": "module",
"scripts": {
"dev": "vite",
@@ -18,8 +18,8 @@
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"jazz-react": "workspace:0.8.31",
"jazz-tools": "workspace:0.8.31",
"jazz-react": "workspace:0.8.33",
"jazz-tools": "workspace:0.8.32",
"lucide-react": "^0.274.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",

View File

@@ -1,5 +1,21 @@
# jazz-example-onboarding
## 0.0.12
### Patch Changes
- jazz-browser-media-images@0.8.33
- jazz-react@0.8.33
## 0.0.11
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react@0.8.32
- jazz-browser-media-images@0.8.32
## 0.0.10
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-onboarding",
"private": true,
"version": "0.0.10",
"version": "0.0.12",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,19 @@
# jazz-password-manager
## 0.0.30
### Patch Changes
- jazz-react@0.8.33
## 0.0.29
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react@0.8.32
## 0.0.28
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-password-manager",
"private": true,
"version": "0.0.28",
"version": "0.0.30",
"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.8.31",
"jazz-tools": "workspace:0.8.31",
"jazz-react": "workspace:0.8.33",
"jazz-tools": "workspace:0.8.32",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.41.5",

View File

@@ -1,5 +1,21 @@
# jazz-example-pets
## 0.0.128
### Patch Changes
- jazz-browser-media-images@0.8.33
- jazz-react@0.8.33
## 0.0.127
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react@0.8.32
- jazz-browser-media-images@0.8.32
## 0.0.126
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.126",
"version": "0.0.128",
"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.8.31",
"jazz-react": "workspace:0.8.31",
"jazz-tools": "workspace:0.8.31",
"jazz-browser-media-images": "workspace:0.8.33",
"jazz-react": "workspace:0.8.33",
"jazz-tools": "workspace:0.8.32",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.2.0",
@@ -41,7 +41,7 @@
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.14",
"is-ci": "^3.0.1",
"jazz-run": "workspace:0.8.31",
"jazz-run": "workspace:0.8.32",
"postcss": "^8.4.27",
"tailwindcss": "3.3.2",
"typescript": "^5.3.3",

View File

@@ -1,5 +1,22 @@
# todo-vue
## 0.0.14
### Patch Changes
- Updated dependencies [3cb27e1]
- jazz-browser@0.8.33
- jazz-vue@0.8.21
## 0.0.13
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-browser@0.8.32
- jazz-vue@0.8.20
## 0.0.12
### Patch Changes

View File

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

View File

@@ -1,5 +1,19 @@
# jazz-example-todo
## 0.0.127
### Patch Changes
- jazz-react@0.8.33
## 0.0.126
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react@0.8.32
## 0.0.125
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.125",
"version": "0.0.127",
"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.8.31",
"jazz-tools": "workspace:0.8.31",
"jazz-react": "workspace:0.8.33",
"jazz-tools": "workspace:0.8.32",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.2.0",

View File

@@ -12,6 +12,7 @@
"dependencies": {
"@evilmartians/harmony": "^1.0.0",
"@headlessui/react": "^2.2.0",
"@icons-pack/react-simple-icons": "^9.1.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"lucide-react": "^0.436.0",
@@ -19,6 +20,7 @@
"next-themes": "^0.2.1",
"react": "^18",
"react-dom": "^18",
"resend": "^4.0.0",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7"
},

View File

@@ -1,5 +1,7 @@
import { clsx } from "clsx";
import { LucideIcon } from "lucide-react";
import Link from "next/link";
import { Spinner } from "./Spinner";
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
children: React.ReactNode;
@@ -7,6 +9,19 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
size?: "sm" | "md" | "lg";
href?: string;
newTab?: boolean;
icon?: LucideIcon;
loading?: boolean;
loadingText?: string;
}
function ButtonIcon({ icon: Icon, loading }: ButtonProps) {
if (!Icon) return null;
const className = "size-5";
if (loading) return <Spinner className={className} />;
return <Icon strokeWidth={1.5} className={className} />;
}
export function Button(props: ButtonProps) {
@@ -18,6 +33,7 @@ export function Button(props: ButtonProps) {
href,
disabled,
newTab,
loadingText,
} = props;
const sizeClasses = {
@@ -37,6 +53,7 @@ export function Button(props: ButtonProps) {
const classNames = clsx(
className,
"inline-flex items-center justify-center gap-2 rounded-lg text-center transition-colors",
"disabled:pointer-events-none disabled:opacity-70",
sizeClasses[size],
variantClasses[variant],
disabled && "opacity-50 cursor-not-allowed pointer-events-none",
@@ -49,14 +66,21 @@ export function Button(props: ButtonProps) {
target={newTab ? "_blank" : undefined}
className={classNames}
>
<ButtonIcon {...props} />
{children}
</Link>
);
}
return (
<button {...props} className={classNames}>
{children}
<button
{...props}
disabled={props.disabled || props.loading}
className={classNames}
>
<ButtonIcon {...props} />
{props.loading && props.loadingText ? props.loadingText : children}
</button>
);
}

View File

@@ -0,0 +1,12 @@
import { clsx } from "clsx";
export function Card({
children,
className,
}: { children: React.ReactNode; className?: string }) {
return (
<div className={clsx(className, "border rounded-xl shadow-sm")}>
{children}
</div>
);
}

View File

@@ -1,16 +1,16 @@
import clsx from "clsx";
import { ReactNode } from "react";
import { Card } from "../atoms/Card";
export function GridCard(props: { children: ReactNode; className?: string }) {
return (
<div
<Card
className={clsx(
"col-span-2 p-4 [&>h4]:mt-0 [&>h3]:mt-0 [&>:last-child]:mb-0",
"border rounded-xl shadow-sm",
props.className,
)}
>
{props.children}
</div>
</Card>
);
}

View File

@@ -0,0 +1,26 @@
import clsx from "clsx";
export function Spinner({ className }: { className?: string }) {
return (
<svg
className={clsx(className, "animate-spin")}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
);
}

View File

@@ -0,0 +1,36 @@
import clsx from "clsx";
import { LucideIcon } from "lucide-react";
import { Card } from "../atoms/Card";
import { Prose } from "./Prose";
export function FeatureCard({
label,
icon: Icon,
explanation,
children,
className,
}: {
label: React.ReactNode;
icon?: LucideIcon;
explanation?: React.ReactNode;
children?: React.ReactNode;
className?: string;
}) {
return (
<Card className={clsx(className, "p-4")}>
{Icon && (
<Icon
className="size-8 text-blue p-1.5 rounded-lg bg-blue-50 dark:text-blue-500 dark:bg-stone-900 mb-2.5 md:size-10"
strokeWidth={1.5}
strokeLinecap="butt"
size={80}
/>
)}
<div className="text-stone-900 font-medium md:text-base dark:text-stone-100 mb-2">
{label}
</div>
{explanation && <Prose>{explanation}</Prose>}
{children}
</Card>
);
}

View File

@@ -6,15 +6,23 @@ export function GappedGrid({
children,
className,
title,
cols = 3,
}: {
children: ReactNode;
className?: string;
title?: string;
cols?: 3 | 4;
}) {
const colsClassName =
cols === 3
? "grid-cols-2 md:grid-cols-4 lg:grid-cols-6"
: "sm:grid-cols-2 lg:grid-cols-4";
return (
<div
className={clsx(
"grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4 lg:gap-8",
"grid gap-4 lg:gap-8",
colsClassName,
"items-stretch",
className,
)}

View File

@@ -1,37 +0,0 @@
import clsx from "clsx";
import { LucideIcon } from "lucide-react";
import { Prose } from "./Prose";
export function LabelledFeatureIcon({
label,
icon: Icon,
explanation,
className,
}: {
label: string;
icon: LucideIcon;
explanation: React.ReactNode;
className?: string;
}) {
return (
<div
className={clsx(
className,
"text-base",
"rounded-xl",
"border p-4 shadow-sm",
)}
>
<Icon
className="size-8 text-blue p-1.5 rounded-lg bg-blue-50 dark:text-blue-500 dark:bg-stone-900 mb-2.5 md:size-10"
strokeWidth={1.5}
strokeLinecap="butt"
size={80}
/>
<div className="text-stone-900 font-medium md:text-base dark:text-stone-100 mb-2">
{label}
</div>
<Prose>{explanation}</Prose>
</div>
);
}

View File

@@ -19,7 +19,7 @@ export function ThemeToggle({ className }: { className?: string }) {
type="button"
className={clsx(
className,
"md:p-2 md:rounded-full md:border",
"md:p-1.5 md:rounded-full md:border",
"text-stone-400 hover:text-stone-900 dark:text-stone-400 dark:hover:text-white",
"md:hover:bg-stone-200 md:dark:hover:bg-stone-900",
"transition-colors",
@@ -29,13 +29,13 @@ export function ThemeToggle({ className }: { className?: string }) {
>
<MoonIcon
size={24}
strokeWidth={1.5}
className="size-5 md:size-6 stroke-stone-900 dark:hidden"
strokeWidth={2}
className="size-5 stroke-stone-900 dark:hidden"
/>
<SunIcon
size={24}
strokeWidth={1.5}
className="size-5 md:size-6 hidden stroke-white dark:block"
strokeWidth={2}
className="size-5 hidden stroke-white dark:block"
/>
</button>
);

View File

@@ -5,6 +5,8 @@ import Link from "next/link";
import { usePathname } from "next/navigation";
import { ReactNode } from "react";
import { ThemeToggle } from "../molecules/ThemeToggle";
import { NewsletterForm } from "./NewsletterForm";
import { SocialLinks, SocialLinksProps } from "./SocialLinks";
type FooterSection = {
title: string;
@@ -19,6 +21,7 @@ type FooterProps = {
logo: ReactNode;
companyName: string;
sections: FooterSection[];
socials: SocialLinksProps;
};
function Copyright({
@@ -35,38 +38,54 @@ function Copyright({
);
}
export function Footer({ logo, companyName, sections }: FooterProps) {
export function Footer({ logo, companyName, sections, socials }: FooterProps) {
return (
<footer className="w-full border-t bg-stone-100 mt-12 md:mt-20 dark:bg-stone-925">
<div className="container py-8 md:py-16 grid gap-y-8 grid-cols-12">
<div className="flex flex-col justify-between col-span-full md:col-span-4">
{logo}
<Copyright className="hidden md:block" companyName={companyName} />
</div>
{sections.map((section, index) => (
<div
key={index}
className="flex flex-col gap-2 text-sm col-span-4 sm:col-span-4 md:col-span-2"
>
<h2 className="font-medium">{section.title}</h2>
{section.links.map((link, linkIndex) => (
<FooterLink key={linkIndex} href={link.href} newTab={link.newTab}>
{link.label}
</FooterLink>
))}
<footer className="w-full py-8 mt-12 md:mt-20">
<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}
</div>
))}
<div className="hidden md:flex justify-end items-end md:col-span-2">
<ThemeToggle />
<p className="col-span-full sm:col-span-6 md:col-span-4 text-sm sm:text-base">
Playful software for serious problems.
</p>
</div>
<div className="grid gap-y-8 grid-cols-12">
<div className="flex flex-col gap-4 col-span-full md:col-span-8">
<p className="font-medium text-stone-900 dark:text-white">
Stay up to date
</p>
<NewsletterForm />
</div>
<Copyright
className="col-span-full md:hidden"
companyName={companyName}
/>
{sections.map((section, index) => (
<div
key={index}
className="flex flex-col gap-2 text-sm col-span-6 md:col-span-2"
>
<h2 className="font-medium">{section.title}</h2>
{section.links.map((link, linkIndex) => (
<FooterLink
key={linkIndex}
href={link.href}
newTab={link.newTab}
>
{link.label}
</FooterLink>
))}
</div>
))}
<Copyright
className="order-last col-span-full self-center md:col-span-10 md:order-none"
companyName={companyName}
/>
<div className="col-span-full flex items-center justify-between gap-6 md:col-span-2">
<SocialLinks {...socials}></SocialLinks>
<ThemeToggle className="hidden md:block" />
</div>
</div>
</div>
</footer>
);

View File

@@ -14,6 +14,7 @@ import { usePathname } from "next/navigation";
import { ReactNode, useEffect, useLayoutEffect, useRef, useState } from "react";
import { BreadCrumb } from "../molecules/Breadcrumb";
import { ThemeToggle } from "../molecules/ThemeToggle";
import { SocialLinks, SocialLinksProps } from "./SocialLinks";
type NavItemProps = {
href: string;
@@ -30,6 +31,7 @@ type NavProps = {
items: NavItemProps[];
docNav?: ReactNode;
cta?: ReactNode;
socials?: SocialLinksProps;
};
function NavItem({
@@ -110,7 +112,7 @@ function NavItem({
);
}
export function MobileNav({ mainLogo, items, docNav, cta }: NavProps) {
export function MobileNav({ mainLogo, items, docNav, cta, socials }: NavProps) {
const [menuOpen, setMenuOpen] = useState(false);
const [searchOpen, setSearchOpen] = useState(false);
const searchRef = useRef<HTMLInputElement>(null);
@@ -170,13 +172,8 @@ export function MobileNav({ mainLogo, items, docNav, cta }: NavProps) {
>
{mainLogo}
</NavLinkLogo>
{items
.filter((item) => "icon" in item)
.map((item, i) => (
<NavLinkLogo key={i} href={item.href} newTab={item.newTab}>
{item.icon}
</NavLinkLogo>
))}
<SocialLinks className="px-2 gap-2" {...socials} />
</div>
{pathname.startsWith("/docs") && docNav && (
@@ -310,6 +307,8 @@ export function Nav(props: NavProps) {
/>
))}
<SocialLinks {...props.socials} />
{cta}
</PopoverGroup>
</div>

View File

@@ -1,30 +1,37 @@
"use client";
import { subscribe } from "@/app/actions/resend";
import { Button } from "gcmp-design-system/src/app/components/atoms/Button";
import { Input } from "gcmp-design-system/src/app/components/molecules/Input";
import { CheckIcon } from "lucide-react";
import { CheckIcon, MailIcon } from "lucide-react";
import { useState } from "react";
import { ErrorResponse } from "resend";
import { subscribe } from "../../../actions/resend";
import { Button } from "../atoms/Button";
import { Input } from "../molecules/Input";
export function NewsletterForm() {
const [email, setEmail] = useState("");
const [subscribed, setSubscribed] = useState(false);
// const [subscribed, setSubscribed] = useState(false);
const [error, setError] = useState<ErrorResponse | undefined>();
const [state, setState] = useState<"ready" | "loading" | "success" | "error">(
"ready",
);
const submit = async (e: React.FormEvent) => {
e.preventDefault();
setState("loading");
const res = await subscribe(email);
if (res.error) {
setError(res.error);
setState("error");
} else {
setSubscribed(true);
setState("success");
}
};
if (subscribed) {
if (state === "success") {
return (
<div className="flex gap-3 items-center">
<CheckIcon className="text-green-500" size={16} />
@@ -33,12 +40,12 @@ export function NewsletterForm() {
);
}
if (error) {
if (state === "error" && error?.message) {
return <p className="text-red-700">Error: {error.message}</p>;
}
return (
<form action="" onSubmit={submit} className="flex gap-x-4 w-120 max-w-xl">
<form action="" onSubmit={submit} className="flex gap-x-4 w-120 max-w-md">
<Input
id="email-address"
name="email"
@@ -51,7 +58,13 @@ export function NewsletterForm() {
className="flex-1 label:sr-only"
label="Email address"
/>
<Button type="submit" variant="secondary">
<Button
type="submit"
variant="secondary"
loadingText="Subscribing..."
loading={state === "loading"}
icon={MailIcon}
>
Subscribe
</Button>
</form>

View File

@@ -0,0 +1,51 @@
import { SiDiscord, SiGithub, SiX } from "@icons-pack/react-simple-icons";
import { clsx } from "clsx";
export interface SocialLinksProps {
github?: string;
x?: string;
discord?: string;
}
const socials = [
{
name: "Github",
icon: SiGithub,
key: "github",
size: 20,
},
{
name: "Discord",
icon: SiDiscord,
key: "discord",
size: 23,
},
{
name: "X",
icon: SiX,
key: "x",
size: 18,
},
];
export function SocialLinks(props: SocialLinksProps & { className?: string }) {
return (
<div className={clsx(props.className, "inline-flex gap-6 items-center")}>
{socials.map(
(social) =>
props[social.key as keyof SocialLinksProps] && (
<a
key={social.key}
href={props[social.key as keyof SocialLinksProps]}
target="_blank"
rel="noreferrer"
className="flex hover:text-stone-900 hover:dark:text-white"
>
<social.icon size={social.size} />
<span className="sr-only">{social.name}</span>
</a>
),
)}
</div>
);
}

View File

@@ -1,4 +1,5 @@
import { Prose } from "@components/molecules/Prose";
import { NewsletterForm } from "@components/organisms/NewsletterForm";
export default function Home() {
return (
@@ -63,6 +64,12 @@ export default function Home() {
</Prose>
</div>
</div>
<h2>Newsletter Subscription Form</h2>
<div className="p-3 border">
<NewsletterForm />
</div>
</main>
);
}

View File

@@ -1,7 +1,7 @@
import { NewsletterForm } from "@/components/NewsletterForm";
import { Posts } from "@/components/blog/Posts";
import { HeroHeader } from "gcmp-design-system/src/app/components/molecules/HeroHeader";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { NewsletterForm } from "gcmp-design-system/src/app/components/organisms/NewsletterForm";
import Link from "next/link";
export const metadata = {

View File

@@ -69,6 +69,15 @@ const team: Array<TeamMember> = [
github: "marinoska",
image: "marina.jpeg",
},
{
name: "Giordano Ricci",
titles: ["Full-Stack Dev", "DevOps"],
location: "Lisbon, Portugal ",
linkedin: "giordanoricci",
github: "Elfo404",
website: "https://giordanoricci.com",
image: "gio.jpg",
},
];
function SocialLink({

View File

@@ -28,7 +28,6 @@
"next": "14.2.15",
"react": "^18",
"react-dom": "^18",
"resend": "^4.0.0",
"shiki": "^0.14.6",
"shiki-twoslash": "^3.1.2",
"tailwind-merge": "^1.14.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -15,7 +15,7 @@ export default function Layout({
}) {
return (
<DocsLayout nav={<ApiNav />}>
<Prose className="py-8">{children}</Prose>
<Prose className="py-8 [&_*]:scroll-mt-[8rem]">{children}</Prose>
</DocsLayout>
);
}

View File

@@ -0,0 +1,111 @@
import { CodeGroup } from "@/components/forMdx";
# Authentication methods
Jazz supports a variety of authentication methods, which you can use to authenticate users in your app.
- Passphrase (built-in)
- Passkey (built-in)
- Clerk ([React](https://www.npmjs.com/package/jazz-react-auth-clerk) and [vanilla](https://www.npmjs.com/package/jazz-browser-auth-clerk) packages)
## Passphrase
Passphrase authentication allows users to create a new account or log in with an existing one by providing a passphrase.
Passphrase authentication is supported out of the box and imported from `jazz-react`.
### How to use
1. Setup up Jazz as described in the [React setup guide](/docs/project-setup/react).
2. Use the `usePassphraseAuth` hook to authenticate.
<CodeGroup>
```ts
import { usePassphraseAuth } from "jazz-react";
// ...
const [passphraseAuth, passphraseState] = usePassphraseAuth({ appName });
```
</CodeGroup>
## Passkey
Passkey authentication allows users to create a new account or log in with an existing one by providing a passkey.
Passkey authentication is supported out of the box.
We have a [minimal example of a passkey authentication setup](https://github.com/garden-co/jazz/tree/main/examples/minimal-auth-passkey).
### How to use
1. Setup up Jazz as described in the [React setup guide](/docs/project-setup/react).
2. Use the `usePasskeyAuth` hook to authenticate.
<CodeGroup>
```ts
import { usePasskeyAuth } from "jazz-react";
// ...
const [passkeyAuth, passkeyState] = usePasskeyAuth({ appName });
```
</CodeGroup>
## Clerk
We have a React package `jazz-react-auth-clerk` to add Clerk authentication to your app.
We have a [minimal example of a Clerk authentication setup](https://github.com/garden-co/jazz/tree/main/examples/minimal-auth-clerk).
### How to use
1. Setup up Jazz as described in the [React setup guide](/docs/project-setup/react).
2. Install Clerk as described in the [Clerk docs](https://clerk.com/docs/components/overview).
3. Then add the appropriate package to your project (e.g. `jazz-react-auth-clerk`).
<CodeGroup>
```bash
pnpm install jazz-react-auth-clerk
```
</CodeGroup>
4. Provide a Clerk instance to the `useJazzClerkAuth` hook.
<CodeGroup>
```tsx
import { useClerk, SignInButton } from "@clerk/clerk-react";
import { useJazzClerkAuth } from "jazz-react-auth-clerk";
// ...
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk);
return (
<>
{clerk.user && auth ? (
<Jazz.Provider auth={auth}></Jazz.Provider>
) : (
<SignInButton />
)}
</>
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ClerkProvider publishableKey={PUBLISHABLE_KEY} afterSignOutUrl="/">
<JazzAndAuth>
<App />
</JazzAndAuth>
</ClerkProvider>
</StrictMode>,
);
```
</CodeGroup>

View File

@@ -1,4 +1,4 @@
import { CodeGroup } from "@/components/forMdx";
import { CodeGroup, ComingSoon } from "@/components/forMdx";
# React guide
@@ -836,8 +836,5 @@ export function ProjectComponent({ projectID }: { projectID: ID<Project> }) {//
</CodeGroup>
### Consuming invites
<div className="text-amber-500 mt-52">
🚧 OH NO - This is as far as we've written the Guide. 🚧
</div>
{" -> "}
<a href="https://github.com/gardencmp/jazz/issues/186">Complain on GitHub</a>
<ComingSoon/>

View File

@@ -1,4 +1,4 @@
import { CodeGroup } from "@/components/forMdx";
import { CodeGroup, ComingSoon } from "@/components/forMdx";
# CoValues
@@ -9,7 +9,7 @@ As their name suggests, they are inherently collaborative, meaning **multiple us
- CoValues allow for concurrent edits by always keeping their full edit histories, deriving the "current state" based on the currently locally available history.
- **Think of CoValues as "super-fast Git for lots of tiny data".**
- (The fact that this happens in an eventually-consistent way makes them [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type))
- Having the full history around also means that you often don't need explicit timestamps and author info - you get this for free, just by having different accounts edit a value and then looking at its [edit metadata](/docs/covalues/metadata).
- Having the full history around also means that you often don't need explicit timestamps and author info - you get this for free, just by having different accounts edit a value and then looking at its [edit metadata](/docs/coming-soon).
CoValues mostly model JSON with CoMaps and CoLists, but also offer CoStreams for simple per-user value streams, and also let you represent binary data with BinaryCoStreams.
@@ -56,10 +56,84 @@ const project: TodoProject = TodoProject.create(
## CoValue field types
Before we look at the different types of CoValues, let's learn what we can put *into* them:
Before we look at the different types of CoValues, let's learn what we can put *into* them.
### Primitive fields
### Refs
You can define primitive field types using the `co` definer:
<CodeGroup>
{/* prettier-ignore */}
```ts
import { co } from "jazz-tools";
export class Person extends CoMap {
title = co.string;
}
export class ListOfColors extends CoList.Of(co.string) {}
```
</CodeGroup>
Here's a quick overview of the primitive types you can use:
<CodeGroup>
{/* prettier-ignore */}
```ts
co.string;
co.number;
co.boolean;
co.null;
co.Date;
co.literal("waiting", "ready");
```
</CodeGroup>
Finally, for more complex JSON data, that you *don't want to be collaborative internally* (but only every update as a whole), you can use `co.json<T>()`:
<CodeGroup>
{/* prettier-ignore */}
```ts
co.json<{ name: string }>();
```
</CodeGroup>
For more detail, see the API Reference for the [`co` Field Definer](/api-reference/jazz-tools#co).
### Refs to other CoValues
To represent complex structured data with Jazz, you form trees or graphs of CoValues that reference each other.
Internally, this is represented by storing the IDs of the referenced CoValues in the corresponding fields, but Jazz abstracts this away, making it look like nested CoValues you can get or assign/insert.
The important caveat here is that **a referenced CoValue might or might not be loaded yet,** but we'll see what exactly that means in [Subscribing and Deep Loading](/docs/coming-soon).
In Schemas, you define Refs using the `co.ref<T>()` definer:
<CodeGroup>
{/* prettier-ignore */}
```ts
class Company extends CoMap {
members = co.ref(ListOfPeople);
}
class ListOfPeople extends CoList.Of(co.ref(Person)) {}
```
</CodeGroup>
#### Optional Refs
If you want to make a referenced CoValue field optional, you *have to* use `co.optional.ref<T>()`:
<CodeGroup>
{/* prettier-ignore */}
```ts
class Person extends CoMap {
pet = co.optional.ref(Pet);
}
```
</CodeGroup>
### Computed fields, methods & constructors
<ComingSoon/>

View File

@@ -0,0 +1,14 @@
import { Button } from "@headlessui/react";
export function ComingSoon() {
return (
<>
<div className="text-amber-500 mt-16">
🚧 OH NO - This is as far as we've written the page. 🚧
</div>
<a href="https://github.com/garden-co/jazz/issues/186">
Complain on GitHub {" -> "}
</a>
</>
);
}

View File

@@ -70,7 +70,11 @@ function RenderPackageChild({
return child.getAllSignatures().map((signature, i) => {
const paramTypes = printParamsWithTypes(signature);
return (
<div key={i} id={child.name} className="not-prose mt-4">
<div
key={i}
id={child.name}
className="not-prose mt-4 p-3 rounded bg-stone-50 dark:bg-stone-925"
>
{
<Highlight hide={[0, 2]}>
{`function \n${printSimpleSignature(child, signature) + ":"}\n {}`}
@@ -171,10 +175,7 @@ function RenderClassOrInterface({
</div>
)}
{classOrInterface.categories?.map((category) => (
<div
className="flex flex-col divide-y divide-stone-200 dark:divide-stone-900"
key={category.title}
>
<div className="flex flex-col mt-6 first:mt-0" key={category.title}>
<PropCategory
name={category.title}
description={renderSummary(

View File

@@ -80,15 +80,15 @@ export function ClassOrInterface({
className="inline-flex items-center gap-2 lg:-ml-[22px]"
>
<LinkIcon size={14} className="hidden lg:inline" />
<h3>
<h3 className="text-lg lg:text-xl">
<Highlight>
{(isInterface ? "interface " : "class ") + name + typeParameters}
</Highlight>
</h3>
</Link>
</div>
<div className="flex flex-col gap-5">
<div>{doc}</div>
<div className="flex flex-col gap-5 mt-5">
{doc && <div>{doc}</div>}
<div>{children}</div>
</div>
</div>
@@ -119,7 +119,7 @@ export function PropDecl({
example?: ReactNode;
}) {
return (
<div className="text-sm py-3 flex flex-col gap-5">
<div className="text-sm flex flex-col gap-3 my-2 p-3 rounded bg-stone-50 dark:bg-stone-925">
{(name || type) && (
<div>
{name && <Highlight>{name + ":"}</Highlight>}
@@ -157,7 +157,7 @@ export function FnDecl({
example: ReactNode;
}) {
return (
<div className="text-sm py-3 flex flex-col gap-5">
<div className="text-sm flex flex-col gap-3 my-2 p-3 rounded bg-stone-50 dark:bg-stone-925">
<div className="flex flex-col gap-2">
<div>
{<Highlight>{signature + ":"}</Highlight>}{" "}
@@ -201,7 +201,7 @@ export function PropCategory({
}) {
return (
<>
<div className="col-span-6 uppercase font-medium tracking-widest text-stone-500 text-xs py-3">
<div className="col-span-6 py-3 font-display font-semibold text-lg text-stone-900 dark:text-white">
{name}
</div>
{description && <PropDecl doc={description} example={example} />}

View File

@@ -1,45 +1,24 @@
import { socials } from "@/lib/socials";
import { GcmpLogo } from "gcmp-design-system/src/app/components/atoms/logos/GcmpLogo";
import { Footer } from "gcmp-design-system/src/app/components/organisms/Footer";
export function JazzFooter() {
return (
<Footer
logo={<GcmpLogo monochrome className="w-32" />}
logo={<GcmpLogo monochrome className="w-36" />}
companyName="Garden Computing, Inc."
socials={socials}
sections={[
{
title: "Resources",
links: [
{ href: "/", label: "Toolkit" },
{ href: "/cloud", label: "Jazz Cloud" },
{ href: "/docs", label: "Docs" },
],
},
{
title: "Community",
title: "About",
links: [
{
href: "https://github.com/gardencmp/jazz",
label: "GitHub",
href: "https://garden.co/team",
label: "Team",
newTab: true,
},
{
href: "https://discord.gg/utDMjHYg42",
label: "Discord",
newTab: true,
},
{
href: "https://x.com/jazz_tools",
label: "X",
newTab: true,
},
],
},
{
title: "News",
links: [
{
href: "https://gcmp.io/news",
href: "https://garden.co/news",
label: "Blog",
newTab: true,
},
@@ -50,6 +29,23 @@ export function JazzFooter() {
},
],
},
{
title: "Resources",
links: [
{
href: "/docs",
label: "Documentation",
},
{
href: "/examples",
label: "Examples",
},
{
href: "/showcase",
label: "Built with Jazz",
},
],
},
]}
/>
);

View File

@@ -4,6 +4,7 @@ import {
} from "@/components/CodeExampleTabs";
import { CodeGroup as CodeGroupClient } from "gcmp-design-system/src/app/components/molecules/CodeGroup";
import { ComingSoon as ComingSoonClient } from "./docs/ComingSoon";
export function CodeExampleTabs(props: CodeExampleTabsProps) {
return <CodeExampleTabsClient {...props} />;
@@ -12,3 +13,7 @@ export function CodeExampleTabs(props: CodeExampleTabsProps) {
export function CodeGroup(props: { children: React.ReactNode }) {
return <CodeGroupClient {...props}></CodeGroupClient>;
}
export function ComingSoon() {
return <ComingSoonClient />;
}

View File

@@ -1,5 +1,6 @@
"use client";
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
@@ -22,7 +23,7 @@ function Iframe(
const { src, user } = props;
return (
<div className="relative col-span-2 w-full border rounded-xl shadow-sm overflow-hidden lg:col-span-2 dark:bg-black">
<Card className="relative col-span-2 w-full overflow-hidden lg:col-span-2 dark:bg-black">
<iframe
{...props}
src={src}
@@ -31,7 +32,7 @@ function Iframe(
height="390"
allowFullScreen
/>
</div>
</Card>
);
}

View File

@@ -1,3 +1,4 @@
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
@@ -42,8 +43,8 @@ export function CollaborationFeaturesSection() {
<GappedGrid>
{data.map(({ title, description, codeSample: CodeSample }) => (
<div
className="col-span-2 border rounded-xl shadow-sm pt-4 px-4 flex flex-col gap-3"
<Card
className="col-span-2 pt-4 px-4 flex flex-col gap-3"
key={title}
>
<div>
@@ -57,7 +58,7 @@ export function CollaborationFeaturesSection() {
<pre className="flex-1 text-sm border-t border-x rounded-t-lg bg-stone-50 dark:bg-stone-925">
<CodeSample />
</pre>
</div>
</Card>
))}
</GappedGrid>
</div>

View File

@@ -3,9 +3,8 @@ import CursorsAndCaretsDescription from "@/app/(home)/toolkit/cursorsAndCarets.m
import TwoWaySyncDescription from "@/app/(home)/toolkit/twoWaySync.mdx";
import VideoPresenceCallsDescription from "@/app/(home)/toolkit/videoPresenceCalls.mdx";
import { CodeRef } from "gcmp-design-system/src/app/components/atoms/CodeRef";
import { GridCard } from "gcmp-design-system/src/app/components/atoms/GridCard";
import { H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { P } from "gcmp-design-system/src/app/components/atoms/Paragraph";
import { FeatureCard } from "gcmp-design-system/src/app/components/molecules/FeatureCard";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
@@ -15,39 +14,40 @@ export function ComingSoonSection() {
<div>
<SectionHeader title="More features coming soon" />
<GappedGrid>
<GridCard>
<H3>Cursors & carets</H3>
<P className="text-lg">Ready-made spatial presence.</P>
<GappedGrid cols={4}>
<FeatureCard className="p-4" label={<h3>Cursors & carets</h3>}>
<P>Ready-made spatial presence.</P>
<Prose size="sm">
<CursorsAndCaretsDescription />
</Prose>
</GridCard>
</FeatureCard>
<GridCard>
<H3>Two-way sync to your DB</H3>
<P className="text-lg">Add Jazz to an existing app.</P>
<FeatureCard className="p-4" label={<h3>Two-way sync to your DB</h3>}>
<P>Add Jazz to an existing app.</P>
<Prose size="sm">
<TwoWaySyncDescription />
</Prose>
</GridCard>
</FeatureCard>
<GridCard>
<H3>Video presence & calls</H3>
<P className="text-lg">Stream and record audio & video.</P>
<FeatureCard className="p-4" label={<h3>Video presence & calls</h3>}>
<P>Stream and record audio & video.</P>
<Prose size="sm">
<VideoPresenceCallsDescription />
</Prose>
</GridCard>
</FeatureCard>
<GridCard>
<H3>
<CodeRef>CoPlainText</CodeRef> & <CodeRef>CoRichText</CodeRef>
</H3>
<FeatureCard
className="p-4"
label={
<h3>
<CodeRef>CoPlainText</CodeRef> & <CodeRef>CoRichText</CodeRef>
</h3>
}
>
<Prose size="sm">
<CoPlainTextDescription />
</Prose>
</GridCard>
</FeatureCard>
</GappedGrid>
</div>
);

View File

@@ -1,10 +1,11 @@
import { Button } from "gcmp-design-system/src/app/components/atoms/Button";
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H2 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
export function EarlyAdopterSection() {
return (
<div className="border rounded-xl shadow-sm p-4 md:py-16">
<Card className="p-4 md:py-16">
<div className="lg:max-w-3xl md:text-center mx-auto space-y-6">
<p className="uppercase text-blue tracking-widest text-sm font-medium dark:text-stone-400">
Become an early adopter
@@ -31,6 +32,6 @@ export function EarlyAdopterSection() {
</Button>
</div>
</div>
</div>
</Card>
);
}

View File

@@ -1,3 +1,4 @@
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { LockKeyholeIcon } from "lucide-react";
@@ -64,7 +65,7 @@ function Illustration() {
export function EncryptionSection() {
return (
<div className="border rounded-xl bg-white shadow-sm overflow-hidden dark:bg-stone-925">
<Card className="overflow-hidden dark:bg-stone-925">
<div className="flex grid md:grid-cols-3 md:gap-3">
<div className="md:col-span-2 px-4 pb-4 md:p-8">
<H3 className="mb-0 text-balance">
@@ -86,6 +87,6 @@ export function EncryptionSection() {
<Illustration />
</div>
</div>
</Card>
);
}

View File

@@ -1,6 +1,7 @@
import { ServerWorkersDiagram } from "@/components/home/ServerWorkersDiagram";
import { ClerkLogo } from "@/components/icons/ClerkLogo";
import { Button } from "gcmp-design-system/src/app/components/atoms/Button";
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
@@ -124,10 +125,7 @@ export function FeaturesSection() {
<div className="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-6 gap-4 lg:gap-8">
{features.map(({ title, icon: Icon, description, illustration }) => (
<div
key={title}
className="col-span-2 border rounded-xl shadow-sm overflow-hidden"
>
<Card key={title} className="col-span-2 overflow-hidden">
<div className="h-48 flex w-full items-center justify-center">
{illustration}
</div>
@@ -137,7 +135,7 @@ export function FeaturesSection() {
</h3>
<Prose size="sm">{description}</Prose>
</div>
</div>
</Card>
))}
<div className="border p-4 sm:p-8 shadow-sm rounded-xl col-span-2 sm:col-span-4 space-y-5">

View File

@@ -1,4 +1,5 @@
import { clsx } from "clsx";
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H2 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import CodeStepAction from "./CodeStepAction.mdx";
@@ -48,10 +49,10 @@ function Step({
className?: string;
}) {
return (
<div
<Card
className={clsx(
className,
"rounded-lg overflow-hidden shadow-sm flex flex-col gap-6 border",
"overflow-hidden flex flex-col gap-6",
"pt-4 sm:pt-6",
"col-span-2 lg:col-span-3",
)}
@@ -70,7 +71,7 @@ function Step({
<p className="max-w-md">{description}</p>
</div>
<div className="flex-1 pl-4 sm:pl-12">{children}</div>
</div>
</Card>
);
}

View File

@@ -1,4 +1,5 @@
import { LabelledFeatureIcon } from "gcmp-design-system/src/app/components/molecules/LabelledFeatureIcon";
import { FeatureCard } from "gcmp-design-system/src/app/components/molecules/FeatureCard";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
import {
GaugeIcon,
@@ -64,16 +65,16 @@ export function LocalFirstFeaturesSection() {
</>
}
/>
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-4 lg:gap-8">
<GappedGrid cols={4}>
{features.map(({ title, icon: Icon, description }) => (
<LabelledFeatureIcon
<FeatureCard
label={title}
icon={Icon}
explanation={description}
key={title}
></LabelledFeatureIcon>
></FeatureCard>
))}
</div>
</GappedGrid>
</div>
);
}

View File

@@ -1,5 +1,4 @@
import { SiDiscord, SiGithub, SiX } from "@icons-pack/react-simple-icons";
import { Button } from "gcmp-design-system/src/app/components/atoms/Button";
import { socials } from "@/lib/socials";
import { JazzLogo } from "gcmp-design-system/src/app/components/atoms/logos/JazzLogo";
import { Nav } from "gcmp-design-system/src/app/components/organisms/Nav";
import { BookTextIcon, BoxIcon, CodeIcon } from "lucide-react";
@@ -68,25 +67,8 @@ export function JazzNav() {
href: "https://github.com/gardencmp/jazz/releases",
newTab: true,
},
{
title: "GitHub",
href: "https://github.com/gardencmp/jazz",
newTab: true,
icon: <SiGithub className="w-5" />,
},
{
title: "Discord",
href: "https://discord.gg/utDMjHYg42",
newTab: true,
icon: <SiDiscord className="w-5" />,
},
{
title: "X",
href: "https://x.com/jazz_tools",
newTab: true,
icon: <SiX className="w-5" />,
},
]}
socials={socials}
docNav={<DocNav className="block h-auto" />}
/>
);

View File

@@ -111,12 +111,27 @@ export const docNavigationItems = [
],
},
{
name: "Authentication",
name: "Authentication methods",
items: [
{
name: "Auth methods overview",
name: "Overview",
href: "/docs/authentication/auth-methods",
done: 0,
done: 80,
},
{
name: "Passphrase",
href: "/docs/authentication/auth-methods#passphrase",
done: 20,
},
{
name: "Passkey",
href: "/docs/authentication/auth-methods#passkey",
done: 20,
},
{
name: "Clerk",
href: "/docs/authentication/auth-methods#clerk",
done: 20,
},
{
name: "Writing your own",

View File

@@ -0,0 +1,5 @@
export const socials = {
github: "https://github.com/gardencmp/jazz",
discord: "https://discord.gg/utDMjHYg42",
x: "https://x.com/jazz_tools",
};

View File

@@ -10,10 +10,6 @@ const nextConfig = {
// Configure `pageExtensions`` to include MDX files
pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"],
transpilePackages: ["gcmp-design-system"],
// Optionally, add any other Next.js config below
experimental: {
serverActions: true,
},
};
const withMDX = createMDX({

View File

@@ -5,7 +5,8 @@
"type": "module",
"scripts": {
"dev": "NODE_OPTIONS=--max-old-space-size=8192 next dev",
"build": "node genDocs.mjs --build && next build",
"build:generate-docs": "node genDocs.mjs --build",
"build": "pnpm run build:generate-docs && next build",
"start": "next start",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write"
@@ -27,7 +28,7 @@
"mdast-util-from-markdown": "^2.0.0",
"mdast-util-mdx": "^3.0.0",
"micromark-extension-mdxjs": "^3.0.0",
"next": "13.5.4",
"next": "14.2.15",
"qrcode": "^1.5.4",
"react": "^18",
"react-dom": "^18",

493
homepage/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,12 @@
# cojson-storage-indexeddb
## 0.8.32
### Patch Changes
- Updated dependencies [df42b2b]
- cojson@0.8.32
## 0.8.31
### Patch Changes

View File

@@ -1,12 +1,12 @@
{
"name": "cojson-storage-indexeddb",
"version": "0.8.31",
"version": "0.8.32",
"main": "dist/index.js",
"type": "module",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"cojson": "workspace:0.8.31"
"cojson": "workspace:0.8.32"
},
"devDependencies": {
"@vitest/browser": "^0.34.1",

View File

@@ -1,5 +1,12 @@
# cojson-storage-sqlite
## 0.8.32
### Patch Changes
- Updated dependencies [df42b2b]
- cojson@0.8.32
## 0.8.31
### Patch Changes

View File

@@ -1,13 +1,13 @@
{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.8.31",
"version": "0.8.32",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"better-sqlite3": "^8.5.2",
"cojson": "workspace:0.8.31",
"cojson": "workspace:0.8.32",
"typescript": "^5.3.3"
},
"devDependencies": {

View File

@@ -1,5 +1,12 @@
# cojson-transport-nodejs-ws
## 0.8.32
### Patch Changes
- Updated dependencies [df42b2b]
- cojson@0.8.32
## 0.8.31
### Patch Changes

View File

@@ -1,12 +1,12 @@
{
"name": "cojson-transport-ws",
"type": "module",
"version": "0.8.31",
"version": "0.8.32",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"cojson": "workspace:0.8.31",
"cojson": "workspace:0.8.32",
"typescript": "^5.3.3"
},
"scripts": {

View File

@@ -1,5 +1,11 @@
# cojson
## 0.8.32
### Patch Changes
- df42b2b: Catch hard-to-debug errors when trying to get edits at a CoMap key called "constructor"
## 0.8.31
### Patch Changes

View File

@@ -19,7 +19,7 @@
},
"type": "module",
"license": "MIT",
"version": "0.8.31",
"version": "0.8.32",
"devDependencies": {
"@types/jest": "^29.5.3",
"typescript": "^5.3.3",

View File

@@ -6,15 +6,19 @@ import {
emptyKnownState,
} from "./sync.js";
export type SyncStateGetter = {
isUploaded: boolean;
};
export type GlobalSyncStateListenerCallback = (
peerId: PeerID,
knownState: CoValueKnownState,
getIsUploadCompleted: () => boolean,
sync: SyncStateGetter,
) => void;
export type PeerSyncStateListenerCallback = (
knownState: CoValueKnownState,
getIsUploadCompleted: () => boolean,
sync: SyncStateGetter,
) => void;
export class SyncStateSubscriptionManager {
@@ -66,18 +70,29 @@ export class SyncStateSubscriptionManager {
}
const knownState = peer.knownStates.get(id) ?? emptyKnownState(id);
const getIsCoValueFullyUploadedIntoPeer = simpleMemoize(() =>
// Build a lazy sync state object to process the isUploaded info
// only when requested
const syncState = {} as SyncStateGetter;
const getIsUploaded = simpleMemoize(() =>
this.getIsCoValueFullyUploadedIntoPeer(peerId, id),
);
Object.defineProperties(syncState, {
isUploaded: {
enumerable: true,
get: getIsUploaded,
},
});
for (const listener of this.listeners) {
listener(peerId, knownState, getIsCoValueFullyUploadedIntoPeer);
listener(peerId, knownState, syncState);
}
if (!peerListeners) return;
for (const listener of peerListeners) {
listener(knownState, getIsCoValueFullyUploadedIntoPeer);
listener(knownState, syncState);
}
}

View File

@@ -164,7 +164,7 @@ export class CoValueCore {
return {
id: this.id,
header: true,
sessions
sessions,
};
}

View File

@@ -107,6 +107,10 @@ export class RawCoMapView<
timeFilteredOps<K extends keyof Shape & string>(
key: K,
): MapOp<K, Shape[K]>[] | undefined {
if (key === "constructor") {
return undefined;
}
if (this.atTimeFilter) {
return this.ops[key]?.filter((op) => op.madeAt <= this.atTimeFilter!);
} else {

View File

@@ -718,8 +718,8 @@ export class SyncManager {
const unsubscribe =
this.syncStateSubscriptionManager.subscribeToPeerUpdates(
peerId,
(knownState, getIsUploadCompleted) => {
if (getIsUploadCompleted() && knownState.id === id) {
(knownState, syncState) => {
if (syncState.isUploaded && knownState.id === id) {
resolve(true);
unsubscribe?.();
}

View File

@@ -33,9 +33,7 @@ describe("SyncStateSubscriptionManager", () => {
const subscriptionManager = client.syncManager.syncStateSubscriptionManager;
const updateSpy: GlobalSyncStateListenerCallback = vi
.fn()
.mockImplementation((_, __, isUploaded) => isUploaded());
const updateSpy: GlobalSyncStateListenerCallback = vi.fn();
const unsubscribe = subscriptionManager.subscribeToUpdates(updateSpy);
await client.syncManager.actuallySyncCoValue(map.core);
@@ -43,9 +41,8 @@ describe("SyncStateSubscriptionManager", () => {
expect(updateSpy).toHaveBeenCalledWith(
"jazzCloudConnection",
emptyKnownState(map.core.id),
expect.any(Function),
{ isUploaded: false },
);
expect(updateSpy).toHaveLastReturnedWith(false);
await waitFor(() => {
return subscriptionManager.getIsCoValueFullyUploadedIntoPeer(
@@ -59,9 +56,8 @@ describe("SyncStateSubscriptionManager", () => {
client.syncManager.peers["jazzCloudConnection"]!.knownStates.get(
map.core.id,
)!,
expect.any(Function),
{ isUploaded: true },
);
expect(updateSpy).toHaveLastReturnedWith(true);
// Cleanup
unsubscribe();
@@ -98,12 +94,8 @@ describe("SyncStateSubscriptionManager", () => {
const subscriptionManager = client.syncManager.syncStateSubscriptionManager;
const updateToJazzCloudSpy: PeerSyncStateListenerCallback = vi
.fn()
.mockImplementation((_, isUploaded) => isUploaded());
const updateToStorageSpy: PeerSyncStateListenerCallback = vi
.fn()
.mockImplementation((_, isUploaded) => isUploaded());
const updateToJazzCloudSpy: PeerSyncStateListenerCallback = vi.fn();
const updateToStorageSpy: PeerSyncStateListenerCallback = vi.fn();
const unsubscribe1 = subscriptionManager.subscribeToPeerUpdates(
"jazzCloudConnection",
updateToJazzCloudSpy,
@@ -122,9 +114,8 @@ describe("SyncStateSubscriptionManager", () => {
expect(updateToJazzCloudSpy).toHaveBeenCalledWith(
emptyKnownState(map.core.id),
expect.any(Function),
{ isUploaded: false },
);
expect(updateToJazzCloudSpy).toHaveLastReturnedWith(false);
await waitFor(() => {
return subscriptionManager.getIsCoValueFullyUploadedIntoPeer(
@@ -137,15 +128,13 @@ describe("SyncStateSubscriptionManager", () => {
client.syncManager.peers["jazzCloudConnection"]!.knownStates.get(
map.core.id,
)!,
expect.any(Function),
{ isUploaded: true },
);
expect(updateToJazzCloudSpy).toHaveLastReturnedWith(true);
expect(updateToStorageSpy).toHaveBeenLastCalledWith(
emptyKnownState(map.core.id),
expect.any(Function),
{ isUploaded: false },
);
expect(updateToStorageSpy).toHaveLastReturnedWith(false);
});
test("getIsCoValueFullyUploadedIntoPeer returns correct status", async () => {

View File

@@ -1,5 +1,23 @@
# jazz-browser-media-images
## 0.8.33
### Patch Changes
- Updated dependencies [3cb27e1]
- jazz-browser@0.8.33
## 0.8.32
### Patch Changes
- 1a4bda0: Document usage in readme
- Updated dependencies [df42b2b]
- Updated dependencies [df42b2b]
- cojson@0.8.32
- jazz-tools@0.8.32
- jazz-browser@0.8.32
## 0.8.31
### Patch Changes

View File

@@ -2,40 +2,30 @@
This package provides a [Clerk-based](https://clerk.com/) authentication strategy for Jazz.
Looking for a React integration? Check out [`jazz-react-auth-clerk`](https://www.npmjs.com/package/jazz-react-auth-clerk).
## Usage
`useJazzClerkAuth` is a hook that returns a `JazzAuth` object and a `JazzAuthState` object. Provide a Clerk instance to `useJazzClerkAuth`, and it will return the appropriate `JazzAuth` object. Once authenticated, authentication will persist across page reloads, even if the device is offline.
`BrowserClerkAuth` is a class that provides a `JazzAuth` object. Provide a Clerk instance to `BrowserClerkAuth`, and it will return the appropriate `JazzAuth` object. Once authenticated, authentication will persist across page reloads, even if the device is offline.
From [the example chat app](https://github.com/gardencmp/jazz/tree/main/examples/chat-clerk):
```typescript
import { ClerkProvider, SignInButton, useClerk } from "@clerk/clerk-react";
import { useJazzClerkAuth } from "jazz-react-auth-clerk";
```ts
import { BrowserClerkAuth } from "jazz-browser-auth-clerk";
const Jazz = createJazzReactApp();
export const { useAccount, useCoState } = Jazz;
// ...
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk);
return (
<>
{state.errors.map((error) => (
<div key={error}>{error}</div>
))}
{auth ? (
<Jazz.Provider
auth={auth}
peer="wss://cloud.jazz.tools/?key=chat-example-jazz-clerk@gcmp.io"
>
{children}
</Jazz.Provider>
) : (
<SignInButton />
)}
</>
);
}
const auth = new BrowserClerkAuth(
{
onError: (error) => {
void clerk.signOut();
setState((state) => ({
...state,
errors: [...state.errors, error.toString()],
}));
},
},
clerk,
);
```

View File

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

View File

@@ -1,5 +1,20 @@
# jazz-browser-media-images
## 0.8.33
### Patch Changes
- Updated dependencies [3cb27e1]
- jazz-browser@0.8.33
## 0.8.32
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-browser@0.8.32
## 0.8.31
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-browser-media-images",
"version": "0.8.31",
"version": "0.8.33",
"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.8.31",
"jazz-tools": "workspace:0.8.31",
"jazz-browser": "workspace:0.8.33",
"jazz-tools": "workspace:0.8.32",
"pica": "^9.0.1",
"typescript": "^5.3.3"
},

View File

@@ -1,5 +1,22 @@
# jazz-browser
## 0.8.33
### Patch Changes
- 3cb27e1: Set created passkey credentials as discoverable
## 0.8.32
### Patch Changes
- Updated dependencies [df42b2b]
- Updated dependencies [df42b2b]
- cojson@0.8.32
- jazz-tools@0.8.32
- cojson-storage-indexeddb@0.8.32
- cojson-transport-ws@0.8.32
## 0.8.31
### Patch Changes

View File

@@ -1,16 +1,16 @@
{
"name": "jazz-browser",
"version": "0.8.31",
"version": "0.8.33",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",
"license": "MIT",
"dependencies": {
"@scure/bip39": "^1.3.0",
"cojson": "workspace:0.8.31",
"cojson-storage-indexeddb": "workspace:0.8.31",
"cojson-transport-ws": "workspace:0.8.31",
"jazz-tools": "workspace:0.8.31",
"cojson": "workspace:0.8.32",
"cojson-storage-indexeddb": "workspace:0.8.32",
"cojson-transport-ws": "workspace:0.8.32",
"jazz-tools": "workspace:0.8.32",
"typescript": "^5.3.3"
},
"scripts": {

View File

@@ -8,6 +8,19 @@ type StorageData = {
const localStorageKey = "demo-auth-logged-in-secret";
/**
* `BrowserDemoAuth` provides a `JazzAuth` object for demo authentication.
*
* Demo authentication is useful for quickly testing your app, as it allows you to create new accounts and log in as existing ones. The authentication persists across page reloads, with the credentials stored in `localStorage`.
*
* ```
* import { BrowserDemoAuth } from "jazz-browser";
*
* const auth = new BrowserDemoAuth(driver);
* ```
*
* @category Auth Providers
*/
export class BrowserDemoAuth implements AuthMethod {
constructor(
public driver: BrowserDemoAuth.Driver,
@@ -37,6 +50,9 @@ export class BrowserDemoAuth implements AuthMethod {
}
}
/**
* @returns A `JazzAuth` object
*/
async start() {
if (localStorage["demo-auth-logged-in-secret"]) {
const localStorageData = JSON.parse(
@@ -129,7 +145,7 @@ export class BrowserDemoAuth implements AuthMethod {
}
}
/** @category Auth Providers */
/** @internal */
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace BrowserDemoAuth {
export interface Driver {

View File

@@ -13,6 +13,17 @@ type LocalStorageData = {
const localStorageKey = "jazz-logged-in-secret";
/**
* `BrowserPasskeyAuth` provides a `JazzAuth` object for passkey authentication.
*
* ```ts
* import { BrowserPasskeyAuth } from "jazz-browser";
*
* const auth = new BrowserPasskeyAuth(driver, appName);
* ```
*
* @category Auth Providers
*/
export class BrowserPasskeyAuth implements AuthMethod {
constructor(
public driver: BrowserPasskeyAuth.Driver,
@@ -29,6 +40,9 @@ export class BrowserPasskeyAuth implements AuthMethod {
this.driver.onError(error);
}
/**
* @returns A `JazzAuth` object
*/
async start(crypto: CryptoProvider): Promise<AuthResult> {
if (localStorage[localStorageKey]) {
const localStorageData = JSON.parse(
@@ -90,6 +104,8 @@ export class BrowserPasskeyAuth implements AuthMethod {
pubKeyCredParams: [{ alg: -7, type: "public-key" }],
authenticatorSelection: {
authenticatorAttachment: "platform",
requireResidentKey: true,
residentKey: "required",
},
timeout: 60000,
attestation: "direct",
@@ -171,7 +187,7 @@ export class BrowserPasskeyAuth implements AuthMethod {
}
}
/** @category Auth Providers */
/** @internal */
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace BrowserPasskeyAuth {
export interface Driver {

View File

@@ -9,6 +9,17 @@ type LocalStorageData = {
const localStorageKey = "jazz-logged-in-secret";
/**
* `BrowserPassphraseAuth` provides a `JazzAuth` object for passphrase authentication.
*
* ```ts
* import { BrowserPassphraseAuth } from "jazz-browser";
*
* const auth = new BrowserPassphraseAuth(driver, wordlist, appName);
* ```
*
* @category Auth Providers
*/
export class BrowserPassphraseAuth implements AuthMethod {
constructor(
public driver: BrowserPassphraseAuth.Driver,
@@ -18,6 +29,9 @@ export class BrowserPassphraseAuth implements AuthMethod {
public appHostname: string = window.location.hostname,
) {}
/**
* @returns A `JazzAuth` object
*/
async start(crypto: CryptoProvider): Promise<AuthResult> {
if (localStorage[localStorageKey]) {
const localStorageData = JSON.parse(
@@ -121,8 +135,7 @@ export class BrowserPassphraseAuth implements AuthMethod {
}
}
/** @category Auth Providers */
// eslint-disable-next-line @typescript-eslint/no-namespace
/** @internal */
export namespace BrowserPassphraseAuth {
export interface Driver {
onReady: (next: {

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