Compare commits

...

108 Commits

Author SHA1 Message Date
Guido D'Orsi
55cb83e6e0 Merge pull request #2652 from garden-co/changeset-release/main
Version Packages
2025-07-17 15:26:20 +02:00
github-actions[bot]
6290088fec Version Packages 2025-07-17 13:06:49 +00:00
Guido D'Orsi
b9c17b37db Merge pull request #2651 from garden-co/fix/optional-load
fix: load failures when loading a missing ref declared with z.optional and Schema.optional
2025-07-17 15:04:36 +02:00
Guido D'Orsi
6c76ff8fbf fix: load of missing z.optional and Schema.optional doesn't fail 2025-07-17 14:54:33 +02:00
Guido D'Orsi
3c6a2a6092 Merge pull request #2649 from garden-co/changeset-release/main
Version Packages
2025-07-16 13:16:14 +02:00
github-actions[bot]
e8a950e61a Version Packages 2025-07-16 10:15:20 +00:00
Guido D'Orsi
e2cbf035de Merge pull request #2648 from garden-co/fix/onAnonymous-stuck
fix: fix stuck authentication when using onAnonymousAccountDiscarded with a storage
2025-07-16 12:13:11 +02:00
Matteo Manchi
47599b6307 chore(cojson): new removeStorage method exposed on LocalNode 2025-07-16 11:19:35 +02:00
Guido D'Orsi
901d0762ee Merge pull request #2647 from garden-co/fix/GCO-646-uncaught-from-load-promise
fix: catch errors from CoValue loading and treat it as "unavailable"
2025-07-16 09:18:43 +02:00
Guido D'Orsi
d1c1b0c5cc fix: fix stuck authentication when using onAnonymousAccountDiscarded with a storage 2025-07-15 22:17:51 +02:00
Matteo Manchi
cf4ad7285d fix(jazz-tools/tools): catch errors from CoValue loading and treat it as "unavailable" 2025-07-15 21:12:21 +02:00
Guido D'Orsi
2983c7bd58 fix: ignore builds for server-side-validation 2025-07-15 18:41:12 +02:00
Nico Rainhart
ab6328f767 Merge pull request #2645 from garden-co/changeset-release/main
Version Packages
2025-07-15 12:23:00 -03:00
github-actions[bot]
e0555debde Version Packages 2025-07-15 15:12:46 +00:00
Guido D'Orsi
247f4556e7 change the changeset to a patch 2025-07-15 17:10:44 +02:00
Nico Rainhart
7903c737f4 Merge pull request #2627 from garden-co/feat/co-optional-and-discriminatedUnion
feat: add `co.optional` and `co.discriminatedUnion`
2025-07-15 12:01:47 -03:00
NicoR
6145da5525 Update changeset 2025-07-15 11:50:55 -03:00
Nico Rainhart
fc0a2e77a3 Merge pull request #2629 from garden-co/feat/improve-zod-functions-type-safety
feat: prevent using Zod functions with CoValue schemas
2025-07-15 09:21:38 -03:00
NicoR
334fbbbb7f Comment back z.record and z.intersection until we support them 2025-07-15 09:12:18 -03:00
NicoR
eaac1e6580 Keep z.optional and z.discriminatedUnion compatible with covalues 2025-07-14 22:44:02 -03:00
Guido D'Orsi
114898d8a9 Merge pull request #2643 from garden-co/changeset-release/main
Version Packages
2025-07-14 21:25:21 +02:00
NicoR
cbc3f0cc65 Improve changeset message 2025-07-14 15:25:04 -03:00
NicoR
29c487e288 Remove new usages of zodSchemaToCoSchema 2025-07-14 15:13:51 -03:00
NicoR
0b0590a364 Merge remote-tracking branch 'origin/main' into feat/co-optional-and-discriminatedUnion 2025-07-14 15:11:31 -03:00
NicoR
1eb01997d8 Remove unused imports 2025-07-14 14:57:42 -03:00
Nico Rainhart
0dc8d511a1 Merge pull request #2636 from garden-co/feat/zod-jazz-schema-boundary
refactor: consolidate boundary between Zod schemas, CoValue schemas & CoValue classes
2025-07-14 14:43:36 -03:00
github-actions[bot]
962213c712 Version Packages 2025-07-14 15:04:25 +00:00
Guido D'Orsi
427df8fcbb Merge pull request #2644 from garden-co/chore/lefthook-autoinstall
chore: auto-install lefthook using `postinstall` script
2025-07-14 17:02:16 +02:00
Matteo Manchi
c40aad55dc chore: auto-install lefthook using postinstall script 2025-07-14 14:38:48 +02:00
Guido D'Orsi
dfca5926de Merge pull request #2640 from garden-co/GCO-621-Adds-documentation-for-descriminatedUnion-workaround
Closes GCO-621 - Add documentation for discriminated union workaround
2025-07-14 12:50:16 +02:00
Guido D'Orsi
9815ec61f0 feat: export the z.ZodDiscriminatedUnion type and improve the recursive types docs 2025-07-14 11:14:59 +02:00
Guido D'Orsi
fca60d213e Merge pull request #2641 from garden-co/GCO-655-user-id-on-unauthorized
Expose current Account id in unauthorized error message
2025-07-14 11:12:49 +02:00
Matteo Manchi
b4fdab475b chore: add changeset 2025-07-14 11:03:59 +02:00
Guido D'Orsi
2b043abffa Merge pull request #2637 from garden-co/feat/discriminated-union-load-subscribe
feat: add load & subscribe to Discriminated union schemas
2025-07-14 10:53:33 +02:00
Matteo Manchi
958c122c36 chore(jazz-tools/tools): expose current user id in unauthorized error message 2025-07-12 21:01:44 +02:00
Margaret Culotta
5842838371 Add examples but remove twoslash because of limitations in how Twoslash parses advanced TypeScript types 2025-07-11 14:36:07 -05:00
NicoR
e136e1b696 Remove unnecessary comment 2025-07-11 16:01:38 -03:00
NicoR
2475a46578 Remove resolve type for when loading/subscribing to discriminated unions 2025-07-11 15:45:23 -03:00
NicoR
44f653a64b Format and reorder imports 2025-07-11 14:00:55 -03:00
NicoR
f8437042a6 Add CoDiscriminatedUnionSchema.subscribe 2025-07-11 13:38:08 -03:00
Margaret Culotta
acd908fbc2 add docs for recursive connection 2025-07-11 10:41:50 -05:00
Margaret Culotta
4e61d1d191 add docs for recursive connections 2025-07-11 10:37:31 -05:00
NicoR
db23582b4c Fix "Expression produces a union type that is too complex to represent" error 2025-07-11 12:27:31 -03:00
NicoR
4b0b6d8a69 Use Add CoDiscriminatedUnionSchema.load in existing tests 2025-07-11 12:21:31 -03:00
NicoR
d450b394fa Tighten CoDiscriminatedUnionSchema type 2025-07-11 12:12:56 -03:00
NicoR
0abc96e400 Add CoDiscriminatedUnionSchema.load 2025-07-11 11:17:44 -03:00
NicoR
7562354b29 Fix e2e test error 2025-07-10 21:44:54 -03:00
NicoR
6c085a3919 Fix imports 2025-07-10 17:29:33 -03:00
NicoR
6afff848bc Clean up CoValue schema definitions 2025-07-10 16:49:19 -03:00
NicoR
47059845cc Make co.discriminatedUnion tests type-tests 2025-07-10 16:09:41 -03:00
NicoR
a1735a8232 Update tests that expected CoValue class instead of schema 2025-07-10 16:00:56 -03:00
NicoR
1f5750d8c4 Support nesting CoValue classes inside CoValue schemas 2025-07-10 15:24:57 -03:00
NicoR
f756ce26b5 Fix CoListSchema 2025-07-10 14:46:22 -03:00
NicoR
84f5bdda74 Rename AnyCoSchema.getCoSchema to getCoValueClass 2025-07-10 14:41:54 -03:00
NicoR
ee7aefa97c Tighten Account schema type when inferring from Zod schema 2025-07-10 14:32:27 -03:00
NicoR
b0895981ba Add CoDiscriminatedUnionSchema 2025-07-10 14:31:58 -03:00
NicoR
94f636b2ee Fix CoOptionalSchema 2025-07-10 14:05:30 -03:00
NicoR
331ab070f6 Fix CoMapSchema.catchall 2025-07-10 13:38:42 -03:00
NicoR
13e73adfb9 Refactor zodSchemaToCoSchema to return CoValue schema instead of class 2025-07-10 12:38:23 -03:00
Guido D'Orsi
9f6079b6c6 Merge pull request #2634 from garden-co/changeset-release/main
Version Packages
2025-07-10 16:14:58 +02:00
github-actions[bot]
4033d78fa6 Version Packages 2025-07-10 14:02:44 +00:00
Guido D'Orsi
83af94c850 Merge pull request #2575 from garden-co/feat/storage-api
feat: storage as load/store API
2025-07-10 16:00:33 +02:00
Guido D'Orsi
70fe856713 fix: don't wait for File streaming on SubscriptionScope 2025-07-10 14:54:00 +02:00
Guido D'Orsi
42e4afc42b test: add tests for markErrored 2025-07-10 14:35:51 +02:00
Guido D'Orsi
0e6797b222 chore: update lockfile 2025-07-10 14:28:10 +02:00
Guido D'Orsi
3634eaf8e9 chore: remove error logged on verify failures 2025-07-10 14:27:56 +02:00
Guido D'Orsi
58dfda3d0f Merge remote-tracking branch 'origin/main' into feat/storage-api 2025-07-10 14:16:16 +02:00
Guido D'Orsi
d304b0bcb5 Merge pull request #2622 from garden-co/feat/wait-for-streaming
feat: wait for the full streaming before return values in load and subscribe
2025-07-10 14:10:01 +02:00
Guido D'Orsi
44f5a3f5a2 test: add tests for loading/subscribing to large coValues 2025-07-10 14:06:20 +02:00
Sammii
ebb3ce1c25 Merge pull request #2623 from garden-co/feat/design-system-shadcn-integration
Feat/design system shadcn integration
2025-07-10 11:18:28 +01:00
Sammii
a67bba0dcf ensuring height consistency between buttons, inputs and dropdowns 2025-07-10 11:12:23 +01:00
Guido D'Orsi
4a72c26e42 chore: simplify toAddTransactions and tracking content from storage 2025-07-10 11:24:21 +02:00
NicoR
f1552b8262 [WIP] FieldSchema refactor 2025-07-09 17:20:51 -03:00
NicoR
6826ad8e45 Add CoOptionalSchema 2025-07-09 17:09:26 -03:00
NicoR
7c1b757b62 Reuse DefaultProfileShape wherever possible 2025-07-09 17:09:26 -03:00
NicoR
326e1734a4 Fix import order 2025-07-09 17:09:10 -03:00
NicoR
0cf027c91b Revert changes on z.object and z.strictObject 2025-07-09 17:09:10 -03:00
NicoR
e358881b76 Prevent using z.record with CoValue schemas 2025-07-09 17:09:10 -03:00
NicoR
cee8010918 Prevent using z.intersection with CoValue schemas 2025-07-09 17:09:10 -03:00
NicoR
cc877139ef Prevent using z.strictObject with CoValue schemas 2025-07-09 17:09:10 -03:00
NicoR
56a9b89538 Prevent using z.tuple with CoValue schemas 2025-07-09 17:09:10 -03:00
NicoR
199c463e28 Prevent using z.array with CoValue schemas 2025-07-09 17:09:10 -03:00
NicoR
50e523d19c Prevent using z.union with CoValue schemas 2025-07-09 17:09:10 -03:00
NicoR
796ea24288 Prevent using z.discriminatedUnion with CoValue schemas 2025-07-09 17:09:10 -03:00
NicoR
c8be86e823 Add tests 2025-07-09 17:09:10 -03:00
NicoR
41b7054aab Prevent using z.optional and z.object with CoValue schemas 2025-07-09 17:09:10 -03:00
NicoR
101adcd024 More updates to docs and examples 2025-07-09 17:08:59 -03:00
NicoR
a2854aeec9 Fix import order 2025-07-09 16:24:45 -03:00
NicoR
bdc9aee689 Add changeset 2025-07-09 16:11:55 -03:00
NicoR
2f53ae0ab8 Update docs 2025-07-09 16:09:03 -03:00
NicoR
f76c05448c Update examples 2025-07-09 16:08:54 -03:00
NicoR
585e7e8177 Add tests for co.optional and co.discriminatedUnion 2025-07-09 15:30:05 -03:00
NicoR
82d8d1d873 Add co.discriminatedUnion 2025-07-09 15:30:05 -03:00
NicoR
2c523c86ff Replace usages of z.optional with CoSchemas with a new co.optional 2025-07-09 15:30:05 -03:00
NicoR
6616668d4a Add pnpm check command to jazz-tools 2025-07-09 15:30:05 -03:00
Nico Rainhart
8a3be85e97 Merge pull request #2601 from garden-co/fix/chat-rn-example-not-running
Update pinned react version to 19.1.0
2025-07-09 09:44:49 -03:00
Brad Anderson
1a7f2b7379 fix: chat-rn build issues for android 2025-07-08 17:32:31 -04:00
Guido D'Orsi
caac82dffd chore: enable lazy load on ProjectScreen 2025-07-08 20:33:49 +02:00
Guido D'Orsi
27b48378e5 feat: wait for the full streaming before return values in load and subscribe 2025-07-08 20:19:24 +02:00
Sammii
bd717fc0d7 updating buttons for default default 2025-07-08 16:04:50 +01:00
Sammii
d49cab0afa improving design systems integration with shadcn vars 2025-07-08 13:56:49 +01:00
Brad Anderson
e2bb3b8015 fix: chat-rn-expo works, canary bump 2025-07-07 12:33:12 -04:00
Brad Anderson
0b09d23bd1 fix: chat-rn works w properly-hoisted RN dep 2025-07-07 12:09:16 -04:00
NicoR
8ff3e234c1 Upgrade examples' expo version to 54.0.0-canary 2025-07-07 12:44:21 -03:00
NicoR
14a5e036a4 Update homepage to react 19.1.0 2025-07-02 11:03:40 -03:00
NicoR
5b1c1ca522 Update all examples to react 19.1.0 2025-07-02 10:44:31 -03:00
NicoR
a9c8458c51 Update chat-rn's Podfile.lock 2025-07-02 09:38:56 -03:00
NicoR
5f31d6cbe1 Update pinned react version 2025-07-02 09:38:38 -03:00
128 changed files with 5550 additions and 3151 deletions

View File

@@ -1,8 +0,0 @@
---
"cojson": patch
---
- Refactored the Peer incoming/outgoing channels to be syncronous
- Changed the storage communication to work with an explicit API and removed the storage role on peers
- Added scheduling of the incoming messages using a round-robin over the peers and a timer to do collaborative scheduling with the event loop
- Added expectContentUntil on the content messages to optimize content syncing with servers during streaming

View File

@@ -13,13 +13,13 @@
"@bacons/text-decoder": "^0.0.0",
"@bam.tech/react-native-image-resizer": "^3.0.11",
"@react-native-community/netinfo": "11.4.1",
"expo": "~53.0.9",
"expo": "54.0.0-canary-20250701-6a945c5",
"expo-clipboard": "^7.1.4",
"expo-secure-store": "~14.2.3",
"expo-sqlite": "~15.2.10",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-native": "0.79.2",
"react": "19.1.0",
"react-native": "0.80.0",
"react-native-get-random-values": "^1.11.0",
"readable-stream": "^4.7.0"
},
@@ -29,4 +29,4 @@
"typescript": "~5.8.3"
},
"private": true
}
}

View File

@@ -11,11 +11,11 @@ react {
// The root of your project, i.e. where "package.json" lives. Default is '../..'
// root = file("../../")
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
// reactNativeDir = file("../../node_modules/react-native")
reactNativeDir = file("../../../../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
// codegenDir = file("../../node_modules/@react-native/codegen")
codegenDir = file("../../../../node_modules/@react-native/codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
// cliFile = file("../../node_modules/react-native/cli.js")
cliFile = file("../../../../node_modules/react-native/cli.js")
/* Variants */
// The list of variants to that are debuggable. For those we're going to

View File

@@ -1,6 +1,6 @@
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
pluginManagement { includeBuild("../../../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
rootProject.name = 'ChatRN'
include ':app'
includeBuild('../node_modules/@react-native/gradle-plugin')
includeBuild('../../../node_modules/@react-native/gradle-plugin')

View File

@@ -380,7 +380,7 @@
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
USE_HERMES = true;
@@ -452,7 +452,7 @@
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
VALIDATE_PRODUCT = YES;

View File

@@ -2370,87 +2370,87 @@ PODS:
- Yoga (0.0.0)
DEPENDENCIES:
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- fast_float (from `../node_modules/react-native/third-party-podspecs/fast_float.podspec`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
- boost (from `../../../node_modules/react-native/third-party-podspecs/boost.podspec`)
- DoubleConversion (from `../../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- fast_float (from `../../../node_modules/react-native/third-party-podspecs/fast_float.podspec`)
- FBLazyVector (from `../../../node_modules/react-native/Libraries/FBLazyVector`)
- fmt (from `../../../node_modules/react-native/third-party-podspecs/fmt.podspec`)
- glog (from `../../../node_modules/react-native/third-party-podspecs/glog.podspec`)
- hermes-engine (from `../../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
- "op-sqlite (from `../../../node_modules/@op-engineering/op-sqlite`)"
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`)
- RCTRequired (from `../node_modules/react-native/Libraries/Required`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`)
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- React-Core (from `../node_modules/react-native/`)
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
- React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
- React-debug (from `../node_modules/react-native/ReactCommon/react/debug`)
- React-defaultsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/defaults`)
- React-domnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/dom`)
- React-Fabric (from `../node_modules/react-native/ReactCommon`)
- React-FabricComponents (from `../node_modules/react-native/ReactCommon`)
- React-FabricImage (from `../node_modules/react-native/ReactCommon`)
- React-featureflags (from `../node_modules/react-native/ReactCommon/react/featureflags`)
- React-featureflagsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/featureflags`)
- React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`)
- React-hermes (from `../node_modules/react-native/ReactCommon/hermes`)
- React-idlecallbacksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks`)
- React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`)
- React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`)
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`)
- React-jsinspectorcdp (from `../node_modules/react-native/ReactCommon/jsinspector-modern/cdp`)
- React-jsinspectornetwork (from `../node_modules/react-native/ReactCommon/jsinspector-modern/network`)
- React-jsinspectortracing (from `../node_modules/react-native/ReactCommon/jsinspector-modern/tracing`)
- React-jsitooling (from `../node_modules/react-native/ReactCommon/jsitooling`)
- React-jsitracing (from `../node_modules/react-native/ReactCommon/hermes/executor/`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
- React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
- RCT-Folly (from `../../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTDeprecation (from `../../../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`)
- RCTRequired (from `../../../node_modules/react-native/Libraries/Required`)
- RCTTypeSafety (from `../../../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../../../node_modules/react-native/`)
- React-callinvoker (from `../../../node_modules/react-native/ReactCommon/callinvoker`)
- React-Core (from `../../../node_modules/react-native/`)
- React-Core/RCTWebSocket (from `../../../node_modules/react-native/`)
- React-CoreModules (from `../../../node_modules/react-native/React/CoreModules`)
- React-cxxreact (from `../../../node_modules/react-native/ReactCommon/cxxreact`)
- React-debug (from `../../../node_modules/react-native/ReactCommon/react/debug`)
- React-defaultsnativemodule (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/defaults`)
- React-domnativemodule (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/dom`)
- React-Fabric (from `../../../node_modules/react-native/ReactCommon`)
- React-FabricComponents (from `../../../node_modules/react-native/ReactCommon`)
- React-FabricImage (from `../../../node_modules/react-native/ReactCommon`)
- React-featureflags (from `../../../node_modules/react-native/ReactCommon/react/featureflags`)
- React-featureflagsnativemodule (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/featureflags`)
- React-graphics (from `../../../node_modules/react-native/ReactCommon/react/renderer/graphics`)
- React-hermes (from `../../../node_modules/react-native/ReactCommon/hermes`)
- React-idlecallbacksnativemodule (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks`)
- React-ImageManager (from `../../../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`)
- React-jserrorhandler (from `../../../node_modules/react-native/ReactCommon/jserrorhandler`)
- React-jsi (from `../../../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../../../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../../../node_modules/react-native/ReactCommon/jsinspector-modern`)
- React-jsinspectorcdp (from `../../../node_modules/react-native/ReactCommon/jsinspector-modern/cdp`)
- React-jsinspectornetwork (from `../../../node_modules/react-native/ReactCommon/jsinspector-modern/network`)
- React-jsinspectortracing (from `../../../node_modules/react-native/ReactCommon/jsinspector-modern/tracing`)
- React-jsitooling (from `../../../node_modules/react-native/ReactCommon/jsitooling`)
- React-jsitracing (from `../../../node_modules/react-native/ReactCommon/hermes/executor/`)
- React-logger (from `../../../node_modules/react-native/ReactCommon/logger`)
- React-Mapbuffer (from `../../../node_modules/react-native/ReactCommon`)
- React-microtasksnativemodule (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
- react-native-get-random-values (from `../../../node_modules/react-native-get-random-values`)
- react-native-mmkv (from `../../../node_modules/react-native-mmkv`)
- "react-native-netinfo (from `../../../node_modules/@react-native-community/netinfo`)"
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
- React-performancetimeline (from `../node_modules/react-native/ReactCommon/react/performance/timeline`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
- React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`)
- React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
- React-RCTFabric (from `../node_modules/react-native/React`)
- React-RCTFBReactNativeSpec (from `../node_modules/react-native/React`)
- React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
- React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
- React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
- React-RCTRuntime (from `../node_modules/react-native/React/Runtime`)
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- React-rendererconsistency (from `../node_modules/react-native/ReactCommon/react/renderer/consistency`)
- React-renderercss (from `../node_modules/react-native/ReactCommon/react/renderer/css`)
- React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`)
- React-rncore (from `../node_modules/react-native/ReactCommon`)
- React-RuntimeApple (from `../node_modules/react-native/ReactCommon/react/runtime/platform/ios`)
- React-RuntimeCore (from `../node_modules/react-native/ReactCommon/react/runtime`)
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
- React-RuntimeHermes (from `../node_modules/react-native/ReactCommon/react/runtime`)
- React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
- React-timing (from `../node_modules/react-native/ReactCommon/react/timing`)
- React-utils (from `../node_modules/react-native/ReactCommon/react/utils`)
- react-native-safe-area-context (from `../../../node_modules/react-native-safe-area-context`)
- React-NativeModulesApple (from `../../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-oscompat (from `../../../node_modules/react-native/ReactCommon/oscompat`)
- React-perflogger (from `../../../node_modules/react-native/ReactCommon/reactperflogger`)
- React-performancetimeline (from `../../../node_modules/react-native/ReactCommon/react/performance/timeline`)
- React-RCTActionSheet (from `../../../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../../../node_modules/react-native/Libraries/NativeAnimation`)
- React-RCTAppDelegate (from `../../../node_modules/react-native/Libraries/AppDelegate`)
- React-RCTBlob (from `../../../node_modules/react-native/Libraries/Blob`)
- React-RCTFabric (from `../../../node_modules/react-native/React`)
- React-RCTFBReactNativeSpec (from `../../../node_modules/react-native/React`)
- React-RCTImage (from `../../../node_modules/react-native/Libraries/Image`)
- React-RCTLinking (from `../../../node_modules/react-native/Libraries/LinkingIOS`)
- React-RCTNetwork (from `../../../node_modules/react-native/Libraries/Network`)
- React-RCTRuntime (from `../../../node_modules/react-native/React/Runtime`)
- React-RCTSettings (from `../../../node_modules/react-native/Libraries/Settings`)
- React-RCTText (from `../../../node_modules/react-native/Libraries/Text`)
- React-RCTVibration (from `../../../node_modules/react-native/Libraries/Vibration`)
- React-rendererconsistency (from `../../../node_modules/react-native/ReactCommon/react/renderer/consistency`)
- React-renderercss (from `../../../node_modules/react-native/ReactCommon/react/renderer/css`)
- React-rendererdebug (from `../../../node_modules/react-native/ReactCommon/react/renderer/debug`)
- React-rncore (from `../../../node_modules/react-native/ReactCommon`)
- React-RuntimeApple (from `../../../node_modules/react-native/ReactCommon/react/runtime/platform/ios`)
- React-RuntimeCore (from `../../../node_modules/react-native/ReactCommon/react/runtime`)
- React-runtimeexecutor (from `../../../node_modules/react-native/ReactCommon/runtimeexecutor`)
- React-RuntimeHermes (from `../../../node_modules/react-native/ReactCommon/react/runtime`)
- React-runtimescheduler (from `../../../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
- React-timing (from `../../../node_modules/react-native/ReactCommon/react/timing`)
- React-utils (from `../../../node_modules/react-native/ReactCommon/react/utils`)
- ReactAppDependencyProvider (from `build/generated/ios`)
- ReactCodegen (from `build/generated/ios`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- ReactCommon/turbomodule/core (from `../../../node_modules/react-native/ReactCommon`)
- "RNCClipboard (from `../../../node_modules/@react-native-clipboard/clipboard`)"
- RNScreens (from `../node_modules/react-native-screens`)
- RNScreens (from `../../../node_modules/react-native-screens`)
- SocketRocket (~> 0.7.1)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
- Yoga (from `../../../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
trunk:
@@ -2458,88 +2458,88 @@ SPEC REPOS:
EXTERNAL SOURCES:
boost:
:podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec"
:podspec: "../../../node_modules/react-native/third-party-podspecs/boost.podspec"
DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
:podspec: "../../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
fast_float:
:podspec: "../node_modules/react-native/third-party-podspecs/fast_float.podspec"
:podspec: "../../../node_modules/react-native/third-party-podspecs/fast_float.podspec"
FBLazyVector:
:path: "../node_modules/react-native/Libraries/FBLazyVector"
:path: "../../../node_modules/react-native/Libraries/FBLazyVector"
fmt:
:podspec: "../node_modules/react-native/third-party-podspecs/fmt.podspec"
:podspec: "../../../node_modules/react-native/third-party-podspecs/fmt.podspec"
glog:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
:podspec: "../../../node_modules/react-native/third-party-podspecs/glog.podspec"
hermes-engine:
:podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
:podspec: "../../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
:tag: hermes-2025-05-06-RNv0.80.0-4eb6132a5bf0450bf4c6c91987675381d7ac8bca
op-sqlite:
:path: "../../../node_modules/@op-engineering/op-sqlite"
RCT-Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
:podspec: "../../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
RCTDeprecation:
:path: "../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation"
:path: "../../../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation"
RCTRequired:
:path: "../node_modules/react-native/Libraries/Required"
:path: "../../../node_modules/react-native/Libraries/Required"
RCTTypeSafety:
:path: "../node_modules/react-native/Libraries/TypeSafety"
:path: "../../../node_modules/react-native/Libraries/TypeSafety"
React:
:path: "../node_modules/react-native/"
:path: "../../../node_modules/react-native/"
React-callinvoker:
:path: "../node_modules/react-native/ReactCommon/callinvoker"
:path: "../../../node_modules/react-native/ReactCommon/callinvoker"
React-Core:
:path: "../node_modules/react-native/"
:path: "../../../node_modules/react-native/"
React-CoreModules:
:path: "../node_modules/react-native/React/CoreModules"
:path: "../../../node_modules/react-native/React/CoreModules"
React-cxxreact:
:path: "../node_modules/react-native/ReactCommon/cxxreact"
:path: "../../../node_modules/react-native/ReactCommon/cxxreact"
React-debug:
:path: "../node_modules/react-native/ReactCommon/react/debug"
:path: "../../../node_modules/react-native/ReactCommon/react/debug"
React-defaultsnativemodule:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/defaults"
:path: "../../../node_modules/react-native/ReactCommon/react/nativemodule/defaults"
React-domnativemodule:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/dom"
:path: "../../../node_modules/react-native/ReactCommon/react/nativemodule/dom"
React-Fabric:
:path: "../node_modules/react-native/ReactCommon"
:path: "../../../node_modules/react-native/ReactCommon"
React-FabricComponents:
:path: "../node_modules/react-native/ReactCommon"
:path: "../../../node_modules/react-native/ReactCommon"
React-FabricImage:
:path: "../node_modules/react-native/ReactCommon"
:path: "../../../node_modules/react-native/ReactCommon"
React-featureflags:
:path: "../node_modules/react-native/ReactCommon/react/featureflags"
:path: "../../../node_modules/react-native/ReactCommon/react/featureflags"
React-featureflagsnativemodule:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/featureflags"
:path: "../../../node_modules/react-native/ReactCommon/react/nativemodule/featureflags"
React-graphics:
:path: "../node_modules/react-native/ReactCommon/react/renderer/graphics"
:path: "../../../node_modules/react-native/ReactCommon/react/renderer/graphics"
React-hermes:
:path: "../node_modules/react-native/ReactCommon/hermes"
:path: "../../../node_modules/react-native/ReactCommon/hermes"
React-idlecallbacksnativemodule:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks"
:path: "../../../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks"
React-ImageManager:
:path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios"
:path: "../../../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios"
React-jserrorhandler:
:path: "../node_modules/react-native/ReactCommon/jserrorhandler"
:path: "../../../node_modules/react-native/ReactCommon/jserrorhandler"
React-jsi:
:path: "../node_modules/react-native/ReactCommon/jsi"
:path: "../../../node_modules/react-native/ReactCommon/jsi"
React-jsiexecutor:
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
:path: "../../../node_modules/react-native/ReactCommon/jsiexecutor"
React-jsinspector:
:path: "../node_modules/react-native/ReactCommon/jsinspector-modern"
:path: "../../../node_modules/react-native/ReactCommon/jsinspector-modern"
React-jsinspectorcdp:
:path: "../node_modules/react-native/ReactCommon/jsinspector-modern/cdp"
:path: "../../../node_modules/react-native/ReactCommon/jsinspector-modern/cdp"
React-jsinspectornetwork:
:path: "../node_modules/react-native/ReactCommon/jsinspector-modern/network"
:path: "../../../node_modules/react-native/ReactCommon/jsinspector-modern/network"
React-jsinspectortracing:
:path: "../node_modules/react-native/ReactCommon/jsinspector-modern/tracing"
:path: "../../../node_modules/react-native/ReactCommon/jsinspector-modern/tracing"
React-jsitooling:
:path: "../node_modules/react-native/ReactCommon/jsitooling"
:path: "../../../node_modules/react-native/ReactCommon/jsitooling"
React-jsitracing:
:path: "../node_modules/react-native/ReactCommon/hermes/executor/"
:path: "../../../node_modules/react-native/ReactCommon/hermes/executor/"
React-logger:
:path: "../node_modules/react-native/ReactCommon/logger"
:path: "../../../node_modules/react-native/ReactCommon/logger"
React-Mapbuffer:
:path: "../node_modules/react-native/ReactCommon"
:path: "../../../node_modules/react-native/ReactCommon"
React-microtasksnativemodule:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks"
:path: "../../../node_modules/react-native/ReactCommon/react/nativemodule/microtasks"
react-native-get-random-values:
:path: "../../../node_modules/react-native-get-random-values"
react-native-mmkv:
@@ -2547,75 +2547,75 @@ EXTERNAL SOURCES:
react-native-netinfo:
:path: "../../../node_modules/@react-native-community/netinfo"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
:path: "../../../node_modules/react-native-safe-area-context"
React-NativeModulesApple:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios"
:path: "../../../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios"
React-oscompat:
:path: "../node_modules/react-native/ReactCommon/oscompat"
:path: "../../../node_modules/react-native/ReactCommon/oscompat"
React-perflogger:
:path: "../node_modules/react-native/ReactCommon/reactperflogger"
:path: "../../../node_modules/react-native/ReactCommon/reactperflogger"
React-performancetimeline:
:path: "../node_modules/react-native/ReactCommon/react/performance/timeline"
:path: "../../../node_modules/react-native/ReactCommon/react/performance/timeline"
React-RCTActionSheet:
:path: "../node_modules/react-native/Libraries/ActionSheetIOS"
:path: "../../../node_modules/react-native/Libraries/ActionSheetIOS"
React-RCTAnimation:
:path: "../node_modules/react-native/Libraries/NativeAnimation"
:path: "../../../node_modules/react-native/Libraries/NativeAnimation"
React-RCTAppDelegate:
:path: "../node_modules/react-native/Libraries/AppDelegate"
:path: "../../../node_modules/react-native/Libraries/AppDelegate"
React-RCTBlob:
:path: "../node_modules/react-native/Libraries/Blob"
:path: "../../../node_modules/react-native/Libraries/Blob"
React-RCTFabric:
:path: "../node_modules/react-native/React"
:path: "../../../node_modules/react-native/React"
React-RCTFBReactNativeSpec:
:path: "../node_modules/react-native/React"
:path: "../../../node_modules/react-native/React"
React-RCTImage:
:path: "../node_modules/react-native/Libraries/Image"
:path: "../../../node_modules/react-native/Libraries/Image"
React-RCTLinking:
:path: "../node_modules/react-native/Libraries/LinkingIOS"
:path: "../../../node_modules/react-native/Libraries/LinkingIOS"
React-RCTNetwork:
:path: "../node_modules/react-native/Libraries/Network"
:path: "../../../node_modules/react-native/Libraries/Network"
React-RCTRuntime:
:path: "../node_modules/react-native/React/Runtime"
:path: "../../../node_modules/react-native/React/Runtime"
React-RCTSettings:
:path: "../node_modules/react-native/Libraries/Settings"
:path: "../../../node_modules/react-native/Libraries/Settings"
React-RCTText:
:path: "../node_modules/react-native/Libraries/Text"
:path: "../../../node_modules/react-native/Libraries/Text"
React-RCTVibration:
:path: "../node_modules/react-native/Libraries/Vibration"
:path: "../../../node_modules/react-native/Libraries/Vibration"
React-rendererconsistency:
:path: "../node_modules/react-native/ReactCommon/react/renderer/consistency"
:path: "../../../node_modules/react-native/ReactCommon/react/renderer/consistency"
React-renderercss:
:path: "../node_modules/react-native/ReactCommon/react/renderer/css"
:path: "../../../node_modules/react-native/ReactCommon/react/renderer/css"
React-rendererdebug:
:path: "../node_modules/react-native/ReactCommon/react/renderer/debug"
:path: "../../../node_modules/react-native/ReactCommon/react/renderer/debug"
React-rncore:
:path: "../node_modules/react-native/ReactCommon"
:path: "../../../node_modules/react-native/ReactCommon"
React-RuntimeApple:
:path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios"
:path: "../../../node_modules/react-native/ReactCommon/react/runtime/platform/ios"
React-RuntimeCore:
:path: "../node_modules/react-native/ReactCommon/react/runtime"
:path: "../../../node_modules/react-native/ReactCommon/react/runtime"
React-runtimeexecutor:
:path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
:path: "../../../node_modules/react-native/ReactCommon/runtimeexecutor"
React-RuntimeHermes:
:path: "../node_modules/react-native/ReactCommon/react/runtime"
:path: "../../../node_modules/react-native/ReactCommon/react/runtime"
React-runtimescheduler:
:path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler"
:path: "../../../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler"
React-timing:
:path: "../node_modules/react-native/ReactCommon/react/timing"
:path: "../../../node_modules/react-native/ReactCommon/react/timing"
React-utils:
:path: "../node_modules/react-native/ReactCommon/react/utils"
:path: "../../../node_modules/react-native/ReactCommon/react/utils"
ReactAppDependencyProvider:
:path: build/generated/ios
ReactCodegen:
:path: build/generated/ios
ReactCommon:
:path: "../node_modules/react-native/ReactCommon"
:path: "../../../node_modules/react-native/ReactCommon"
RNCClipboard:
:path: "../../../node_modules/@react-native-clipboard/clipboard"
RNScreens:
:path: "../node_modules/react-native-screens"
:path: "../../../node_modules/react-native-screens"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
:path: "../../../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS:
boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90
@@ -2692,7 +2692,7 @@ SPEC CHECKSUMS:
React-timing: a275a1c2e6112dba17f8f7dd496d439213bbea0d
React-utils: 449a6e1fd53886510e284e80bdbb1b1c6db29452
ReactAppDependencyProvider: 3267432b637c9b38e86961b287f784ee1b08dde0
ReactCodegen: 5d41e1df061200130dd326e55cdfdf94b0289c6e
ReactCodegen: d82f538f70f00484d418803f74b5a0ea09cc8689
ReactCommon: b028d09a66e60ebd83ca59d8cc9a1216360db147
RNCClipboard: 54ff19965d7c816febbafe5f520c2c3e7b677a49
RNScreens: ee2abe7e0c548eed14e92742e81ed991165c56aa

View File

@@ -13,7 +13,7 @@
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bacons/text-decoder": "0.0.0",
"@op-engineering/op-sqlite": "14.1.0",
"@react-native-clipboard/clipboard": "1.16.2",
"@react-native-clipboard/clipboard": "1.16.3",
"@react-native-community/netinfo": "11.4.1",
"@react-navigation/native": "7.1.14",
"@react-navigation/native-stack": "7.3.19",
@@ -40,7 +40,7 @@
"@react-native/typescript-config": "0.80.0",
"@rnx-kit/metro-config": "^2.0.1",
"@rnx-kit/metro-resolver-symlinks": "^0.2.5",
"@types/react": "19.1.0",
"@types/react": "^19.1.0",
"eslint": "^8.19.0",
"pod-install": "^0.3.5",
"prettier": "2.8.8",

View File

@@ -1,5 +1,42 @@
# passkey-svelte
## 0.0.102
### Patch Changes
- Updated dependencies [6c76ff8]
- jazz-tools@0.15.13
## 0.0.101
### Patch Changes
- Updated dependencies [d1c1b0c]
- Updated dependencies [cf4ad72]
- jazz-tools@0.15.12
## 0.0.100
### Patch Changes
- Updated dependencies [bdc9aee]
- jazz-tools@0.15.11
## 0.0.99
### Patch Changes
- Updated dependencies [9815ec6]
- Updated dependencies [b4fdab4]
- jazz-tools@0.15.10
## 0.0.98
### Patch Changes
- Updated dependencies [27b4837]
- jazz-tools@0.15.9
## 0.0.97
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-svelte",
"version": "0.0.97",
"version": "0.0.102",
"type": "module",
"private": true,
"scripts": {

View File

@@ -16,15 +16,15 @@
"hash-slash": "workspace:*",
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"zod": "3.25.28"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react-swc": "^3.10.1",
"is-ci": "^3.0.1",
"postcss": "^8.4.40",
@@ -32,4 +32,4 @@
"typescript": "5.6.2",
"vite": "^6.3.5"
}
}
}

View File

@@ -1,8 +1,8 @@
import { co, z } from "jazz-tools";
import { co } from "jazz-tools";
export const Message = co.map({
text: co.plainText(),
image: z.optional(co.image()),
image: co.optional(co.image()),
});
export type Message = co.loaded<typeof Message>;

View File

@@ -14,15 +14,15 @@
"@bam.tech/react-native-image-resizer": "^3.0.11",
"@clerk/clerk-expo": "^2.13.1",
"@react-native-community/netinfo": "11.4.1",
"expo": "~53.0.9",
"expo": "54.0.0-canary-20250701-6a945c5",
"expo-crypto": "~14.1.5",
"expo-linking": "~7.1.5",
"expo-secure-store": "~14.2.3",
"expo-sqlite": "~15.2.10",
"expo-web-browser": "~14.2.0",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-native": "0.79.2",
"react": "19.1.0",
"react-native": "0.80.0",
"react-native-get-random-values": "^1.11.0",
"readable-stream": "^4.7.0"
},
@@ -32,4 +32,4 @@
"typescript": "~5.8.3"
},
"private": true
}
}

View File

@@ -14,17 +14,17 @@
"dependencies": {
"@clerk/clerk-react": "^5.4.1",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0"
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",
"vite": "^6.3.5"
}
}
}

View File

@@ -11,14 +11,14 @@
},
"dependencies": {
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0"
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"is-ci": "^3.0.1",

View File

@@ -1,7 +1,7 @@
import { co, z } from "jazz-tools";
import { co } from "jazz-tools";
export const JazzProfile = co.profile({
file: z.optional(co.fileStream()),
file: co.optional(co.fileStream()),
});
export const JazzAccount = co.account({

View File

@@ -12,16 +12,16 @@
"dependencies": {
"hash-slash": "workspace:*",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0"
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@playwright/test": "^1.50.1",
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"is-ci": "^3.0.1",

View File

@@ -28,16 +28,16 @@ export const BubbleTeaOrder = co.map({
addOns: ListOfBubbleTeaAddOns,
deliveryDate: z.date(),
withMilk: z.boolean(),
instructions: z.optional(co.plainText()),
instructions: co.optional(co.plainText()),
});
export const DraftBubbleTeaOrder = co
.map({
baseTea: z.optional(z.literal([...BubbleTeaBaseTeaTypes])),
addOns: z.optional(ListOfBubbleTeaAddOns),
addOns: co.optional(ListOfBubbleTeaAddOns),
deliveryDate: z.optional(z.date()),
withMilk: z.optional(z.boolean()),
instructions: z.optional(co.plainText()),
instructions: co.optional(co.plainText()),
})
.withHelpers((Self) => ({
hasChanges(order: Loaded<typeof Self> | undefined) {

View File

@@ -11,14 +11,14 @@
},
"dependencies": {
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0"
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",

View File

@@ -1,7 +1,7 @@
import { co, z } from "jazz-tools";
import { co } from "jazz-tools";
export const JazzProfile = co.profile({
image: z.optional(co.image()),
image: co.optional(co.image()),
});
export const JazzAccount = co.account({

View File

@@ -17,15 +17,15 @@
"cojson-transport-ws": "workspace:*",
"hash-slash": "workspace:*",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-use": "^17.4.0"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react-swc": "^3.10.1",
"postcss": "^8.4.40",
"tailwindcss": "^4.1.10",

View File

@@ -10,8 +10,8 @@
"dependencies": {
"jazz-tools": "workspace:*",
"next": "15.3.2",
"react": "^19.0.0",
"react-dom": "^19.0.0"
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.10",
@@ -21,4 +21,4 @@
"tailwindcss": "^4.1.10",
"typescript": "^5"
}
}
}

View File

@@ -24,15 +24,15 @@
"clsx": "^2.1.1",
"jazz-tools": "workspace:*",
"lucide-react": "^0.485.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.17",
"tw-animate-css": "^1.2.5"
},
"devDependencies": {
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.3.4",
"jazz-run": "workspace:*",
"npm-run-all": "^4.1.5",

View File

@@ -8,7 +8,7 @@ export type Player = co.loaded<typeof Player>;
export const Game = co.map({
player1: Player,
player2: z.optional(Player),
player2: co.optional(Player),
outcome: z.optional(z.literal(["player1", "player2", "draw"])),
player1Score: z.number(),
player2Score: z.number(),
@@ -17,8 +17,8 @@ export type Game = co.loaded<typeof Game>;
export const WaitingRoom = co.map({
account1: co.account(),
account2: z.optional(co.account()),
game: z.optional(Game),
account2: co.optional(co.account()),
game: co.optional(Game),
});
export type WaitingRoom = co.loaded<typeof WaitingRoom>;
@@ -47,7 +47,7 @@ export const JoinGameRequest = co.map({
});
export type JoinGameRequest = co.loaded<typeof JoinGameRequest>;
export const InboxMessage = z.discriminatedUnion("type", [
export const InboxMessage = co.discriminatedUnion("type", [
PlayIntent,
NewGameIntent,
CreateGameRequest,

View File

@@ -13,14 +13,14 @@
"dependencies": {
"@react-spring/web": "^9.7.5",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"zod": "3.25.28"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"is-ci": "^3.0.1",

View File

@@ -12,14 +12,14 @@
"dependencies": {
"@clerk/clerk-react": "^5.4.1",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"tailwindcss": "^4.1.10"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",

View File

@@ -23,8 +23,8 @@
"clsx": "^2.1.1",
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-router": "^6.16.0",
"react-router-dom": "^6.16.0",
"tailwind-merge": "^1.14.0"
@@ -32,8 +32,8 @@
"devDependencies": {
"@playwright/test": "^1.50.1",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react-swc": "^3.10.1",
"postcss": "^8.4.27",
"tailwindcss": "^4.1.10",

View File

@@ -66,7 +66,7 @@ export const MusicaAccountRoot = co.map({
// track and playlist
// You can also add the position in time if you want make it possible
// to resume the song
activeTrack: z.optional(MusicTrack),
activeTrack: co.optional(MusicTrack),
activePlaylist: Playlist,
exampleDataLoaded: z.optional(z.boolean()),

View File

@@ -14,8 +14,8 @@
"dependencies": {
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-router": "^6.16.0",
"react-router-dom": "^6.16.0"
},
@@ -24,8 +24,8 @@
"@playwright/test": "^1.50.1",
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"postcss": "^8.4.40",

View File

@@ -11,14 +11,14 @@
},
"dependencies": {
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"tailwindcss": "^4.1.10"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",

View File

@@ -12,14 +12,14 @@
"dependencies": {
"hash-slash": "workspace:*",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"tailwindcss": "^4.1.10"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"typescript": "5.6.2",

View File

@@ -19,15 +19,15 @@
"prosemirror-schema-list": "^1.5.1",
"prosemirror-state": "^1.4.3",
"prosemirror-view": "^1.39.1",
"react": "19.0.0",
"react-dom": "19.0.0"
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@playwright/test": "^1.50.1",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"is-ci": "^3.0.1",

View File

@@ -22,15 +22,15 @@
"clsx": "^2.1.1",
"jazz-tools": "workspace:*",
"lucide-react": "^0.509.0",
"react": "19.0.0",
"react-dom": "19.0.0"
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@playwright/test": "^1.50.1",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"is-ci": "^3.0.1",

View File

@@ -0,0 +1,3 @@
{
"ignoreCommand": "echo true"
}

View File

@@ -18,8 +18,8 @@
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-router": "^6.16.0",
"react-router-dom": "^6.16.0",
"tailwind-merge": "^1.14.0",
@@ -29,8 +29,8 @@
"devDependencies": {
"@tailwindcss/postcss": "^4.1.10",
"@types/qrcode": "^1.5.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react-swc": "^3.10.1",
"postcss": "^8.4.27",
"tailwindcss": "^4.1.10",

View File

@@ -12,14 +12,14 @@
"dependencies": {
"@tailwindcss/forms": "^0.5.9",
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0"
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@tailwindcss/postcss": "^4.1.10",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitejs/plugin-react": "^4.5.1",
"globals": "^15.11.0",
"tailwindcss": "^4.1.10",

View File

@@ -27,28 +27,26 @@ export default function ButtonsPage() {
return (
<>
<h3 className="text-lg mt-5 mb-2 font-bold">Variants</h3>
<p className="mb-3">
For compatibility the shadcn/ui variants are mapped to the design
system.
</p>
<p className="my-3">Buttons are styled with the variant prop.</p>
<div className="grid grid-cols-2 gap-2">
<Button variant="default">default</Button>
<Button variant="link">link</Button>
<Button variant="ghost">ghost</Button>
<Button variant="outline">outline</Button>
<Button variant="secondary">secondary</Button>
<Button variant="destructive">destructive</Button>
</div>
<h3 className="text-lg mt-5 mb-2 font-bold">Intents</h3>
<p>
We have extended the shadcn/ui variants to include more styles via the
intent prop.
<h3 className="text-lg mt-5 font-bold">Intents</h3>
<p className="my-3">
We have extended the variants to include more styles via the intent
prop.
</p>
<div className="grid grid-cols-2 gap-2">
{/* <Button intent="default">default</Button> */}
<Button intent="default">default</Button>
<Button intent="muted">muted</Button>
<Button intent="strong">strong</Button>
<Button intent="primary">primary</Button>
<Button intent="tip">tip</Button>
<Button intent="info">info</Button>
@@ -56,8 +54,6 @@ export default function ButtonsPage() {
<Button intent="warning">warning</Button>
<Button intent="alert">alert</Button>
<Button intent="danger">danger</Button>
<Button intent="muted">muted</Button>
<Button intent="strong">strong</Button>
</div>
<div className="flex justify-between items-center w-48 mt-10">
@@ -89,7 +85,7 @@ export default function ButtonsPage() {
<p className="text-sm mt-2 mb-5">
<strong>NB:</strong> Variants and styles are interchangeable. See the
intent on each variant with the dropdown
intent on each variant with the dropdown.
</p>
<div className="grid grid-cols-2 gap-2">
@@ -107,9 +103,19 @@ export default function ButtonsPage() {
</Button>
</div>
<p className="my-3">
For compatibility the shadcn/ui variants are mapped to the design
system.
</p>
<div className="grid grid-cols-2 gap-2">
<Button variant="secondary">secondary</Button>
<Button variant="destructive">destructive</Button>
</div>
<h3 className="text-lg font-bold mt-5">Icons</h3>
<p>Buttons can also contain an icon and text.</p>
<p className="my-3">Buttons can also contain an icon and text.</p>
<div className="grid grid-cols-2 gap-2">
<Button
@@ -130,7 +136,7 @@ export default function ButtonsPage() {
>
outline info with icon
</Button>
<p className="col-span-2">
<p className="col-span-2 my-2">
Or just use the icon prop with any of the button variants, style
variants and colors.
</p>
@@ -151,6 +157,7 @@ const buttonPropsTableData = {
{
prop: "intent?",
types: [
"default",
"primary",
"tip",
"info",
@@ -174,7 +181,7 @@ const buttonPropsTableData = {
"secondary",
"destructive",
],
default: "undefined",
default: "default",
},
{
prop: "icon?",

View File

@@ -159,8 +159,8 @@ const styleClasses = (intent: Style, variant: Variant | undefined) => {
inverted: `${styleToTextMap[intent]} ${colorToBgHoverMap30[styleToColorMap[intent] as VariantColor]} ${colorToBgMap[styleToColorMap[intent] as VariantColor]} ${colorToBgActiveMap50[styleToColorMap[intent] as VariantColor]} ${shadowClassesBase}`,
ghost: `bg-transparent ${styleToTextMap[intent]} ${colorToBgHoverMap10[styleToColorMap[intent] as VariantColor]} ${colorToBgActiveMap25[styleToColorMap[intent] as VariantColor]}`,
link: `bg-transparent ${styleToTextMap[intent]} underline underline-offset-2 p-0 hover:bg-transparent ${styleToTextHoverMap[intent]} ${styleToTextActiveMap[intent]} active:underline-stone-500`,
secondary: `bg-stone-300 ${styleToTextMap[intent]} hover:bg-stone-400/80 active:bg-stone-500/80`,
destructive: `bg-danger text-white hover:bg-red/80 active:bg-red/70`,
secondary: variantClass("muted"),
destructive: variantClass("danger"),
default: `${styleToBgGradientColorMap["default"]} ${styleToBgGradientHoverMap["default"]} ${textColorVariant("default")} ${styleToButtonStateMap["default"]} ${shadowClassesBase} shadow-stone-400/20`,
};
};

View File

@@ -44,7 +44,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
: icon && iconPosition === "right";
const inputClassName = clsx(
"w-full rounded-md border px-3.5 py-2 shadow-sm",
"w-full rounded-md border px-2.5 py-1 shadow-sm h-[36px]",
"font-medium text-stone-900",
"dark:text-white dark:bg-stone-925",
);

View File

@@ -21,7 +21,7 @@ export type Style =
export const sizeClasses = {
sm: "text-sm py-1 px-2",
md: "py-1.5 px-3",
md: "py-1.5 px-3 h-[36px]",
lg: "py-2 px-5 md:px-6 md:py-2.5",
};

View File

@@ -202,7 +202,7 @@ See the corresponding sections for [creating](/docs/using-covalues/filestreams#c
### Unions of CoMaps (declaration)
You can declare unions of CoMaps that have discriminating fields, using `z.discriminatedUnion()`.
You can declare unions of CoMaps that have discriminating fields, using `co.discriminatedUnion()`.
<CodeGroup>
```ts twoslash
@@ -220,7 +220,7 @@ const SliderWidget = co.map({
max: z.number(),
});
const WidgetUnion = z.discriminatedUnion("type", [ButtonWidget, SliderWidget]);
const WidgetUnion = co.discriminatedUnion("type", [ButtonWidget, SliderWidget]);
```
</CodeGroup>
@@ -321,7 +321,7 @@ const Company = co.map({
#### Optional References
You can make references optional with `z.optional()`:
You can make references optional with `co.optional()`:
<CodeGroup>
```ts twoslash
@@ -331,7 +331,7 @@ const Pet = co.map({
});
// ---cut---
const Person = co.map({
pet: z.optional(Pet),
pet: co.optional(Pet),
});
```
</CodeGroup>
@@ -372,7 +372,7 @@ const ListOfPeople = co.list(Person);
</CodeGroup>
Note: similarly, if you use modifiers like `z.optional()` you'll need to help TypeScript along:
Note: similarly, if you use modifiers like `co.optional()` you'll need to help TypeScript along:
<CodeGroup>
```ts twoslash
@@ -381,7 +381,7 @@ import { co, z } from "jazz-tools";
const Person = co.map({
name: z.string(),
get bestFriend(): z.ZodOptional<typeof Person> {
return z.optional(Person);
return co.optional(Person);
}
});
```

View File

@@ -24,7 +24,7 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
});
export type Project = co.loaded<typeof Project>;
```
@@ -54,7 +54,7 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
});
const Inventory = co.record(z.string(), z.number());
// ---cut---
@@ -90,7 +90,7 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
});
// ---cut---
@@ -134,7 +134,7 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
});
const project = Project.create(
{
@@ -165,7 +165,7 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
});
const project = Project.create(
{
@@ -197,7 +197,7 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
get subProject() {
return Project.optional();
}
@@ -219,9 +219,9 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
get subProjects(): z.ZodOptional<CoListSchema<typeof Project>> {
return z.optional(co.list(Project));
return co.optional(co.list(Project));
}
});
export type Project = co.loaded<typeof Project>;
@@ -265,7 +265,7 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
});
const Inventory = co.record(z.string(), z.number());
const project = Project.create(
@@ -297,7 +297,7 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
});
const Inventory = co.record(z.string(), z.number());
const project = Project.create(
@@ -347,7 +347,7 @@ const Project = co.map({
name: z.string(),
startDate: z.date(),
status: z.literal(["planning", "active", "completed"]),
coordinator: z.optional(Member),
coordinator: co.optional(Member),
});
const Inventory = co.record(z.string(), z.number());
const project = Project.create(
@@ -445,7 +445,7 @@ const TaskV2 = co.map({
// Export the discriminated union; because some users might
// not be able to run the migration
export const Task = z.discriminatedUnion("version", [
export const Task = co.discriminatedUnion("version", [
TaskV1,
TaskV2,
]);

View File

@@ -6,7 +6,7 @@ export const metadata = {
# Connecting CoValues with direct linking
CoValues can form relationships with each other by **linking directly to other CoValues**. This creates a powerful connection where one CoValue can point to the unique identity of another.
Instead of embedding all of the details of one coValue directly within another, you use its Jazz-Tools schema as the field type. This allows multiple CoValues to point to the same piece of data effortlessly.
Instead of embedding all the details of one CoValue directly within another, you use its Jazz-Tools schema as the field type. This allows multiple CoValues to point to the same piece of data effortlessly.
<CodeGroup>
```ts twoslash
@@ -50,3 +50,51 @@ export type User = co.loaded<typeof User>;
This direct linking approach offers a single source of truth. When you update a referenced CoValue, all other CoValues that point to it are automatically updated, ensuring data consistency across your application.
By connecting CoValues through these direct references, you can build robust and collaborative applications where data is consistent, efficient to manage, and relationships are clearly defined. The ability to link different CoValue types to the same underlying data is fundamental to building complex applications with Jazz.
## Recursive references with DiscriminatedUnion
In advanced schemas, you may want a CoValue that recursively references itself. For example, a `ReferenceItem` that contains a list of other items like `NoteItem` or `AttachmentItem`. This is common in tree-like structures such as threaded comments or nested project outlines.
You can model this with a Zod `z.discriminatedUnion`, but TypeScripts type inference doesn't handle recursive unions well without a workaround.
Heres how to structure your schema to avoid circular reference errors.
### Use this pattern for recursive discriminated unions
<CodeGroup>
```ts twoslash
import { CoListSchema, co, z } from "jazz-tools";
// Recursive item modeling pattern using discriminated unions
// First, define the non-recursive types
export const NoteItem = co.map({
type: z.literal("note"),
internal: z.boolean(),
content: co.plainText(),
});
export const AttachmentItem = co.map({
type: z.literal("attachment"),
internal: z.boolean(),
content: co.fileStream(),
});
export const ReferenceItem = co.map({
type: z.literal("reference"),
internal: z.boolean(),
content: z.string(),
// Workaround: declare the field type using CoListSchema and ZodDiscriminatedUnion so TS can safely recurse
get children(): CoListSchema<z.ZodDiscriminatedUnion<[typeof NoteItem, typeof AttachmentItem, typeof ReferenceItem]>> {
return ProjectContextItemList;
},
});
// Create the recursive union
export const ProjectContextItem = z.discriminatedUnion("type", [NoteItem, AttachmentItem, ReferenceItem]);
// Final list of recursive types
export const ProjectContextItemList = co.list(ProjectContextItem);
```
</CodeGroup>
Even though this seems like a shortcut, TypeScript and Zod can't resolve the circular reference this way. Always define the discriminated union before introducing recursive links.

1543
homepage/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ packages:
- "gcmp"
catalog:
"react": "19.0.0"
"react-dom": "19.0.0"
"@types/react": "19.0.0"
"@types/react-dom": "19.0.0"
"react": "19.1.0"
"react-dom": "19.1.0"
"@types/react": "19.1.0"
"@types/react-dom": "19.1.0"

View File

@@ -39,6 +39,7 @@
"changeset-version": "changeset version && pnpm i --no-frozen-lockfile",
"release": "turbo run build --filter='./packages/*' && pnpm changeset publish && git push --follow-tags",
"clean": "rm -rf ./packages/*/dist && rm -rf ./packages/*/node_modules && rm -rf ./examples/*/node_modules && rm -rf ./examples/*/dist",
"postinstall": "lefthook install",
"check-catalog-deps": "node scripts/check-catalog-deps.js"
},
"version": "0.0.0",
@@ -50,10 +51,10 @@
"ignoreMissing": ["@babel/*", "expo-modules-*", "typescript"]
},
"overrides": {
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"vite": "6.3.5",
"esbuild": "0.24.0"
}

View File

@@ -1,5 +1,37 @@
# cojson-storage-indexeddb
## 0.15.13
### Patch Changes
- cojson@0.15.13
## 0.15.12
### Patch Changes
- cojson@0.15.12
## 0.15.11
### Patch Changes
- cojson@0.15.11
## 0.15.10
### Patch Changes
- cojson@0.15.10
## 0.15.9
### Patch Changes
- Updated dependencies [27b4837]
- Updated dependencies [2776263]
- cojson@0.15.9
## 0.15.8
### Patch Changes

View File

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

View File

@@ -1,5 +1,37 @@
# cojson-storage-sqlite
## 0.15.13
### Patch Changes
- cojson@0.15.13
## 0.15.12
### Patch Changes
- cojson@0.15.12
## 0.15.11
### Patch Changes
- cojson@0.15.11
## 0.15.10
### Patch Changes
- cojson@0.15.10
## 0.15.9
### Patch Changes
- Updated dependencies [27b4837]
- Updated dependencies [2776263]
- cojson@0.15.9
## 0.15.8
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "cojson-storage-sqlite",
"type": "module",
"version": "0.15.8",
"version": "0.15.13",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",

View File

@@ -1,5 +1,37 @@
# cojson-transport-nodejs-ws
## 0.15.13
### Patch Changes
- cojson@0.15.13
## 0.15.12
### Patch Changes
- cojson@0.15.12
## 0.15.11
### Patch Changes
- cojson@0.15.11
## 0.15.10
### Patch Changes
- cojson@0.15.10
## 0.15.9
### Patch Changes
- Updated dependencies [27b4837]
- Updated dependencies [2776263]
- cojson@0.15.9
## 0.15.8
### Patch Changes

View File

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

View File

@@ -1,5 +1,23 @@
# cojson
## 0.15.13
## 0.15.12
## 0.15.11
## 0.15.10
## 0.15.9
### Patch Changes
- 27b4837: Wait for the full streaming before return values in load and subscribe
- 2776263: - Refactored the Peer incoming/outgoing channels to be syncronous
- Changed the storage communication to work with an explicit API and removed the storage role on peers
- Added scheduling of the incoming messages using a round-robin over the peers and a timer to do collaborative scheduling with the event loop
- Added expectContentUntil on the content messages to optimize content syncing with servers during streaming
## 0.15.8
## 0.15.7

View File

@@ -25,7 +25,7 @@
},
"type": "module",
"license": "MIT",
"version": "0.15.8",
"version": "0.15.13",
"devDependencies": {
"@opentelemetry/sdk-metrics": "^2.0.0",
"libsql": "^0.5.13",

View File

@@ -1039,7 +1039,7 @@ export class CoValueCore {
node.storage.load(
this.id,
(data) => {
node.syncManager.handleNewContent(data);
node.syncManager.handleNewContent(data, "storage");
},
(found) => {
if (!found) {

View File

@@ -47,8 +47,7 @@ export type Transaction = PrivateTransaction | TrustingTransaction;
type SessionLog = {
readonly transactions: Transaction[];
lastHash?: Hash;
streamingHash: StreamingHash;
streamingHash?: StreamingHash;
readonly signatureAfter: { [txIdx: number]: Signature | undefined };
lastSignature: Signature;
};
@@ -86,8 +85,7 @@ export class VerifiedState {
for (let [sessionID, sessionLog] of this.sessions) {
clonedSessions.set(sessionID, {
lastSignature: sessionLog.lastSignature,
lastHash: sessionLog.lastHash,
streamingHash: sessionLog.streamingHash.clone(),
streamingHash: sessionLog.streamingHash?.clone(),
signatureAfter: { ...sessionLog.signatureAfter },
transactions: sessionLog.transactions.slice(),
} satisfies SessionLog);
@@ -110,12 +108,11 @@ export class VerifiedState {
skipVerify: boolean = false,
givenNewStreamingHash?: StreamingHash,
): Result<true, TryAddTransactionsError> {
if (skipVerify === true && givenNewStreamingHash && givenExpectedNewHash) {
if (skipVerify === true) {
this.doAddTransactions(
sessionID,
newTransactions,
newSignature,
givenExpectedNewHash,
givenNewStreamingHash,
);
} else {
@@ -147,7 +144,6 @@ export class VerifiedState {
sessionID,
newTransactions,
newSignature,
expectedNewHash,
newStreamingHash,
);
}
@@ -159,16 +155,16 @@ export class VerifiedState {
sessionID: SessionID,
newTransactions: Transaction[],
newSignature: Signature,
expectedNewHash: Hash,
newStreamingHash: StreamingHash,
newStreamingHash?: StreamingHash,
) {
const transactions = this.sessions.get(sessionID)?.transactions ?? [];
const sessionLog = this.sessions.get(sessionID);
const transactions = sessionLog?.transactions ?? [];
for (const tx of newTransactions) {
transactions.push(tx);
}
const signatureAfter = this.sessions.get(sessionID)?.signatureAfter ?? {};
const signatureAfter = sessionLog?.signatureAfter ?? {};
const lastInbetweenSignatureIdx = Object.keys(signatureAfter).reduce(
(max, idx) => (parseInt(idx) > max ? parseInt(idx) : max),
@@ -192,7 +188,6 @@ export class VerifiedState {
this.sessions.set(sessionID, {
transactions,
lastHash: expectedNewHash,
streamingHash: newStreamingHash,
lastSignature: newSignature,
signatureAfter: signatureAfter,
@@ -206,9 +201,27 @@ export class VerifiedState {
sessionID: SessionID,
newTransactions: Transaction[],
): { expectedNewHash: Hash; newStreamingHash: StreamingHash } {
const streamingHash =
this.sessions.get(sessionID)?.streamingHash.clone() ??
new StreamingHash(this.crypto);
const sessionLog = this.sessions.get(sessionID);
if (!sessionLog?.streamingHash) {
const streamingHash = new StreamingHash(this.crypto);
const oldTransactions = sessionLog?.transactions ?? [];
for (const transaction of oldTransactions) {
streamingHash.update(transaction);
}
for (const transaction of newTransactions) {
streamingHash.update(transaction);
}
return {
expectedNewHash: streamingHash.digest(),
newStreamingHash: streamingHash,
};
}
const streamingHash = sessionLog.streamingHash.clone();
for (const transaction of newTransactions) {
streamingHash.update(transaction);
@@ -386,6 +399,13 @@ export class VerifiedState {
return knownState;
}
isStreaming(): boolean {
// Call knownStateWithStreaming to delete the streamingKnownState when it matches the current knownState
this.knownStateWithStreaming();
return this.streamingKnownState !== undefined;
}
knownState(): CoValueKnownState {
if (this._cachedKnownState) {
return this._cachedKnownState;

View File

@@ -114,14 +114,6 @@ export class WasmCrypto extends CryptoProvider<Blake3State> {
textEncoder.encode(id),
);
if (!result) {
logger.error("Failed to verify signature", {
signature,
message,
id,
});
}
return result;
}

View File

@@ -82,6 +82,11 @@ export class LocalNode {
this.storage = storage;
}
removeStorage() {
this.storage?.close();
this.storage = undefined;
}
getCoValue(id: RawCoID) {
let entry = this.coValues.get(id);
@@ -348,12 +353,10 @@ export class LocalNode {
skipLoadingFromPeer?: PeerID,
skipRetry?: boolean,
): Promise<CoValueCore> {
if (!id) {
throw new Error("Trying to load CoValue with undefined id");
}
if (!id.startsWith("co_z")) {
throw new Error(`Trying to load CoValue with invalid id ${id}`);
if (typeof id !== "string" || !id.startsWith("co_z")) {
throw new TypeError(
`Trying to load CoValue with invalid id ${Array.isArray(id) ? JSON.stringify(id) : id}`,
);
}
if (this.crashed) {

View File

@@ -443,8 +443,9 @@ export class SyncManager {
}
}
handleNewContent(msg: NewContentMessage, peer?: PeerState) {
handleNewContent(msg: NewContentMessage, from: PeerState | "storage") {
const coValue = this.local.getCoValue(msg.id);
const peer = from === "storage" ? undefined : from;
if (!coValue.hasVerifiedContent()) {
if (!msg.header) {
@@ -586,7 +587,7 @@ export class SyncManager {
},
priority: msg.priority,
},
peer,
from,
);
});
continue;
@@ -598,7 +599,7 @@ export class SyncManager {
newTransactions,
undefined,
newContentForSession.lastSignature,
"immediate", // TODO: can we change this to deferred?
"immediate",
);
if (result.isErr()) {
@@ -660,11 +661,9 @@ export class SyncManager {
peer.trackToldKnownState(msg.id);
}
const sourcePeer = peer;
const isContentFromStorage = !sourcePeer;
const syncedPeers = [];
if (!isContentFromStorage) {
if (from !== "storage") {
this.storeCoValue(coValue, [msg]);
}

View File

@@ -1,5 +1,13 @@
import { encrypt } from "jazz-crypto-rs";
import { assert, afterEach, beforeEach, expect, test, vi } from "vitest";
import {
assert,
afterEach,
beforeEach,
describe,
expect,
test,
vi,
} from "vitest";
import { bytesToBase64url } from "../base64url.js";
import { CoValueCore } from "../coValueCore/coValueCore.js";
import { Transaction } from "../coValueCore/verifiedState.js";
@@ -512,3 +520,264 @@ test("getValidTransactions should skip private transactions with invalid JSON",
expect(validTransactions.length).toBe(1);
expect(validTransactions[0]?.changes).toEqual([{ hello: "world" }]);
});
describe("markErrored and isErroredInPeer", () => {
test("markErrored should mark a peer as errored with the provided error", () => {
const [agent, sessionID] = randomAgentAndSessionID();
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
const coValue = node.createCoValue({
type: "costream",
ruleset: { type: "unsafeAllowAll" },
meta: null,
...Crypto.createdNowUnique(),
});
const peerId = "test-peer-1";
const testError = {
type: "InvalidSignature" as const,
id: coValue.id,
newSignature: "invalid-signature" as any,
sessionID: sessionID,
signerID: "test-signer" as any,
};
// Initially, the peer should not be errored
expect(coValue.isErroredInPeer(peerId)).toBe(false);
// Mark the peer as errored
coValue.markErrored(peerId, testError);
// Verify the peer is now marked as errored
expect(coValue.isErroredInPeer(peerId)).toBe(true);
// Verify the peer state contains the error
const peerState = coValue.getStateForPeer(peerId);
expect(peerState).toBeDefined();
expect(peerState?.type).toBe("errored");
});
test("markErrored should update loading state and notify listeners", () => {
const [agent, sessionID] = randomAgentAndSessionID();
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
const coValue = node.createCoValue({
type: "costream",
ruleset: { type: "unsafeAllowAll" },
meta: null,
...Crypto.createdNowUnique(),
});
const peerId = "test-peer-2";
const testError = {
type: "InvalidHash" as const,
id: coValue.id,
expectedNewHash: "expected-hash" as any,
givenExpectedNewHash: "given-hash" as any,
};
const listener = vi.fn();
coValue.subscribe(listener);
// Mark the peer as errored
coValue.markErrored(peerId, testError);
// Verify the listener was called
expect(listener).toHaveBeenCalled();
});
test("isErroredInPeer should return false for non-existent peers", () => {
const [agent, sessionID] = randomAgentAndSessionID();
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
const coValue = node.createCoValue({
type: "costream",
ruleset: { type: "unsafeAllowAll" },
meta: null,
...Crypto.createdNowUnique(),
});
const nonExistentPeerId = "non-existent-peer";
// Verify non-existent peer is not errored
expect(coValue.isErroredInPeer(nonExistentPeerId)).toBe(false);
});
test("isErroredInPeer should return false for peers with other states", () => {
const [agent, sessionID] = randomAgentAndSessionID();
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
const coValue = node.createCoValue({
type: "costream",
ruleset: { type: "unsafeAllowAll" },
meta: null,
...Crypto.createdNowUnique(),
});
const peerId = "test-peer-3";
// Mark peer as pending
coValue.markPending(peerId);
expect(coValue.isErroredInPeer(peerId)).toBe(false);
// Mark peer as unavailable
coValue.markNotFoundInPeer(peerId);
expect(coValue.isErroredInPeer(peerId)).toBe(false);
// Mark peer as available
coValue.provideHeader({} as any, peerId);
expect(coValue.isErroredInPeer(peerId)).toBe(false);
});
test("markErrored should work with multiple peers", () => {
const [agent, sessionID] = randomAgentAndSessionID();
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
const coValue = node.createCoValue({
type: "costream",
ruleset: { type: "unsafeAllowAll" },
meta: null,
...Crypto.createdNowUnique(),
});
const peer1Id = "peer-1";
const peer2Id = "peer-2";
const peer3Id = "peer-3";
const error1 = {
type: "InvalidSignature" as const,
id: coValue.id,
newSignature: "invalid-signature-1" as any,
sessionID: sessionID,
signerID: "test-signer-1" as any,
};
const error2 = {
type: "InvalidHash" as const,
id: coValue.id,
expectedNewHash: "expected-hash-2" as any,
givenExpectedNewHash: "given-hash-2" as any,
};
// Mark different peers as errored
coValue.markErrored(peer1Id, error1);
coValue.markErrored(peer2Id, error2);
// Verify each peer is correctly marked as errored
expect(coValue.isErroredInPeer(peer1Id)).toBe(true);
expect(coValue.isErroredInPeer(peer2Id)).toBe(true);
expect(coValue.isErroredInPeer(peer3Id)).toBe(false);
});
test("markErrored should override previous peer states", () => {
const [agent, sessionID] = randomAgentAndSessionID();
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
const coValue = node.createCoValue({
type: "costream",
ruleset: { type: "unsafeAllowAll" },
meta: null,
...Crypto.createdNowUnique(),
});
const peerId = "test-peer-4";
// Initially mark as pending
coValue.markPending(peerId);
expect(coValue.isErroredInPeer(peerId)).toBe(false);
// Then mark as errored
const testError = {
type: "TriedToAddTransactionsWithoutVerifiedState" as const,
id: coValue.id,
};
coValue.markErrored(peerId, testError);
// Verify the peer is now errored
expect(coValue.isErroredInPeer(peerId)).toBe(true);
const peerState = coValue.getStateForPeer(peerId);
expect(peerState?.type).toBe("errored");
});
test("markErrored should work with different error types", () => {
const [agent, sessionID] = randomAgentAndSessionID();
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
const coValue = node.createCoValue({
type: "costream",
ruleset: { type: "unsafeAllowAll" },
meta: null,
...Crypto.createdNowUnique(),
});
const peerId = "test-peer-5";
// Test with InvalidSignature error
const invalidSignatureError = {
type: "InvalidSignature" as const,
id: coValue.id,
newSignature: "invalid-sig" as any,
sessionID: sessionID,
signerID: "test-signer" as any,
};
coValue.markErrored(peerId, invalidSignatureError);
expect(coValue.isErroredInPeer(peerId)).toBe(true);
// Test with InvalidHash error
const invalidHashError = {
type: "InvalidHash" as const,
id: coValue.id,
expectedNewHash: "expected" as any,
givenExpectedNewHash: "given" as any,
};
coValue.markErrored(peerId, invalidHashError);
expect(coValue.isErroredInPeer(peerId)).toBe(true);
// Test with TriedToAddTransactionsWithoutVerifiedState error
const noVerifiedStateError = {
type: "TriedToAddTransactionsWithoutVerifiedState" as const,
id: coValue.id,
};
coValue.markErrored(peerId, noVerifiedStateError);
expect(coValue.isErroredInPeer(peerId)).toBe(true);
});
test("markErrored should trigger immediate notification", () => {
const [agent, sessionID] = randomAgentAndSessionID();
const node = new LocalNode(agent.agentSecret, sessionID, Crypto);
const coValue = node.createCoValue({
type: "costream",
ruleset: { type: "unsafeAllowAll" },
meta: null,
...Crypto.createdNowUnique(),
});
const peerId = "test-peer-6";
const testError = {
type: "InvalidSignature" as const,
id: coValue.id,
newSignature: "test-sig" as any,
sessionID: sessionID,
signerID: "test-signer" as any,
};
let notificationCount = 0;
const listener = () => {
notificationCount++;
};
coValue.subscribe(listener);
// Mark as errored
coValue.markErrored(peerId, testError);
// Verify immediate notification
expect(notificationCount).toBeGreaterThan(0);
});
});

View File

@@ -54,6 +54,38 @@ describe("loading coValues from server", () => {
`);
});
test("coValue load throws on invalid id", async () => {
const { node } = setupTestNode({
connected: true,
});
expect(async () => await node.load("test" as any)).rejects.toThrow(
"Trying to load CoValue with invalid id test",
);
expect(async () => await node.load(null as any)).rejects.toThrow(
"Trying to load CoValue with invalid id null",
);
expect(async () => await node.load(undefined as any)).rejects.toThrow(
"Trying to load CoValue with invalid id undefined",
);
expect(async () => await node.load(1 as any)).rejects.toThrow(
"Trying to load CoValue with invalid id 1",
);
expect(async () => await node.load({} as any)).rejects.toThrow(
"Trying to load CoValue with invalid id [object Object]",
);
expect(async () => await node.load([] as any)).rejects.toThrow(
"Trying to load CoValue with invalid id []",
);
expect(async () => await node.load(["test"] as any)).rejects.toThrow(
'Trying to load CoValue with invalid id ["test"]',
);
expect(async () => await node.load((() => {}) as any)).rejects.toThrow(
"Trying to load CoValue with invalid id () => {\n }",
);
expect(async () => await node.load(new Date() as any)).rejects.toThrow();
});
test("unavailable coValue retry with skipRetry set to true", async () => {
const client = setupTestNode();
const client2 = setupTestNode();

View File

@@ -991,7 +991,7 @@ describe("LocalNode.load", () => {
// @ts-expect-error Testing with undefined ID
await expect(client.node.load(undefined)).rejects.toThrow(
"Trying to load CoValue with undefined id",
"Trying to load CoValue with invalid id undefined",
);
});

View File

@@ -2136,7 +2136,7 @@ See the corresponding sections for [creating](/docs/using-covalues/filestreams#c
### Unions of CoMaps (declaration)
You can declare unions of CoMaps that have discriminating fields, using `z.discriminatedUnion()`.
You can declare unions of CoMaps that have discriminating fields, using `co.discriminatedUnion()`.
<CodeGroup>
```ts twoslash
@@ -2153,7 +2153,7 @@ const SliderWidget = co.map({
max: z.number(),
});
const WidgetUnion = z.discriminatedUnion([ButtonWidget, SliderWidget]);
const WidgetUnion = co.discriminatedUnion([ButtonWidget, SliderWidget]);
```
</CodeGroup>
@@ -11911,4 +11911,4 @@ export function cn(...inputs: ClassValue[]) {
```ts
/// <reference types="vite/client" />
```
```

View File

@@ -1,5 +1,53 @@
# jazz-auth-betterauth
## 0.15.13
### Patch Changes
- Updated dependencies [6c76ff8]
- jazz-tools@0.15.13
- jazz-betterauth-client-plugin@0.15.13
- cojson@0.15.13
## 0.15.12
### Patch Changes
- Updated dependencies [d1c1b0c]
- Updated dependencies [cf4ad72]
- jazz-tools@0.15.12
- jazz-betterauth-client-plugin@0.15.12
- cojson@0.15.12
## 0.15.11
### Patch Changes
- Updated dependencies [bdc9aee]
- jazz-tools@0.15.11
- jazz-betterauth-client-plugin@0.15.11
- cojson@0.15.11
## 0.15.10
### Patch Changes
- Updated dependencies [9815ec6]
- Updated dependencies [b4fdab4]
- jazz-tools@0.15.10
- jazz-betterauth-client-plugin@0.15.10
- cojson@0.15.10
## 0.15.9
### Patch Changes
- Updated dependencies [27b4837]
- Updated dependencies [2776263]
- jazz-tools@0.15.9
- cojson@0.15.9
- jazz-betterauth-client-plugin@0.15.9
## 0.15.8
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-auth-betterauth",
"version": "0.15.8",
"version": "0.15.13",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,35 @@
# jazz-betterauth-client-plugin
## 0.15.13
### Patch Changes
- jazz-betterauth-server-plugin@0.15.13
## 0.15.12
### Patch Changes
- jazz-betterauth-server-plugin@0.15.12
## 0.15.11
### Patch Changes
- jazz-betterauth-server-plugin@0.15.11
## 0.15.10
### Patch Changes
- jazz-betterauth-server-plugin@0.15.10
## 0.15.9
### Patch Changes
- jazz-betterauth-server-plugin@0.15.9
## 0.15.8
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-betterauth-client-plugin",
"version": "0.15.8",
"version": "0.15.13",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,48 @@
# jazz-betterauth-server-plugin
## 0.15.13
### Patch Changes
- Updated dependencies [6c76ff8]
- jazz-tools@0.15.13
- cojson@0.15.13
## 0.15.12
### Patch Changes
- Updated dependencies [d1c1b0c]
- Updated dependencies [cf4ad72]
- jazz-tools@0.15.12
- cojson@0.15.12
## 0.15.11
### Patch Changes
- Updated dependencies [bdc9aee]
- jazz-tools@0.15.11
- cojson@0.15.11
## 0.15.10
### Patch Changes
- Updated dependencies [9815ec6]
- Updated dependencies [b4fdab4]
- jazz-tools@0.15.10
- cojson@0.15.10
## 0.15.9
### Patch Changes
- Updated dependencies [27b4837]
- Updated dependencies [2776263]
- jazz-tools@0.15.9
- cojson@0.15.9
## 0.15.8
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-betterauth-server-plugin",
"version": "0.15.8",
"version": "0.15.13",
"type": "module",
"main": "dist/index.js",
"types": "src/index.ts",

View File

@@ -1,5 +1,58 @@
# jazz-react-auth-betterauth
## 0.15.13
### Patch Changes
- Updated dependencies [6c76ff8]
- jazz-tools@0.15.13
- jazz-auth-betterauth@0.15.13
- jazz-betterauth-client-plugin@0.15.13
- cojson@0.15.13
## 0.15.12
### Patch Changes
- Updated dependencies [d1c1b0c]
- Updated dependencies [cf4ad72]
- jazz-tools@0.15.12
- jazz-auth-betterauth@0.15.12
- jazz-betterauth-client-plugin@0.15.12
- cojson@0.15.12
## 0.15.11
### Patch Changes
- Updated dependencies [bdc9aee]
- jazz-tools@0.15.11
- jazz-auth-betterauth@0.15.11
- jazz-betterauth-client-plugin@0.15.11
- cojson@0.15.11
## 0.15.10
### Patch Changes
- Updated dependencies [9815ec6]
- Updated dependencies [b4fdab4]
- jazz-tools@0.15.10
- jazz-auth-betterauth@0.15.10
- jazz-betterauth-client-plugin@0.15.10
- cojson@0.15.10
## 0.15.9
### Patch Changes
- Updated dependencies [27b4837]
- Updated dependencies [2776263]
- jazz-tools@0.15.9
- cojson@0.15.9
- jazz-auth-betterauth@0.15.9
- jazz-betterauth-client-plugin@0.15.9
## 0.15.8
### Patch Changes

View File

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

View File

@@ -1,5 +1,58 @@
# jazz-run
## 0.15.13
### Patch Changes
- Updated dependencies [6c76ff8]
- jazz-tools@0.15.13
- cojson@0.15.13
- cojson-storage-sqlite@0.15.13
- cojson-transport-ws@0.15.13
## 0.15.12
### Patch Changes
- Updated dependencies [d1c1b0c]
- Updated dependencies [cf4ad72]
- jazz-tools@0.15.12
- cojson@0.15.12
- cojson-storage-sqlite@0.15.12
- cojson-transport-ws@0.15.12
## 0.15.11
### Patch Changes
- Updated dependencies [bdc9aee]
- jazz-tools@0.15.11
- cojson@0.15.11
- cojson-storage-sqlite@0.15.11
- cojson-transport-ws@0.15.11
## 0.15.10
### Patch Changes
- Updated dependencies [9815ec6]
- Updated dependencies [b4fdab4]
- jazz-tools@0.15.10
- cojson@0.15.10
- cojson-storage-sqlite@0.15.10
- cojson-transport-ws@0.15.10
## 0.15.9
### Patch Changes
- Updated dependencies [27b4837]
- Updated dependencies [2776263]
- jazz-tools@0.15.9
- cojson@0.15.9
- cojson-storage-sqlite@0.15.9
- cojson-transport-ws@0.15.9
## 0.15.8
### Patch Changes

View File

@@ -3,7 +3,7 @@
"bin": "./dist/index.js",
"type": "module",
"license": "MIT",
"version": "0.15.8",
"version": "0.15.13",
"exports": {
"./startSyncServer": {
"import": "./dist/startSyncServer.js",
@@ -28,11 +28,11 @@
"@effect/printer-ansi": "^0.34.5",
"@effect/schema": "^0.71.1",
"@effect/typeclass": "^0.25.5",
"cojson": "workspace:0.15.8",
"cojson-storage-sqlite": "workspace:0.15.8",
"cojson-transport-ws": "workspace:0.15.8",
"cojson": "workspace:0.15.13",
"cojson-storage-sqlite": "workspace:0.15.13",
"cojson-transport-ws": "workspace:0.15.13",
"effect": "^3.6.5",
"jazz-tools": "workspace:0.15.8",
"jazz-tools": "workspace:0.15.13",
"ws": "^8.14.2"
},
"devDependencies": {

View File

@@ -1,5 +1,55 @@
# jazz-tools
## 0.15.13
### Patch Changes
- 6c76ff8: Fix load failures when loading a missing ref declared with z.optional and Schema.optional
- cojson@0.15.13
- cojson-storage-indexeddb@0.15.13
- cojson-transport-ws@0.15.13
## 0.15.12
### Patch Changes
- d1c1b0c: Fix stuck authentication when using onAnonymousAccountDiscarded with a storage
- cf4ad72: fix unhandled rejection on CoValue.load
- cojson@0.15.12
- cojson-storage-indexeddb@0.15.12
- cojson-transport-ws@0.15.12
## 0.15.11
### Patch Changes
- bdc9aee: - Add `co.optional` and `co.discriminatedUnion`. You can now `load` and `subcribe` to schemas created with `co.discriminatedUnion`.
- Improved type-checking around `z.` schemas to prevent invalid combinations with `co.` schemas.
- cojson@0.15.11
- cojson-storage-indexeddb@0.15.11
- cojson-transport-ws@0.15.11
## 0.15.10
### Patch Changes
- 9815ec6: Export the z.ZodDiscriminatedUnion type
- b4fdab4: Exposed the current Account's ID in unauthorized error message
- cojson@0.15.10
- cojson-storage-indexeddb@0.15.10
- cojson-transport-ws@0.15.10
## 0.15.9
### Patch Changes
- 27b4837: Wait for the full streaming before return values in load and subscribe
- Updated dependencies [27b4837]
- Updated dependencies [2776263]
- cojson@0.15.9
- cojson-storage-indexeddb@0.15.9
- cojson-transport-ws@0.15.9
## 0.15.8
### Patch Changes

View File

@@ -139,7 +139,7 @@
},
"type": "module",
"license": "MIT",
"version": "0.15.8",
"version": "0.15.13",
"dependencies": {
"@manuscripts/prosemirror-recreate-steps": "^0.1.4",
"@scure/base": "1.2.1",
@@ -163,6 +163,7 @@
"zod": "3.25.28"
},
"scripts": {
"check": "tsc --noEmit",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"dev": "tsup --watch --dts",
@@ -178,8 +179,8 @@
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "16.2.0",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.0",
"@vitest/browser": "^3.2.4",
"queueueue": "^4.1.2",
"playwright": "^1.50.1",

View File

@@ -1,16 +1,6 @@
// @vitest-environment happy-dom
import {
Account,
CoMap,
Loaded,
RefsToResolve,
Resolved,
co,
coField,
z,
zodSchemaToCoSchema,
} from "jazz-tools";
import { RefsToResolve, co, z, zodSchemaToCoSchema } from "jazz-tools";
import { beforeEach, describe, expect, it } from "vitest";
import { useAccount, useJazzContextManager } from "../hooks.js";
import { useIsAuthenticated } from "../index.js";

View File

@@ -47,6 +47,26 @@ describe("useCoState", () => {
expect(result.current?.value).toBe("123");
});
it("should return null on invalid id", async () => {
const TestMap = co.map({
value: z.string(),
});
const account = await createJazzTestAccount({
isCurrentActiveAccount: true,
});
const { result } = renderHook(() => useCoState(TestMap, "test", {}), {
account,
});
expect(result.current).toBeUndefined();
await waitFor(() => {
expect(result.current).toBeNull();
});
});
it("should update the value when the coValue changes", async () => {
const TestMap = co.map({
value: z.string(),

View File

@@ -11,10 +11,10 @@ import {
anySchemaToCoSchema,
coValuesCache,
inspect,
isCoValueSchema,
} from "../internal.js";
import type {
Account,
CoValueClassFromZodSchema,
Group,
InstanceOfSchemaCoValuesNullable,
} from "../internal.js";
@@ -101,7 +101,7 @@ export class CoValueBase implements CoValue {
: S extends z.core.$ZodType
? NonNullable<InstanceOfSchemaCoValuesNullable<S>>
: never {
const cl = "getCoSchema" in schema ? (schema as any).getCoSchema() : schema;
const cl = isCoValueSchema(schema) ? schema.getCoValueClass() : schema;
if (this.constructor === cl) {
return this as any;

View File

@@ -3,14 +3,12 @@ import { CoStreamItem, RawCoStream } from "cojson";
import {
type Account,
CoValue,
CoValueClass,
CoValueOrZodSchema,
ID,
InstanceOfSchema,
activeAccountContext,
anySchemaToCoSchema,
loadCoValue,
zodSchemaToCoSchema,
} from "../internal.js";
export type InboxInvite = `${CoID<MessagesStream>}/${InviteSecret}`;

View File

@@ -1,8 +1,19 @@
import {
Account,
AnonymousJazzAgent,
CoValue,
CoValueBase,
CoValueClass,
CoValueFromRaw,
ID,
RefsToResolve,
RefsToResolveStrict,
Resolved,
SubscribeListenerOptions,
SubscribeRestArgs,
loadCoValueWithoutMe,
parseSubscribeRestArgs,
subscribeToCoValueWithoutMe,
} from "../internal.js";
/**
@@ -99,4 +110,55 @@ export abstract class SchemaUnion extends CoValueBase implements CoValue {
static fromRaw<V extends CoValue>(this: CoValueClass<V>, raw: V["_raw"]): V {
throw new Error("Not implemented");
}
/**
* Load a `SchemaUnion` with a given ID, as a given account.
*
* Note: The `resolve` option is not supported for `SchemaUnion`s due to https://github.com/garden-co/jazz/issues/2639
*
* @category Subscription & Loading
*/
static load<M extends SchemaUnion>(
this: CoValueClass<M>,
id: ID<M>,
options?: {
loadAs?: Account | AnonymousJazzAgent;
skipRetry?: boolean;
},
): Promise<Resolved<M, true> | null> {
return loadCoValueWithoutMe(this, id, options);
}
/**
* Load and subscribe to a `CoMap` with a given ID, as a given account.
*
* Automatically also subscribes to updates to all referenced/nested CoValues as soon as they are accessed in the listener.
*
* Returns an unsubscribe function that you should call when you no longer need updates.
*
* Also see the `useCoState` hook to reactively subscribe to a CoValue in a React component.
*
* Note: The `resolve` option is not supported for `SchemaUnion`s due to https://github.com/garden-co/jazz/issues/2639
*
* @category Subscription & Loading
*/
static subscribe<M extends SchemaUnion>(
this: CoValueClass<M>,
id: ID<M>,
listener: (value: Resolved<M, true>, unsubscribe: () => void) => void,
): () => void;
static subscribe<M extends SchemaUnion>(
this: CoValueClass<M>,
id: ID<M>,
options: SubscribeListenerOptions<M, true>,
listener: (value: Resolved<M, true>, unsubscribe: () => void) => void,
): () => void;
static subscribe<M extends SchemaUnion>(
this: CoValueClass<M>,
id: ID<M>,
...args: SubscribeRestArgs<M, true>
): () => void {
const { options, listener } = parseSubscribeRestArgs(args);
return subscribeToCoValueWithoutMe<M, true>(this, id, options, listener);
}
}

View File

@@ -279,8 +279,12 @@ export class JazzContextManager<
},
);
prevContext.node.syncManager.addPeer(currentAccountAsPeer);
// Closing storage on the prevContext to avoid conflicting transactions and getting stuck on waitForAllCoValuesSync
// The storage is reachable through currentContext using the connectedPeers
prevContext.node.removeStorage();
currentContext.node.syncManager.addPeer(prevAccountAsPeer);
prevContext.node.syncManager.addPeer(currentAccountAsPeer);
try {
await this.props.onAnonymousAccountDiscarded?.(prevContext.me);

View File

@@ -10,4 +10,6 @@ export {
coImageDefiner as image,
coAccountDefiner as account,
coProfileDefiner as profile,
coOptionalDefiner as optional,
coDiscriminatedUnionDefiner as discriminatedUnion,
} from "./zodCo.js";

View File

@@ -1,5 +1,6 @@
import { CoMap, CoValueClass, isCoValueClass } from "../../../internal.js";
import { coField } from "../../schema.js";
import { isAnyCoOptionalSchema } from "../schemaTypes/CoOptionalSchema.js";
import {
isUnionOfCoMapsDeeply,
isUnionOfPrimitivesDeeply,
@@ -12,10 +13,19 @@ import {
ZodReadonly,
z,
} from "../zodReExport.js";
import { ZodPrimitiveSchema } from "../zodSchema.js";
import { zodSchemaToCoSchemaOrKeepPrimitive } from "./zodSchemaToCoSchema.js";
import { AnyCoSchema, ZodPrimitiveSchema } from "../zodSchema.js";
import {
isCoValueSchema,
zodSchemaToCoSchemaOrKeepPrimitive,
} from "./zodSchemaToCoSchema.js";
type FieldSchema =
/**
* Types of objects that can be nested inside CoValue schema containers
*/
type SchemaField =
// Schemas created with co.map(), co.record(), co.list(), etc.
| AnyCoSchema
// CoValue classes created with class syntax, or framework-provided classes like Group
| CoValueClass
| ZodPrimitiveSchema
| z.core.$ZodOptional<z.core.$ZodType>
@@ -33,20 +43,35 @@ type FieldSchema =
| z.core.$ZodCatch<z.core.$ZodType>
| (z.core.$ZodCustom<any, any> & { builtin: any });
export function zodFieldToCoFieldDef(schema: FieldSchema) {
export function schemaFieldToCoFieldDef(
schema: SchemaField,
isOptional = false,
) {
if (isCoValueClass(schema)) {
return coField.ref(schema);
if (isOptional) {
return coField.ref(schema, { optional: true });
} else {
return coField.ref(schema);
}
} else if (isCoValueSchema(schema)) {
if (isAnyCoOptionalSchema(schema)) {
return coField.ref(schema.getCoValueClass(), {
optional: true,
});
}
if (isOptional) {
return coField.ref(schema.getCoValueClass(), { optional: true });
} else {
return coField.ref(schema.getCoValueClass());
}
} else {
if ("_zod" in schema) {
if (schema._zod.def.type === "optional") {
const inner = zodSchemaToCoSchemaOrKeepPrimitive(
schema._zod.def.innerType,
);
if (isCoValueClass(inner)) {
return coField.ref(inner, { optional: true });
} else {
return zodFieldToCoFieldDef(inner);
}
return schemaFieldToCoFieldDef(inner, true);
} else if (schema._zod.def.type === "string") {
return coField.string;
} else if (schema._zod.def.type === "number") {
@@ -58,8 +83,9 @@ export function zodFieldToCoFieldDef(schema: FieldSchema) {
} else if (schema._zod.def.type === "enum") {
return coField.string;
} else if (schema._zod.def.type === "readonly") {
return zodFieldToCoFieldDef(
(schema as unknown as ZodReadonly).def.innerType as FieldSchema,
return schemaFieldToCoFieldDef(
(schema as unknown as ZodReadonly).def.innerType as SchemaField,
isOptional,
);
} else if (schema._zod.def.type === "date") {
return coField.optional.Date;
@@ -67,8 +93,9 @@ export function zodFieldToCoFieldDef(schema: FieldSchema) {
return coField.string;
} else if (schema._zod.def.type === "lazy") {
// Mostly to support z.json()
return zodFieldToCoFieldDef(
(schema as unknown as ZodLazy).unwrap() as FieldSchema,
return schemaFieldToCoFieldDef(
(schema as unknown as ZodLazy).unwrap() as SchemaField,
isOptional,
);
} else if (
schema._zod.def.type === "default" ||
@@ -78,9 +105,10 @@ export function zodFieldToCoFieldDef(schema: FieldSchema) {
"z.default()/z.catch() are not supported in collaborative schemas. They will be ignored.",
);
return zodFieldToCoFieldDef(
return schemaFieldToCoFieldDef(
(schema as unknown as ZodDefault | ZodCatch).def
.innerType as FieldSchema,
.innerType as SchemaField,
isOptional,
);
} else if (schema._zod.def.type === "literal") {
if (
@@ -112,7 +140,7 @@ export function zodFieldToCoFieldDef(schema: FieldSchema) {
return coField.json();
} else if (schema._zod.def.type === "custom") {
if ("builtin" in schema) {
return zodFieldToCoFieldDef(schema.builtin);
return schemaFieldToCoFieldDef(schema.builtin, isOptional);
} else {
throw new Error(`Unsupported custom zod type`);
}
@@ -120,9 +148,13 @@ export function zodFieldToCoFieldDef(schema: FieldSchema) {
if (isUnionOfPrimitivesDeeply(schema)) {
return coField.json();
} else if (isUnionOfCoMapsDeeply(schema)) {
return coField.ref<CoValueClass<CoMap>>(
schemaUnionDiscriminatorFor(schema),
);
const result = schemaUnionDiscriminatorFor(schema);
if (isOptional) {
return coField.ref<CoValueClass<CoMap>>(result, { optional: true });
} else {
return coField.ref<CoValueClass<CoMap>>(result);
}
} else {
throw new Error(
"z.union()/z.discriminatedUnion() of mixed collaborative and non-collaborative types is not supported",

View File

@@ -9,89 +9,140 @@ import {
CoValueClass,
FileStream,
SchemaUnion,
enrichAccountSchema,
enrichCoDiscriminatedUnionSchema,
enrichCoFeedSchema,
enrichCoListSchema,
enrichCoMapSchema,
enrichFileStreamSchema,
enrichPlainTextSchema,
isCoValueClass,
} from "../../../internal.js";
import { coField } from "../../schema.js";
import { isAnyCoOptionalSchema } from "../schemaTypes/CoOptionalSchema.js";
import { enrichRichTextSchema } from "../schemaTypes/RichTextSchema.js";
import {
isUnionOfCoMapsDeeply,
schemaUnionDiscriminatorFor,
} from "../unionUtils.js";
import { z } from "../zodReExport.js";
import {
CoValueClassFromZodSchema,
AnyCoSchema,
CoValueClassFromAnySchema,
CoValueOrZodSchema,
CoValueSchemaFromZodSchema,
ZodPrimitiveSchema,
getDef,
isZodArray,
isZodCustom,
isZodObject,
} from "../zodSchema.js";
import { zodFieldToCoFieldDef } from "./zodFieldToCoFieldDef.js";
import { schemaFieldToCoFieldDef } from "./zodFieldToCoFieldDef.js";
let coSchemasForZodSchemas = new Map<z.core.$ZodType, CoValueClass>();
let coSchemasForZodSchemas = new Map<z.core.$ZodType, AnyCoSchema>();
export function tryZodSchemaToCoSchema<S extends z.core.$ZodType>(
export function isAnyCoValueSchema(
schema: z.core.$ZodType | CoValueClass,
): schema is AnyCoSchema {
return "collaborative" in schema && schema.collaborative === true;
}
export function isCoValueSchema(
schema: z.core.$ZodType | CoValueClass,
): schema is CoValueSchemaFromZodSchema<AnyCoSchema> {
return isAnyCoValueSchema(schema) && "getCoValueClass" in schema;
}
/**
* Convert a Zod schema into a CoValue schema.
*
* @param schema A Zod schema that may represent a CoValue schema
* @returns The CoValue schema matching the provided ProtoCoSchema, or `null` if the Zod schema
* does not match a CoValue schema.
*/
function tryZodSchemaToCoSchema<S extends z.core.$ZodType>(
schema: S,
): CoValueClassFromZodSchema<S> | null {
if ("collaborative" in schema && schema.collaborative) {
): CoValueSchemaFromZodSchema<S> | null {
if (isAnyCoValueSchema(schema)) {
if (coSchemasForZodSchemas.has(schema)) {
return coSchemasForZodSchemas.get(schema) as CoValueClassFromZodSchema<S>;
return coSchemasForZodSchemas.get(
schema,
) as CoValueSchemaFromZodSchema<S>;
}
if (isZodObject(schema)) {
if (isAnyCoOptionalSchema(schema)) {
// Optional schemas are not supported as top-level schemas
return null;
} else if (isZodObject(schema)) {
const def = getDef(schema);
const ClassToExtend =
"builtin" in schema && schema.builtin === "Account" ? Account : CoMap;
const coSchema = class ZCoMap extends ClassToExtend {
const coValueClass = class ZCoMap extends ClassToExtend {
constructor(options: { fromRaw: RawCoMap } | undefined) {
super(options);
for (const [field, fieldType] of Object.entries(
def.shape as z.core.$ZodShape,
)) {
(this as any)[field] = zodFieldToCoFieldDef(
(this as any)[field] = schemaFieldToCoFieldDef(
zodSchemaToCoSchemaOrKeepPrimitive(fieldType),
);
}
if (def.catchall) {
(this as any)[coField.items] = zodFieldToCoFieldDef(
(this as any)[coField.items] = schemaFieldToCoFieldDef(
zodSchemaToCoSchemaOrKeepPrimitive(def.catchall),
);
}
}
};
coSchemasForZodSchemas.set(schema, coSchema as unknown as CoValueClass);
return coSchema as unknown as CoValueClassFromZodSchema<S>;
const coValueSchema =
ClassToExtend === Account
? enrichAccountSchema(schema as any, coValueClass as any)
: enrichCoMapSchema(schema as any, coValueClass as any);
coSchemasForZodSchemas.set(schema, coValueSchema);
return coValueSchema as unknown as CoValueSchemaFromZodSchema<S>;
} else if (isZodArray(schema)) {
const def = getDef(schema);
const coSchema = class ZCoList extends CoList {
const coValueClass = class ZCoList extends CoList {
constructor(options: { fromRaw: RawCoList } | undefined) {
super(options);
(this as any)[coField.items] = zodFieldToCoFieldDef(
(this as any)[coField.items] = schemaFieldToCoFieldDef(
zodSchemaToCoSchemaOrKeepPrimitive(def.element),
);
}
};
coSchemasForZodSchemas.set(schema, coSchema);
return coSchema as unknown as CoValueClassFromZodSchema<S>;
const coValueSchema = enrichCoListSchema(schema, coValueClass as any);
coSchemasForZodSchemas.set(schema, coValueSchema);
return coValueSchema as unknown as CoValueSchemaFromZodSchema<S>;
} else if (isZodCustom(schema)) {
if ("builtin" in schema) {
if (schema.builtin === "CoFeed" && "element" in schema) {
return CoFeed.Of(
zodFieldToCoFieldDef(
const coValueClass = CoFeed.Of(
schemaFieldToCoFieldDef(
zodSchemaToCoSchemaOrKeepPrimitive(
schema.element as z.core.$ZodType,
),
),
) as unknown as CoValueClassFromZodSchema<S>;
);
const coValueSchema = enrichCoFeedSchema(schema, coValueClass as any);
return coValueSchema as unknown as CoValueSchemaFromZodSchema<S>;
} else if (schema.builtin === "FileStream") {
return FileStream as unknown as CoValueClassFromZodSchema<S>;
const coValueClass = FileStream;
const coValueSchema = enrichFileStreamSchema(schema, coValueClass);
return coValueSchema as unknown as CoValueSchemaFromZodSchema<S>;
} else if (schema.builtin === "CoPlainText") {
return CoPlainText as unknown as CoValueClassFromZodSchema<S>;
const coValueClass = CoPlainText;
const coValueSchema = enrichPlainTextSchema(schema, coValueClass);
return coValueSchema as unknown as CoValueSchemaFromZodSchema<S>;
} else if (schema.builtin === "CoRichText") {
return CoRichText as unknown as CoValueClassFromZodSchema<S>;
const coValueClass = CoRichText;
const coValueSchema = enrichRichTextSchema(schema, coValueClass);
return coValueSchema as unknown as CoValueSchemaFromZodSchema<S>;
} else {
throw new Error(`Unsupported builtin type: ${schema.builtin}`);
}
@@ -105,9 +156,12 @@ export function tryZodSchemaToCoSchema<S extends z.core.$ZodType>(
}
} else if (schema instanceof z.core.$ZodDiscriminatedUnion) {
if (isUnionOfCoMapsDeeply(schema)) {
return SchemaUnion.Of(
schemaUnionDiscriminatorFor(schema),
) as unknown as CoValueClassFromZodSchema<S>;
const coValueClass = SchemaUnion.Of(schemaUnionDiscriminatorFor(schema));
const coValueSchema = enrichCoDiscriminatedUnionSchema(
schema as any,
coValueClass as any,
);
return coValueSchema as unknown as CoValueSchemaFromZodSchema<S>;
} else {
throw new Error(
"z.discriminatedUnion() of non-collaborative types is not supported as a top-level schema",
@@ -118,19 +172,9 @@ export function tryZodSchemaToCoSchema<S extends z.core.$ZodType>(
}
}
export function zodSchemaToCoSchema<
S extends
| z.core.$ZodType
| (z.core.$ZodObject<any, any> & {
builtin: "Account";
migration?: (account: any, creationProps?: { name: string }) => void;
})
| (z.core.$ZodCustom<any, any> & { builtin: "FileStream" })
| (z.core.$ZodCustom<any, any> & {
builtin: "CoFeed";
element: z.core.$ZodType;
}),
>(schema: S): CoValueClassFromZodSchema<S> {
export function zodSchemaToCoSchema<S extends z.core.$ZodType | AnyCoSchema>(
schema: S,
): CoValueSchemaFromZodSchema<S> {
const coSchema = tryZodSchemaToCoSchema(schema);
if (!coSchema) {
throw new Error(
@@ -140,38 +184,24 @@ export function zodSchemaToCoSchema<
return coSchema;
}
export function anySchemaToCoSchema<
S extends
| CoValueClass
| z.core.$ZodType
| (z.core.$ZodObject<any, any> & {
builtin: "Account";
migration?: (account: any, creationProps?: { name: string }) => void;
})
| (z.core.$ZodCustom<any, any> & { builtin: "FileStream" })
| (z.core.$ZodCustom<any, any> & {
builtin: "CoFeed";
element: z.core.$ZodType;
}),
>(
// TODO this should be coValueClassOrAnySchemaToCoValueClass
export function anySchemaToCoSchema<S extends CoValueOrZodSchema>(
schema: S,
): S extends CoValueClass
? S
: S extends z.core.$ZodType
? CoValueClassFromZodSchema<S>
: never {
): CoValueClassFromAnySchema<S> {
if (isCoValueClass(schema)) {
return schema as any;
} else if ("getCoSchema" in schema) {
return (schema as any).getCoSchema() as any;
} else if (isCoValueSchema(schema)) {
return schema.getCoValueClass() as any;
} else if ("def" in schema) {
const coSchema = tryZodSchemaToCoSchema(schema as z.core.$ZodType);
const coSchema = tryZodSchemaToCoSchema(
schema as z.core.$ZodType | AnyCoSchema,
);
if (!coSchema) {
throw new Error(
`Unsupported zod type: ${(schema.def as any)?.type || JSON.stringify(schema)}`,
);
}
return coSchema as any;
return coSchema.getCoValueClass() as any;
}
throw new Error(`Unsupported schema: ${JSON.stringify(schema)}`);
@@ -179,7 +209,7 @@ export function anySchemaToCoSchema<
export function zodSchemaToCoSchemaOrKeepPrimitive<S extends z.core.$ZodType>(
schema: S,
): CoValueClassFromZodSchema<S> | ZodPrimitiveSchema {
): CoValueSchemaFromZodSchema<S> | ZodPrimitiveSchema {
const coSchema = tryZodSchemaToCoSchema(schema);
if (!coSchema) {
return schema as any;

View File

@@ -1,5 +1,10 @@
import { CryptoProvider } from "cojson";
import { Account, Group, RefsToResolveStrict } from "../../../internal.js";
import {
Account,
AccountCreationProps,
Group,
RefsToResolveStrict,
} from "../../../internal.js";
import { AnonymousJazzAgent } from "../../anonymousJazzAgent.js";
import { InstanceOrPrimitiveOfSchema } from "../typeConverters/InstanceOrPrimitiveOfSchema.js";
import { InstanceOrPrimitiveOfSchemaCoValuesNullable } from "../typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.js";
@@ -57,9 +62,63 @@ export type AccountSchema<
) => void,
): AccountSchema<Shape>;
getCoSchema: () => typeof Account;
getCoValueClass: () => typeof Account;
};
export function enrichAccountSchema<Shape extends BaseAccountShape>(
schema: AnyAccountSchema<Shape>,
coValueClass: typeof Account,
): AccountSchema<Shape> {
const enrichedSchema = Object.assign(schema, {
create: (...args: any[]) => {
// @ts-expect-error
return coValueClass.create(...args);
},
createAs: (...args: any[]) => {
// @ts-expect-error
return coValueClass.createAs(...args);
},
getMe: (...args: any[]) => {
// @ts-expect-error
return coValueClass.getMe(...args);
},
load: (...args: any[]) => {
// @ts-expect-error
return coValueClass.load(...args);
},
subscribe: (...args: any[]) => {
// @ts-expect-error
return coValueClass.subscribe(...args);
},
withHelpers: (helpers: (Self: z.core.$ZodType) => object) => {
return Object.assign(schema, helpers(schema));
},
fromRaw: (...args: any[]) => {
// @ts-expect-error
return coValueClass.fromRaw(...args);
},
withMigration: (
migration: (
value: any,
creationProps?: AccountCreationProps,
) => void | Promise<void>,
) => {
(coValueClass.prototype as Account).migrate = async function (
this,
creationProps,
) {
await migration(this, creationProps);
};
return enrichedSchema;
},
getCoValueClass: () => {
return coValueClass;
},
}) as unknown as AccountSchema<Shape>;
return enrichedSchema;
}
export type DefaultProfileShape = {
name: z.core.$ZodString<string>;
inbox: z.core.$ZodOptional<z.core.$ZodString>;
@@ -71,7 +130,7 @@ export type CoProfileSchema<
Config extends z.core.$ZodObjectConfig = z.core.$ZodObjectConfig,
> = CoMapSchema<Shape & DefaultProfileShape, Config, Group>;
// less precise verion to avoid circularity issues and allow matching against
// less precise version to avoid circularity issues and allow matching against
export type AnyAccountSchema<
Shape extends z.core.$ZodLooseShape = z.core.$ZodLooseShape,
> = z.core.$ZodObject<Shape> & {

View File

@@ -0,0 +1,90 @@
import {
Account,
AnonymousJazzAgent,
AnyCoSchema,
InstanceOrPrimitiveOfSchemaCoValuesNullable,
RefsToResolve,
RefsToResolveStrict,
Resolved,
SchemaUnion,
SubscribeListenerOptions,
} from "../../../internal.js";
import { z } from "../zodReExport.js";
export type AnyDiscriminableCoSchema = AnyCoSchema &
z.core.$ZodTypeDiscriminable;
export type AnyCoDiscriminatedUnionSchema<
Types extends readonly [
AnyDiscriminableCoSchema,
...AnyDiscriminableCoSchema[],
],
> = z.ZodDiscriminatedUnion<Types> & {
collaborative: true;
};
export type CoDiscriminatedUnionSchema<
Types extends readonly [
AnyDiscriminableCoSchema,
...AnyDiscriminableCoSchema[],
],
> = AnyCoDiscriminatedUnionSchema<Types> & {
load(
id: string,
options?: {
loadAs?: Account | AnonymousJazzAgent;
skipRetry?: boolean;
},
): Promise<Resolved<
CoDiscriminatedUnionInstanceCoValuesNullable<Types> & SchemaUnion,
true
> | null>;
subscribe(
id: string,
options: SubscribeListenerOptions<
CoDiscriminatedUnionInstanceCoValuesNullable<Types> & SchemaUnion,
true
>,
listener: (
value: Resolved<
CoDiscriminatedUnionInstanceCoValuesNullable<Types> & SchemaUnion,
true
>,
unsubscribe: () => void,
) => void,
): () => void;
getCoValueClass: () => typeof SchemaUnion;
};
export function enrichCoDiscriminatedUnionSchema<
Types extends readonly [
AnyDiscriminableCoSchema,
...AnyDiscriminableCoSchema[],
],
>(
schema: z.ZodDiscriminatedUnion<Types>,
coValueClass: typeof SchemaUnion,
): CoDiscriminatedUnionSchema<Types> {
return Object.assign(schema, {
load: (...args: [any, ...any]) => {
// @ts-expect-error
return coValueClass.load(...args);
},
subscribe: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.subscribe(...args);
},
getCoValueClass: () => {
return coValueClass;
},
}) as unknown as CoDiscriminatedUnionSchema<Types>;
}
type CoDiscriminatedUnionInstanceCoValuesNullable<
Types extends readonly [
AnyDiscriminableCoSchema,
...AnyDiscriminableCoSchema[],
],
> = NonNullable<InstanceOrPrimitiveOfSchemaCoValuesNullable<Types[number]>>;

View File

@@ -58,10 +58,35 @@ export type CoFeedSchema<T extends z.core.$ZodType> = z.core.$ZodCustom<
) => void,
): () => void;
getCoSchema: () => typeof CoFeed;
getCoValueClass: () => typeof CoFeed;
};
// less precise verion to avoid circularity issues and allow matching against
export function enrichCoFeedSchema<T extends z.core.$ZodType>(
schema: AnyCoFeedSchema<T>,
coValueClass: typeof CoFeed,
): CoFeedSchema<T> {
return Object.assign(schema, {
create: (...args: [any, ...any[]]) => {
return coValueClass.create(...args);
},
load: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.load(...args);
},
subscribe: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.subscribe(...args);
},
withHelpers: (helpers: (Self: z.core.$ZodType) => object) => {
return Object.assign(schema, helpers(schema));
},
getCoValueClass: () => {
return coValueClass;
},
}) as unknown as CoFeedSchema<T>;
}
// less precise version to avoid circularity issues and allow matching against
export type AnyCoFeedSchema<T extends z.core.$ZodType = z.core.$ZodType> =
z.core.$ZodCustom<any, unknown> & {
collaborative: true;

View File

@@ -19,9 +19,7 @@ type CoListInit<T extends z.core.$ZodType> = Array<
: NonNullable<InstanceOrPrimitiveOfSchemaCoValuesNullable<T>>
>;
export type CoListSchema<T extends z.core.$ZodType> = z.core.$ZodArray<T> & {
collaborative: true;
export type CoListSchema<T extends z.core.$ZodType> = AnyCoListSchema<T> & {
create: (
items: CoListInit<T>,
options?: { owner: Account | Group } | Account | Group,
@@ -52,10 +50,34 @@ export type CoListSchema<T extends z.core.$ZodType> = z.core.$ZodArray<T> & {
helpers: (Self: S) => T,
): WithHelpers<S, T>;
getCoSchema: () => typeof CoList;
getCoValueClass: () => typeof CoList;
};
// less precise verion to avoid circularity issues and allow matching against
export function enrichCoListSchema<T extends z.core.$ZodType>(
schema: AnyCoListSchema<T>,
coValueClass: typeof CoList,
): CoListSchema<T> {
return Object.assign(schema, {
create: (...args: [any, ...any[]]) => {
return coValueClass.create(...args);
},
load: (...args: [any, ...any[]]) => {
return coValueClass.load(...args);
},
subscribe: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.subscribe(...args);
},
withHelpers: (helpers: (Self: z.core.$ZodType) => object) => {
return Object.assign(schema, helpers(schema));
},
getCoValueClass: () => {
return coValueClass;
},
}) as unknown as CoListSchema<T>;
}
// less precise version to avoid circularity issues and allow matching against
export type AnyCoListSchema<T extends z.core.$ZodType = z.core.$ZodType> =
z.core.$ZodArray<T> & { collaborative: true };

View File

@@ -8,6 +8,7 @@ import {
Resolved,
Simplify,
SubscribeListenerOptions,
zodSchemaToCoSchema,
} from "../../../internal.js";
import { AnonymousJazzAgent } from "../../anonymousJazzAgent.js";
import { InstanceOrPrimitiveOfSchema } from "../typeConverters/InstanceOrPrimitiveOfSchema.js";
@@ -19,10 +20,8 @@ export type CoMapSchema<
Shape extends z.core.$ZodLooseShape,
Config extends z.core.$ZodObjectConfig = z.core.$ZodObjectConfig,
Owner extends Account | Group = Account | Group,
> = z.core.$ZodObject<Shape, Config> &
> = AnyCoMapSchema<Shape, Config> &
z.$ZodTypeDiscriminable & {
collaborative: true;
create: (
init: Simplify<CoMapInitZod<Shape>>,
options?:
@@ -145,9 +144,65 @@ export type CoMapSchema<
) => undefined,
): CoMapSchema<Shape, Config, Owner>;
getCoSchema: () => typeof CoMap;
getCoValueClass: () => typeof CoMap;
};
export function enrichCoMapSchema<
Shape extends z.core.$ZodLooseShape,
Config extends z.core.$ZodObjectConfig,
>(
schema: AnyCoMapSchema<Shape, Config>,
coValueClass: typeof CoMap,
): CoMapSchema<Shape, Config> {
// @ts-expect-error schema is actually a z.ZodObject, but we need to use z.core.$ZodObject to avoid circularity issues
const baseCatchall = schema.catchall;
const coValueSchema = Object.assign(schema, {
create: (...args: [any, ...any[]]) => {
return coValueClass.create(...args);
},
load: (...args: [any, ...any[]]) => {
return coValueClass.load(...args);
},
subscribe: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.subscribe(...args);
},
findUnique: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.findUnique(...args);
},
upsertUnique: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.upsertUnique(...args);
},
loadUnique: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.loadUnique(...args);
},
catchall: (index: z.core.$ZodType) => {
const newSchema = baseCatchall(index);
// TODO avoid repeating this with coMapDefiner
const enrichedSchema = Object.assign(newSchema, {
collaborative: true,
}) as AnyCoMapSchema<Shape, Config>;
return zodSchemaToCoSchema(enrichedSchema);
},
withHelpers: (helpers: (Self: z.core.$ZodType) => object) => {
return Object.assign(schema, helpers(schema));
},
withMigration: (migration: (value: any) => undefined) => {
// @ts-expect-error TODO check
coValueClass.prototype.migrate = migration;
return coValueSchema;
},
getCoValueClass: () => {
return coValueClass;
},
}) as unknown as CoMapSchema<Shape, Config>;
return coValueSchema;
}
export type optionalKeys<Shape extends z.core.$ZodLooseShape> = {
[key in keyof Shape]: Shape[key] extends z.core.$ZodOptional<any>
? key
@@ -170,7 +225,7 @@ export type CoMapInitZod<Shape extends z.core.$ZodLooseShape> = {
>;
} & { [key in keyof Shape]?: unknown };
// less precise verion to avoid circularity issues and allow matching against
// less precise version to avoid circularity issues and allow matching against
export type AnyCoMapSchema<
Shape extends z.core.$ZodLooseShape = z.core.$ZodLooseShape,
Config extends z.core.$ZodObjectConfig = z.core.$ZodObjectConfig,

View File

@@ -0,0 +1,33 @@
import { isAnyCoValueSchema } from "../runtimeConverters/zodSchemaToCoSchema.js";
import { z } from "../zodReExport.js";
import { AnyCoSchema, CoValueSchemaFromZodSchema } from "../zodSchema.js";
export type AnyCoOptionalSchema<
Shape extends z.core.$ZodType = z.core.$ZodType,
> = z.ZodOptional<Shape> & {
collaborative: true;
};
export type CoOptionalSchema<Shape extends z.core.$ZodType = z.core.$ZodType> =
AnyCoOptionalSchema<Shape> & {
getCoValueClass: () => CoValueSchemaFromZodSchema<AnyCoSchema>["getCoValueClass"];
};
export function createCoOptionalSchema<T extends AnyCoSchema>(
schema: T,
): CoOptionalSchema<T> {
return Object.assign(z.optional(schema), {
collaborative: true,
getCoValueClass: () => {
return (
schema as CoValueSchemaFromZodSchema<AnyCoSchema>
).getCoValueClass();
},
}) as unknown as CoOptionalSchema<T>;
}
export function isAnyCoOptionalSchema(
schema: z.core.$ZodType,
): schema is CoOptionalSchema<z.core.$ZodType> {
return isAnyCoValueSchema(schema) && schema._zod.def.type === "optional";
}

View File

@@ -28,9 +28,7 @@ type CoRecordInit<
export type CoRecordSchema<
K extends z.core.$ZodString<string>,
V extends z.core.$ZodType,
> = z.core.$ZodRecord<K, V> & {
collaborative: true;
> = AnyCoRecordSchema<K, V> & {
create: (
init: Simplify<CoRecordInit<K, V>>,
options?:
@@ -83,10 +81,10 @@ export type CoRecordSchema<
this: S,
helpers: (Self: S) => T,
): WithHelpers<S, T>;
getCoSchema: () => typeof CoMap;
getCoValueClass: () => typeof CoMap;
};
// less precise verion to avoid circularity issues and allow matching against
// less precise version to avoid circularity issues and allow matching against
export type AnyCoRecordSchema<
K extends z.core.$ZodString<string> = z.core.$ZodString<string>,
V extends z.core.$ZodType = z.core.$ZodType,

View File

@@ -6,9 +6,12 @@ import {
} from "../../../internal.js";
import { z } from "../zodReExport.js";
export type FileStreamSchema = z.core.$ZodCustom<FileStream, unknown> & {
export type AnyFileStreamSchema = z.core.$ZodCustom<FileStream, unknown> & {
collaborative: true;
builtin: "FileStream";
};
export type FileStreamSchema = AnyFileStreamSchema & {
create(options?: { owner?: Account | Group } | Account | Group): FileStream;
createFromBlob(
blob: Blob | File,
@@ -40,5 +43,32 @@ export type FileStreamSchema = z.core.$ZodCustom<FileStream, unknown> & {
id: string,
listener: (value: FileStream, unsubscribe: () => void) => void,
): () => void;
getCoSchema: () => typeof FileStream;
getCoValueClass: () => typeof FileStream;
};
export function enrichFileStreamSchema(
schema: AnyFileStreamSchema,
coValueClass: typeof FileStream,
): FileStreamSchema {
return Object.assign(schema, {
create: (...args: any[]) => {
return coValueClass.create(...args);
},
createFromBlob: (...args: [any, ...any[]]) => {
return coValueClass.createFromBlob(...args);
},
load: (...args: [any, ...any[]]) => {
return coValueClass.load(...args);
},
loadAsBlob: (...args: [any, ...any[]]) => {
return coValueClass.loadAsBlob(...args);
},
subscribe: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.subscribe(...args);
},
getCoValueClass: () => {
return coValueClass;
},
}) as unknown as FileStreamSchema;
}

View File

@@ -3,9 +3,12 @@ import { Account, CoPlainText, Group } from "../../../internal.js";
import { AnonymousJazzAgent } from "../../anonymousJazzAgent.js";
import { z } from "../zodReExport.js";
export type PlainTextSchema = z.core.$ZodCustom<CoPlainText, unknown> & {
export type AnyPlainTextSchema = z.core.$ZodCustom<CoPlainText, unknown> & {
collaborative: true;
builtin: "CoPlainText";
};
export type PlainTextSchema = AnyPlainTextSchema & {
create(
text: string,
options?: { owner: Account | Group } | Account | Group,
@@ -24,5 +27,30 @@ export type PlainTextSchema = z.core.$ZodCustom<CoPlainText, unknown> & {
listener: (value: CoPlainText, unsubscribe: () => void) => void,
): () => void;
fromRaw(raw: RawCoPlainText): CoPlainText;
getCoSchema: () => typeof CoPlainText;
getCoValueClass: () => typeof CoPlainText;
};
export function enrichPlainTextSchema(
schema: AnyPlainTextSchema,
coValueClass: typeof CoPlainText,
): PlainTextSchema {
return Object.assign(schema, {
create: (...args: [any, ...any[]]) => {
return coValueClass.create(...args);
},
load: (...args: [any, ...any[]]) => {
return coValueClass.load(...args);
},
subscribe: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.subscribe(...args);
},
fromRaw: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.fromRaw(...args);
},
getCoValueClass: () => {
return coValueClass;
},
}) as unknown as PlainTextSchema;
}

View File

@@ -2,9 +2,12 @@ import { Account, CoRichText, Group } from "../../../internal.js";
import { AnonymousJazzAgent } from "../../anonymousJazzAgent.js";
import { z } from "../zodReExport.js";
export type RichTextSchema = z.core.$ZodCustom<CoRichText, unknown> & {
export type AnyRichTextSchema = z.core.$ZodCustom<CoRichText, unknown> & {
collaborative: true;
builtin: "CoRichText";
};
export type RichTextSchema = AnyRichTextSchema & {
create(
text: string,
options?: { owner: Account | Group } | Account | Group,
@@ -22,5 +25,26 @@ export type RichTextSchema = z.core.$ZodCustom<CoRichText, unknown> & {
id: string,
listener: (value: CoRichText, unsubscribe: () => void) => void,
): () => void;
getCoSchema: () => typeof CoRichText;
getCoValueClass: () => typeof CoRichText;
};
export function enrichRichTextSchema(
schema: AnyRichTextSchema,
coValueClass: typeof CoRichText,
): RichTextSchema {
return Object.assign(schema, {
create: (...args: [any, ...any[]]) => {
return coValueClass.create(...args);
},
load: (...args: [any, ...any[]]) => {
return coValueClass.load(...args);
},
subscribe: (...args: [any, ...any[]]) => {
// @ts-expect-error
return coValueClass.subscribe(...args);
},
getCoValueClass: () => {
return coValueClass;
},
}) as unknown as RichTextSchema;
}

View File

@@ -1,5 +1,7 @@
import {
Account,
AnyAccountSchema,
AnyCoRecordSchema,
CoFeed,
CoList,
CoMap,
@@ -11,24 +13,19 @@ import {
import { AnyCoFeedSchema } from "../schemaTypes/CoFeedSchema.js";
import { AnyCoListSchema } from "../schemaTypes/CoListSchema.js";
import { AnyCoMapSchema } from "../schemaTypes/CoMapSchema.js";
import { FileStreamSchema } from "../schemaTypes/FileStreamSchema.js";
import { PlainTextSchema } from "../schemaTypes/PlainTextSchema.js";
import { RichTextSchema } from "../schemaTypes/RichTextSchema.js";
import { AnyFileStreamSchema } from "../schemaTypes/FileStreamSchema.js";
import { AnyPlainTextSchema } from "../schemaTypes/PlainTextSchema.js";
import { AnyRichTextSchema } from "../schemaTypes/RichTextSchema.js";
import { z } from "../zodReExport.js";
import { InstanceOrPrimitiveOfSchema } from "./InstanceOrPrimitiveOfSchema.js";
export type InstanceOfSchema<S extends CoValueClass | z.core.$ZodType> =
S extends z.core.$ZodType
? S extends z.core.$ZodObject<infer Shape> & {
collaborative: true;
builtin: "Account";
}
? S extends AnyAccountSchema<infer Shape>
? {
[key in keyof Shape]: InstanceOrPrimitiveOfSchema<Shape[key]>;
} & Account
: S extends z.core.$ZodRecord<infer K, infer V> & {
collaborative: true;
}
: S extends AnyCoRecordSchema<infer K, infer V>
? {
[key in z.output<K> & string]: InstanceOrPrimitiveOfSchema<V>;
} & CoMap
@@ -45,11 +42,11 @@ export type InstanceOfSchema<S extends CoValueClass | z.core.$ZodType> =
? CoList<InstanceOrPrimitiveOfSchema<T>>
: S extends AnyCoFeedSchema<infer T>
? CoFeed<InstanceOrPrimitiveOfSchema<T>>
: S extends PlainTextSchema
: S extends AnyPlainTextSchema
? CoPlainText
: S extends RichTextSchema
: S extends AnyRichTextSchema
? CoRichText
: S extends FileStreamSchema
: S extends AnyFileStreamSchema
? FileStream
: S extends z.core.$ZodOptional<infer Inner>
? InstanceOrPrimitiveOfSchema<Inner>

View File

@@ -1,5 +1,12 @@
import { RawAccount, RawCoList, RawCoMap } from "cojson";
import { zodSchemaToCoSchema } from "./runtimeConverters/zodSchemaToCoSchema.js";
import { CoValueClass, CoValueFromRaw } from "../../internal.js";
import {
isAnyCoValueSchema,
zodSchemaToCoSchema,
} from "./runtimeConverters/zodSchemaToCoSchema.js";
import { AccountSchema } from "./schemaTypes/AccountSchema.js";
import { CoListSchema } from "./schemaTypes/CoListSchema.js";
import { CoMapSchema } from "./schemaTypes/CoMapSchema.js";
import { z } from "./zodReExport.js";
export function schemaUnionDiscriminatorFor(
@@ -8,7 +15,7 @@ export function schemaUnionDiscriminatorFor(
if (isUnionOfCoMapsDeeply(schema)) {
if (!schema._zod.disc || schema._zod.disc.size == 0) {
throw new Error(
"z.union() of collaborative types is not supported, use z.discriminatedUnion() instead",
"z.union() of collaborative types is not supported, use co.discriminatedUnion() instead",
);
}
@@ -17,14 +24,14 @@ export function schemaUnionDiscriminatorFor(
if (!field) {
throw new Error(
"z.discriminatedUnion() of collaborative types with non-existent discriminator key is not supported",
"co.discriminatedUnion() of collaborative types with non-existent discriminator key is not supported",
);
}
for (const value of field.values) {
if (typeof value !== "string" && typeof value !== "number") {
throw new Error(
"z.discriminatedUnion() of collaborative types with non-string or non-number discriminator value is not supported",
"co.discriminatedUnion() of collaborative types with non-string or non-number discriminator value is not supported",
);
}
}
@@ -42,7 +49,7 @@ export function schemaUnionDiscriminatorFor(
}
} else {
throw new Error(
"Unsupported zod type in z.discriminatedUnion() of collaborative types",
"Unsupported zod type in co.discriminatedUnion() of collaborative types",
);
}
}
@@ -50,7 +57,7 @@ export function schemaUnionDiscriminatorFor(
const determineSchema = (_raw: RawCoMap | RawAccount | RawCoList) => {
if (_raw instanceof RawCoList) {
throw new Error(
"z.discriminatedUnion() of collaborative types is not supported for CoLists",
"co.discriminatedUnion() of collaborative types is not supported for CoLists",
);
}
@@ -90,12 +97,17 @@ export function schemaUnionDiscriminatorFor(
}
if (match) {
return zodSchemaToCoSchema(option);
const coValueSchema = zodSchemaToCoSchema(option) as
| CoMapSchema<any>
| AccountSchema
| CoListSchema<any>;
return coValueSchema.getCoValueClass() as CoValueClass<any> &
CoValueFromRaw<any>;
}
}
throw new Error(
"z.discriminatedUnion() of collaborative types with no matching discriminator value found",
"co.discriminatedUnion() of collaborative types with no matching discriminator value found",
);
};
@@ -120,11 +132,7 @@ export function isUnionOfCoMapsDeeply(
function isCoMapOrUnionOfCoMapsDeeply(
schema: z.core.$ZodType,
): schema is z.core.$ZodDiscriminatedUnion {
if (
schema instanceof z.core.$ZodObject &&
"collaborative" in schema &&
schema.collaborative
) {
if (schema instanceof z.core.$ZodObject && isAnyCoValueSchema(schema)) {
return true;
} else if (schema instanceof z.core.$ZodUnion) {
return schema._zod.def.options.every(isCoMapOrUnionOfCoMapsDeeply);
@@ -137,6 +145,6 @@ export function isUnionOfPrimitivesDeeply(schema: z.core.$ZodType) {
if (schema instanceof z.core.$ZodUnion) {
return schema._zod.def.options.every(isUnionOfPrimitivesDeeply);
} else {
return !("collaborative" in schema);
return !isAnyCoValueSchema(schema);
}
}

View File

@@ -1,8 +1,11 @@
import {
type Account,
type AccountCreationProps,
type AccountSchema,
type AnyCoMapSchema,
AnyAccountSchema,
AnyCoFeedSchema,
AnyCoListSchema,
AnyCoSchema,
AnyFileStreamSchema,
AnyPlainTextSchema,
BaseAccountShape,
CoFeed,
type CoFeedSchema,
@@ -20,121 +23,31 @@ import {
type Simplify,
zodSchemaToCoSchema,
} from "../../internal.js";
import { RichTextSchema } from "./schemaTypes/RichTextSchema.js";
import {
AnyDiscriminableCoSchema,
CoDiscriminatedUnionSchema,
} from "./schemaTypes/CoDiscriminatedUnionSchema.js";
import {
CoOptionalSchema,
createCoOptionalSchema,
} from "./schemaTypes/CoOptionalSchema.js";
import {
AnyRichTextSchema,
RichTextSchema,
} from "./schemaTypes/RichTextSchema.js";
import { z } from "./zodReExport.js";
function enrichCoMapSchema<Shape extends z.core.$ZodLooseShape>(
schema: z.ZodObject<
{ -readonly [P in keyof Shape]: Shape[P] },
z.core.$strip
>,
) {
const baseCatchall = schema.catchall;
const enrichedSchema = Object.assign(schema, {
collaborative: true,
create: (...args: any[]) => {
return coSchema.create(...args);
},
load: (...args: any[]) => {
return coSchema.load(...args);
},
subscribe: (...args: any[]) => {
return coSchema.subscribe(...args);
},
findUnique: (...args: any[]) => {
return coSchema.findUnique(...args);
},
upsertUnique: (...args: any[]) => {
return coSchema.upsertUnique(...args);
},
loadUnique: (...args: any[]) => {
return coSchema.loadUnique(...args);
},
catchall: (index: z.core.$ZodType) => {
return enrichCoMapSchema(baseCatchall(index));
},
withHelpers: (helpers: (Self: z.core.$ZodType) => object) => {
return Object.assign(schema, helpers(schema));
},
withMigration: (migration: (value: any) => undefined) => {
coSchema.prototype.migrate = migration;
return enrichedSchema;
},
getCoSchema: () => {
return coSchema;
},
}) as unknown as CoMapSchema<Shape>;
// Needs to be derived from the enriched schema
const coSchema = zodSchemaToCoSchema(enrichedSchema) as any;
return enrichedSchema;
}
export const coMapDefiner = <Shape extends z.core.$ZodLooseShape>(
shape: Shape,
): CoMapSchema<Shape> => {
const objectSchema = z.object(shape).meta({
collaborative: true,
});
return enrichCoMapSchema(objectSchema);
};
function enrichAccountSchema<Shape extends BaseAccountShape>(
schema: z.ZodObject<Shape, z.core.$strip>,
) {
const enrichedSchema = Object.assign(schema, {
const enrichedSchema = Object.assign(objectSchema, {
collaborative: true,
builtin: "Account",
create: (...args: any[]) => {
return coSchema.create(...args);
},
createAs: (...args: any[]) => {
return coSchema.createAs(...args);
},
getMe: (...args: any[]) => {
return coSchema.getMe(...args);
},
load: (...args: any[]) => {
return coSchema.load(...args);
},
subscribe: (...args: any[]) => {
return coSchema.subscribe(...args);
},
withHelpers: (helpers: (Self: z.core.$ZodType) => object) => {
return Object.assign(schema, helpers(schema));
},
fromRaw: (...args: any[]) => {
return coSchema.fromRaw(...args);
},
withMigration: (
migration: (
value: any,
creationProps?: AccountCreationProps,
) => void | Promise<void>,
) => {
(coSchema.prototype as Account).migrate = async function (
this,
creationProps,
) {
await migration(this, creationProps);
};
return enrichedSchema;
},
getCoSchema: () => {
return coSchema;
},
}) as unknown as AccountSchema<Shape>;
// Needs to be derived from the enriched schema
const coSchema = zodSchemaToCoSchema(enrichedSchema) as any;
return enrichedSchema;
}
});
return zodSchemaToCoSchema(enrichedSchema);
};
/**
* Defines a collaborative account schema for Jazz applications.
@@ -183,11 +96,14 @@ export const coAccountDefiner = <Shape extends BaseAccountShape>(
root: coMapDefiner({}),
} as unknown as Shape,
): AccountSchema<Shape> => {
const objectSchema = z.object(shape).meta({
const schema = z.object(shape).meta({
collaborative: true,
});
return enrichAccountSchema(objectSchema) as unknown as AccountSchema<Shape>;
const enrichedSchema = Object.assign(schema, {
collaborative: true,
builtin: "Account",
}) as AnyAccountSchema<Shape>;
return zodSchemaToCoSchema(enrichedSchema);
};
export const coRecordDefiner = <
@@ -203,190 +119,86 @@ export const coRecordDefiner = <
>;
};
function enrichCoListSchema<T extends z.core.$ZodType>(schema: z.ZodArray<T>) {
const enrichedSchema = Object.assign(schema, {
collaborative: true,
create: (...args: any[]) => {
return coSchema.create(...args);
},
load: (...args: any[]) => {
return coSchema.load(...args);
},
subscribe: (...args: any[]) => {
return coSchema.subscribe(...args);
},
withHelpers: (helpers: (Self: z.core.$ZodType) => object) => {
return Object.assign(schema, helpers(schema));
},
getCoSchema: () => {
return coSchema;
},
}) as unknown as CoListSchema<T>;
// Needs to be derived from the enriched schema
const coSchema = zodSchemaToCoSchema(enrichedSchema) as any;
return enrichedSchema;
}
export const coListDefiner = <T extends z.core.$ZodType>(
element: T,
): CoListSchema<T> => {
const arraySchema = z.array(element).meta({
const schema = z.array(element).meta({
collaborative: true,
});
return enrichCoListSchema(arraySchema);
const enrichedSchema = Object.assign(schema, {
collaborative: true,
}) as AnyCoListSchema<T>;
return zodSchemaToCoSchema(enrichedSchema) as unknown as CoListSchema<T>;
};
export const coProfileDefiner = <
Shape extends z.core.$ZodLooseShape = Simplify<DefaultProfileShape>,
>(
shape: Shape & {
name?: z.core.$ZodString<string>;
inbox?: z.core.$ZodOptional<z.core.$ZodString>;
inboxInvite?: z.core.$ZodOptional<z.core.$ZodString>;
} = {} as any,
shape: Shape & Partial<DefaultProfileShape> = {} as any,
): CoProfileSchema<Shape> => {
const ehnancedShape = Object.assign(shape ?? {}, {
const ehnancedShape = Object.assign(shape, {
name: z.string(),
inbox: z.optional(z.string()),
inboxInvite: z.optional(z.string()),
});
return coMapDefiner(ehnancedShape) as CoProfileSchema<Shape>;
};
function enrichCoFeedSchema<T extends z.core.$ZodType>(
schema: z.ZodCustom<CoFeed<unknown>, unknown>,
element: T,
) {
const enrichedSchema = Object.assign(schema, {
collaborative: true,
builtin: "CoFeed",
element,
create: (...args: any[]) => {
return coSchema.create(...args);
},
load: (...args: any[]) => {
return coSchema.load(...args);
},
subscribe: (...args: any[]) => {
return coSchema.subscribe(...args);
},
withHelpers: (helpers: (Self: z.core.$ZodType) => object) => {
return Object.assign(schema, helpers(schema));
},
getCoSchema: () => {
return coSchema;
},
}) as unknown as CoFeedSchema<T>;
// Needs to be derived from the enriched schema
const coSchema = zodSchemaToCoSchema(enrichedSchema) as any;
return enrichedSchema;
}
export const coFeedDefiner = <T extends z.core.$ZodType>(
element: T,
): CoFeedSchema<T> => {
return enrichCoFeedSchema(z.instanceof(CoFeed), element);
const schema = z.instanceof(CoFeed);
const enrichedSchema = Object.assign(schema, {
collaborative: true,
builtin: "CoFeed",
element,
}) as AnyCoFeedSchema<T>;
return zodSchemaToCoSchema(enrichedSchema);
};
function enrichFileStreamSchema(schema: z.ZodCustom<FileStream, unknown>) {
export const coFileStreamDefiner = (): FileStreamSchema => {
const schema = z.instanceof(FileStream);
const enrichedSchema = Object.assign(schema, {
collaborative: true,
builtin: "FileStream",
create: (...args: any[]) => {
return coSchema.create(...args);
},
createFromBlob: (...args: any[]) => {
return coSchema.createFromBlob(...args);
},
load: (...args: any[]) => {
return coSchema.load(...args);
},
loadAsBlob: (...args: any[]) => {
return coSchema.loadAsBlob(...args);
},
subscribe: (...args: any[]) => {
return coSchema.subscribe(...args);
},
getCoSchema: () => {
return coSchema;
},
}) as unknown as FileStreamSchema;
// Needs to be derived from the enriched schema
const coSchema = zodSchemaToCoSchema(enrichedSchema) as any;
return enrichedSchema;
}
export const coFileStreamDefiner = (): FileStreamSchema => {
return enrichFileStreamSchema(z.instanceof(FileStream));
}) as AnyFileStreamSchema;
return zodSchemaToCoSchema(enrichedSchema);
};
function enrichPlainTextSchema(schema: z.ZodCustom<CoPlainText, unknown>) {
export const coPlainTextDefiner = (): PlainTextSchema => {
const schema = z.instanceof(CoPlainText);
const enrichedSchema = Object.assign(schema, {
collaborative: true,
builtin: "CoPlainText",
create: (...args: any[]) => {
return coSchema.create(...args);
},
load: (...args: any[]) => {
return coSchema.load(...args);
},
subscribe: (...args: any[]) => {
return coSchema.subscribe(...args);
},
fromRaw: (...args: any[]) => {
return coSchema.fromRaw(...args);
},
getCoSchema: () => {
return coSchema;
},
}) as unknown as PlainTextSchema;
// Needs to be derived from the enriched schema
const coSchema = zodSchemaToCoSchema(enrichedSchema) as any;
return enrichedSchema;
}
export const coPlainTextDefiner = (): PlainTextSchema => {
return enrichPlainTextSchema(z.instanceof(CoPlainText));
}) as AnyPlainTextSchema;
return zodSchemaToCoSchema(enrichedSchema);
};
function enrichRichTextSchema(schema: z.ZodCustom<CoRichText, unknown>) {
export const coRichTextDefiner = (): RichTextSchema => {
const schema = z.instanceof(CoRichText);
const enrichedSchema = Object.assign(schema, {
collaborative: true,
builtin: "CoRichText",
create: (...args: any[]) => {
return coSchema.create(...args);
},
load: (...args: any[]) => {
return coSchema.load(...args);
},
subscribe: (...args: any[]) => {
return coSchema.subscribe(...args);
},
getCoSchema: () => {
return coSchema;
},
}) as unknown as RichTextSchema;
// Needs to be derived from the enriched schema
const coSchema = zodSchemaToCoSchema(enrichedSchema) as any;
return enrichedSchema;
}
export const coRichTextDefiner = (): RichTextSchema => {
return enrichRichTextSchema(z.instanceof(CoRichText));
}) as AnyRichTextSchema;
return zodSchemaToCoSchema(enrichedSchema);
};
export const coImageDefiner = (): typeof ImageDefinition => {
return ImageDefinition;
};
export const coOptionalDefiner = <T extends AnyCoSchema>(
schema: T,
): CoOptionalSchema<T> => {
return createCoOptionalSchema(schema);
};
export const coDiscriminatedUnionDefiner = <
T extends readonly [AnyDiscriminableCoSchema, ...AnyDiscriminableCoSchema[]],
>(
discriminator: string,
schemas: T,
): CoDiscriminatedUnionSchema<T> => {
const schema = z.discriminatedUnion(discriminator, schemas as any);
return zodSchemaToCoSchema(schema);
};

View File

@@ -1,13 +1,19 @@
import {
ZodArray,
ZodTuple,
ZodUnion,
core,
array as zodArray,
tuple as zodTuple,
union as zodUnion,
} from "zod/v4";
export {
string,
number,
boolean,
union,
object,
array,
templateLiteral,
json,
tuple,
date,
emoji,
base64,
@@ -29,8 +35,8 @@ export {
int32,
strictObject,
discriminatedUnion,
// intersection,
// record,
// record,
// intersection,
int,
optional,
type ZodOptional,
@@ -39,5 +45,29 @@ export {
type ZodDefault,
type ZodCatch,
type output as infer,
type ZodDiscriminatedUnion,
z,
} from "zod/v4";
type NonCoZodType = core.$ZodType & { collaborative?: false };
export function union<const T extends readonly NonCoZodType[]>(
options: T,
params?: string | core.$ZodUnionParams,
): ZodUnion<T> {
return zodUnion(options, params);
}
export function array<T extends NonCoZodType>(
element: T,
params?: string | core.$ZodArrayParams,
): ZodArray<T> {
return zodArray(element, params);
}
export function tuple<T extends readonly [NonCoZodType, ...NonCoZodType[]]>(
options: T,
params?: string | core.$ZodTupleParams,
): ZodTuple<T> {
return zodTuple(options, params);
}

View File

@@ -2,23 +2,47 @@ import { LocalNode, RawAccount } from "cojson";
import {
Account,
AccountClass,
CoValue,
CoValueClass,
CoValueFromRaw,
InstanceOfSchema,
RefsToResolve,
RefsToResolveStrict,
Resolved,
Simplify,
} from "../../internal.js";
import { AnyAccountSchema } from "./schemaTypes/AccountSchema.js";
import { AnyCoFeedSchema } from "./schemaTypes/CoFeedSchema.js";
import { AnyCoListSchema } from "./schemaTypes/CoListSchema.js";
import { AnyCoMapSchema, CoMapInitZod } from "./schemaTypes/CoMapSchema.js";
import { AnyCoRecordSchema } from "./schemaTypes/CoRecordSchema.js";
import { FileStreamSchema } from "./schemaTypes/FileStreamSchema.js";
import { PlainTextSchema } from "./schemaTypes/PlainTextSchema.js";
import { RichTextSchema } from "./schemaTypes/RichTextSchema.js";
import { InstanceOfSchema } from "./typeConverters/InstanceOfSchema.js";
import {
AccountSchema,
AnyAccountSchema,
BaseAccountShape,
} from "./schemaTypes/AccountSchema.js";
import {
AnyDiscriminableCoSchema,
CoDiscriminatedUnionSchema,
} from "./schemaTypes/CoDiscriminatedUnionSchema.js";
import { AnyCoFeedSchema, CoFeedSchema } from "./schemaTypes/CoFeedSchema.js";
import { AnyCoListSchema, CoListSchema } from "./schemaTypes/CoListSchema.js";
import {
AnyCoMapSchema,
CoMapInitZod,
CoMapSchema,
} from "./schemaTypes/CoMapSchema.js";
import { AnyCoOptionalSchema } from "./schemaTypes/CoOptionalSchema.js";
import {
AnyCoRecordSchema,
CoRecordSchema,
} from "./schemaTypes/CoRecordSchema.js";
import {
AnyFileStreamSchema,
FileStreamSchema,
} from "./schemaTypes/FileStreamSchema.js";
import {
AnyPlainTextSchema,
PlainTextSchema,
} from "./schemaTypes/PlainTextSchema.js";
import {
AnyRichTextSchema,
RichTextSchema,
} from "./schemaTypes/RichTextSchema.js";
import { InstanceOfSchemaCoValuesNullable } from "./typeConverters/InstanceOfSchemaCoValuesNullable.js";
import { z } from "./zodReExport.js";
@@ -47,7 +71,7 @@ export type AnyCoUnionSchema = z.core.$ZodDiscriminatedUnion<
// this is a series of hacks to work around z4 removing _zod at runtime from z.core.$ZodType
export function isZodObject(
schema: z.core.$ZodType,
): schema is z.core.$ZodObject<any, any> {
): schema is z.ZodObject<any, any> {
return (schema as any).def?.type === "object";
}
@@ -67,19 +91,53 @@ export function getDef<S extends z.core.$ZodType>(schema: S): S["_zod"]["def"] {
return (schema as any).def;
}
// TODO rename. This represents a CoValue class or a CoValue schema
export type CoValueOrZodSchema = CoValueClass | AnyCoSchema;
export type CoValueClassFromZodSchema<S extends z.core.$ZodType> = CoValueClass<
InstanceOfSchema<S>
> &
CoValueFromRaw<InstanceOfSchema<S>> &
(S extends AnyAccountSchema ? AccountClassEssentials : {});
// TODO rename to CoValueSchemaFromCoProtoSchema
export type CoValueSchemaFromZodSchema<S extends z.core.$ZodType> =
S extends z.core.$ZodType
? S extends AnyAccountSchema<infer Shape extends BaseAccountShape>
? AccountSchema<Shape>
: S extends AnyCoRecordSchema<infer K, infer V>
? CoRecordSchema<K, V>
: S extends AnyCoMapSchema<infer Shape, infer Config>
? CoMapSchema<Shape, Config>
: S extends AnyCoListSchema<infer T>
? CoListSchema<T>
: S extends AnyCoFeedSchema<infer T>
? CoFeedSchema<T>
: S extends AnyPlainTextSchema
? PlainTextSchema
: S extends AnyRichTextSchema
? RichTextSchema
: S extends AnyFileStreamSchema
? FileStreamSchema
: S extends z.core.$ZodOptional<infer Inner>
? CoValueSchemaFromZodSchema<Inner>
: S extends z.core.$ZodUnion<
infer Members extends readonly [
AnyDiscriminableCoSchema,
...AnyDiscriminableCoSchema[],
]
>
? CoDiscriminatedUnionSchema<Members>
: never
: never;
export type CoValueClassFromAnySchema<S extends CoValueOrZodSchema> =
S extends CoValueClass<any>
? S
: CoValueClass<InstanceOfSchema<S>> &
CoValueFromRaw<InstanceOfSchema<S>> &
(S extends AnyAccountSchema ? AccountClassEssentials : {});
type AccountClassEssentials = {
fromRaw: <A extends Account>(this: AccountClass<A>, raw: RawAccount) => A;
fromNode: <A extends Account>(this: AccountClass<A>, node: LocalNode) => A;
};
// TODO rename to ProtoCoSchema?
export type AnyCoSchema =
| AnyCoMapSchema
| AnyAccountSchema
@@ -87,9 +145,10 @@ export type AnyCoSchema =
| AnyCoListSchema
| AnyCoFeedSchema
| AnyCoUnionSchema
| PlainTextSchema
| RichTextSchema
| FileStreamSchema;
| AnyCoOptionalSchema
| AnyPlainTextSchema
| AnyRichTextSchema
| AnyFileStreamSchema;
export type Loaded<
T extends CoValueClass | AnyCoSchema,

View File

@@ -33,6 +33,7 @@ export * from "./implementation/zodSchema/zodSchema.js";
export * from "./implementation/zodSchema/zodCo.js";
export * as co from "./implementation/zodSchema/coExport.js";
export * from "./implementation/zodSchema/schemaTypes/CoMapSchema.js";
export * from "./implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.js";
export * from "./implementation/zodSchema/schemaTypes/CoRecordSchema.js";
export * from "./implementation/zodSchema/schemaTypes/CoListSchema.js";
export * from "./implementation/zodSchema/schemaTypes/CoFeedSchema.js";

View File

@@ -28,6 +28,10 @@ export class CoValueCoreSubscription {
this.subscribeToState();
this.listener("unavailable");
}
})
.catch((error) => {
console.error("Unexpected error loading CoValue: ", error);
this.listener("unavailable");
});
}
}

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