Compare commits

...

17 Commits

Author SHA1 Message Date
Guido D'Orsi
d1609cdd55 Merge pull request #2679 from garden-co/changeset-release/main
Version Packages
2025-07-28 18:12:46 +02:00
github-actions[bot]
b71ab3168a Version Packages 2025-07-28 15:15:40 +00:00
Nico Rainhart
0c8f6e5039 Merge pull request #2677 from garden-co/feat/add-nullable-support
feat: Add support for nullable non-collaborative fields
2025-07-28 12:12:12 -03:00
NicoR
6a93a1b8a3 chore: add comment on why nullable date cofields are not supported 2025-07-28 11:52:44 -03:00
NicoR
9f654a2603 test: loading a map with a nullable field 2025-07-28 11:46:50 -03:00
NicoR
dbf735d9e1 Fix rebase error 2025-07-28 10:27:44 -03:00
NicoR
c62abefb66 Add changeset 2025-07-28 10:19:55 -03:00
NicoR
1453869a46 Add support for nullable non-collaborative fields 2025-07-28 10:18:39 -03:00
NicoR
0c0178764e chore: fix rebase errors 2025-07-28 09:34:24 -03:00
NicoR
928350b821 refactor: rename OptionalizeUndefinedKeys to PartialOnUndefined 2025-07-28 09:34:23 -03:00
NicoR
be3fd9c696 test: create CoMap with shallowly resolved CoValue 2025-07-28 09:34:23 -03:00
NicoR
269c028df0 test: add test for CoMapSchema + catchall 2025-07-28 09:34:23 -03:00
NicoR
e4df837138 refactor: rename CoMapInitZod to CoMapSchemaInit 2025-07-28 09:34:23 -03:00
NicoR
54fe6d93ba refactor: extract CoMapSchema.create's return type 2025-07-28 09:34:23 -03:00
NicoR
979689c6d8 refactor: improve CatchAll type handling in CoMapSchemas 2025-07-28 09:34:23 -03:00
NicoR
859a37868f refactor: simplify CoMapSchema.create's return type 2025-07-28 09:34:23 -03:00
NicoR
57bd32d77e refactor: simplify the type of CoMapSchema.create's init parameter 2025-07-28 09:34:23 -03:00
48 changed files with 472 additions and 209 deletions

View File

@@ -1,5 +1,12 @@
# passkey-svelte
## 0.0.107
### Patch Changes
- Updated dependencies [c62abef]
- jazz-tools@0.16.1
## 0.0.106
### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# cojson-storage-indexeddb
## 0.16.1
### Patch Changes
- cojson@0.16.1
## 0.16.0
### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# cojson-storage-sqlite
## 0.16.1
### Patch Changes
- cojson@0.16.1
## 0.16.0
### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# cojson-transport-nodejs-ws
## 0.16.1
### Patch Changes
- cojson@0.16.1
## 0.16.0
### Patch Changes

View File

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

View File

@@ -1,5 +1,7 @@
# cojson
## 0.16.1
## 0.16.0
### Minor Changes

View File

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

View File

@@ -1,5 +1,14 @@
# jazz-auth-betterauth
## 0.16.1
### Patch Changes
- Updated dependencies [c62abef]
- jazz-tools@0.16.1
- jazz-betterauth-client-plugin@0.16.1
- cojson@0.16.1
## 0.16.0
### Patch Changes

View File

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

View File

@@ -1,5 +1,11 @@
# jazz-betterauth-client-plugin
## 0.16.1
### Patch Changes
- jazz-betterauth-server-plugin@0.16.1
## 0.16.0
### Patch Changes

View File

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

View File

@@ -1,5 +1,13 @@
# jazz-betterauth-server-plugin
## 0.16.1
### Patch Changes
- Updated dependencies [c62abef]
- jazz-tools@0.16.1
- cojson@0.16.1
## 0.16.0
### Patch Changes

View File

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

View File

@@ -1,5 +1,15 @@
# jazz-react-auth-betterauth
## 0.16.1
### Patch Changes
- Updated dependencies [c62abef]
- jazz-tools@0.16.1
- jazz-auth-betterauth@0.16.1
- jazz-betterauth-client-plugin@0.16.1
- cojson@0.16.1
## 0.16.0
### Patch Changes

View File

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

View File

@@ -1,5 +1,15 @@
# jazz-run
## 0.16.1
### Patch Changes
- Updated dependencies [c62abef]
- jazz-tools@0.16.1
- cojson@0.16.1
- cojson-storage-sqlite@0.16.1
- cojson-transport-ws@0.16.1
## 0.16.0
### Patch Changes

View File

@@ -3,7 +3,7 @@
"bin": "./dist/index.js",
"type": "module",
"license": "MIT",
"version": "0.16.0",
"version": "0.16.1",
"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.16.0",
"cojson-storage-sqlite": "workspace:0.16.0",
"cojson-transport-ws": "workspace:0.16.0",
"cojson": "workspace:0.16.1",
"cojson-storage-sqlite": "workspace:0.16.1",
"cojson-transport-ws": "workspace:0.16.1",
"effect": "^3.6.5",
"jazz-tools": "workspace:0.16.0",
"jazz-tools": "workspace:0.16.1",
"ws": "^8.14.2"
},
"devDependencies": {

View File

@@ -1,5 +1,14 @@
# jazz-tools
## 0.16.1
### Patch Changes
- c62abef: Add support for nullable non-collaborative fields
- cojson@0.16.1
- cojson-storage-indexeddb@0.16.1
- cojson-transport-ws@0.16.1
## 0.16.0
### Minor Changes

View File

@@ -139,7 +139,7 @@
},
"type": "module",
"license": "MIT",
"version": "0.16.0",
"version": "0.16.1",
"dependencies": {
"@manuscripts/prosemirror-recreate-steps": "^0.1.4",
"@scure/base": "1.2.1",

View File

@@ -14,6 +14,7 @@ import type {
CoValueClass,
Group,
ID,
PartialOnUndefined,
RefEncoded,
RefIfCoValue,
RefsToResolve,
@@ -778,13 +779,9 @@ type ForceRequiredRef<V> = V extends InstanceType<CoValueClass> | null
? V | null
: V;
export type CoMapInit<Map extends object> = {
[Key in CoKeys<Map> as undefined extends Map[Key]
? never
: Key]: ForceRequiredRef<Map[Key]>;
} & {
[Key in CoKeys<Map>]?: ForceRequiredRef<Map[Key]>;
};
export type CoMapInit<Map extends object> = PartialOnUndefined<{
[Key in CoKeys<Map>]: ForceRequiredRef<Map[Key]>;
}>;
// TODO: cache handlers per descriptor for performance?
const CoMapProxyHandler: ProxyHandler<CoMap> = {

View File

@@ -10,8 +10,8 @@ import z from "zod/v4";
import {
AnyZodOrCoValueSchema,
CoMap,
CoMapInitZod,
CoMapSchema,
CoMapSchemaInit,
CoValueClass,
CoreCoMapSchema,
Group,
@@ -93,7 +93,7 @@ type AsNullablePayload<T extends MessageShape> = T extends Record<string, never>
? undefined
: never;
type MessageValuePayload<T extends MessageShape> =
| Simplify<CoMapInitZod<T>>
| Simplify<CoMapSchemaInit<T>>
| AsNullablePayload<T>;
function createMessageEnvelope<S extends MessageShape>(

View File

@@ -22,6 +22,7 @@ export type SchemaField =
| CoValueClass
| ZodPrimitiveSchema
| z.core.$ZodOptional<z.core.$ZodType>
| z.core.$ZodNullable<z.core.$ZodType>
| z.core.$ZodUnion<z.core.$ZodType[]>
| z.core.$ZodDiscriminatedUnion<z.core.$ZodType[]>
| z.core.$ZodObject<z.core.$ZodLooseShape>
@@ -49,9 +50,24 @@ export function schemaFieldToCoFieldDef(schema: SchemaField) {
} else {
if ("_zod" in schema) {
const zodSchemaDef = schema._zod.def;
if (zodSchemaDef.type === "optional") {
if (
zodSchemaDef.type === "optional" ||
zodSchemaDef.type === "nullable"
) {
const inner = zodSchemaDef.innerType as ZodPrimitiveSchema;
return schemaFieldToCoFieldDef(inner);
const coFieldDef: any = schemaFieldToCoFieldDef(inner);
if (
zodSchemaDef.type === "nullable" &&
coFieldDef === coField.optional.Date
) {
// We do not currently have a way to encode null Date coFields.
// We only support encoding optional (i.e. Date | undefined) coFields.
throw new Error("Nullable z.date() is not supported");
}
// Primitive coField types support null and undefined as values,
// so we can just return the inner type here and rely on support
// for null/undefined at the type level
return coFieldDef;
} else if (zodSchemaDef.type === "string") {
return coField.string;
} else if (zodSchemaDef.type === "number") {

View File

@@ -3,7 +3,6 @@ import {
AnyZodOrCoValueSchema,
CoFeed,
Group,
NotNull,
RefsToResolve,
RefsToResolveStrict,
Resolved,
@@ -12,13 +11,14 @@ import {
coOptionalDefiner,
} from "../../../internal.js";
import { AnonymousJazzAgent } from "../../anonymousJazzAgent.js";
import { CoFieldInit } from "../typeConverters/CoFieldInit.js";
import { InstanceOrPrimitiveOfSchema } from "../typeConverters/InstanceOrPrimitiveOfSchema.js";
import { InstanceOrPrimitiveOfSchemaCoValuesNullable } from "../typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.js";
import { CoOptionalSchema } from "./CoOptionalSchema.js";
import { CoreCoValueSchema } from "./CoValueSchema.js";
type CoFeedInit<T extends AnyZodOrCoValueSchema> = Simplify<
Array<NotNull<InstanceOrPrimitiveOfSchemaCoValuesNullable<T>>>
Array<CoFieldInit<T>>
>;
export class CoFeedSchema<T extends AnyZodOrCoValueSchema>

View File

@@ -2,7 +2,6 @@ import {
Account,
CoList,
Group,
NotNull,
RefsToResolve,
RefsToResolveStrict,
Resolved,
@@ -11,6 +10,7 @@ import {
coOptionalDefiner,
} from "../../../internal.js";
import { AnonymousJazzAgent } from "../../anonymousJazzAgent.js";
import { CoFieldInit } from "../typeConverters/CoFieldInit.js";
import { InstanceOrPrimitiveOfSchema } from "../typeConverters/InstanceOrPrimitiveOfSchema.js";
import { InstanceOrPrimitiveOfSchemaCoValuesNullable } from "../typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.js";
import { AnyZodOrCoValueSchema } from "../zodSchema.js";
@@ -18,7 +18,7 @@ import { CoOptionalSchema } from "./CoOptionalSchema.js";
import { CoreCoValueSchema } from "./CoValueSchema.js";
type CoListInit<T extends AnyZodOrCoValueSchema> = Simplify<
Array<NotNull<InstanceOrPrimitiveOfSchemaCoValuesNullable<T>>>
Array<CoFieldInit<T>>
>;
export class CoListSchema<T extends AnyZodOrCoValueSchema>

View File

@@ -5,6 +5,7 @@ import {
DiscriminableCoValueSchemaDefinition,
DiscriminableCoreCoValueSchema,
Group,
PartialOnUndefined,
RefsToResolve,
RefsToResolveStrict,
Resolved,
@@ -16,11 +17,12 @@ import {
} from "../../../internal.js";
import { AnonymousJazzAgent } from "../../anonymousJazzAgent.js";
import { removeGetters } from "../../schemaUtils.js";
import { CoFieldInit } from "../typeConverters/CoFieldInit.js";
import { InstanceOrPrimitiveOfSchema } from "../typeConverters/InstanceOrPrimitiveOfSchema.js";
import { InstanceOrPrimitiveOfSchemaCoValuesNullable } from "../typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.js";
import { z } from "../zodReExport.js";
import { AnyZodOrCoValueSchema } from "../zodSchema.js";
import { CoOptionalSchema, CoreCoOptionalSchema } from "./CoOptionalSchema.js";
import { CoOptionalSchema } from "./CoOptionalSchema.js";
export interface CoMapSchema<
Shape extends z.core.$ZodLooseShape,
@@ -28,25 +30,14 @@ export interface CoMapSchema<
Owner extends Account | Group = Account | Group,
> extends CoreCoMapSchema<Shape, CatchAll> {
create: (
init: Simplify<CoMapInitZod<Shape>>,
init: Simplify<CoMapSchemaInit<Shape>>,
options?:
| {
owner: Owner;
unique?: CoValueUniqueness["uniqueness"];
}
| Owner,
) => (Shape extends Record<string, never>
? {}
: {
-readonly [key in keyof Shape]: InstanceOrPrimitiveOfSchema<Shape[key]>;
}) &
(unknown extends CatchAll
? {}
: {
// @ts-expect-error
[key: string]: InstanceOrPrimitiveOfSchema<CatchAll>;
}) &
CoMap;
) => CoMapInstanceShape<Shape, CatchAll> & CoMap;
load<
const R extends RefsToResolve<
@@ -98,7 +89,7 @@ export interface CoMapSchema<
Simplify<CoMapInstanceCoValuesNullable<Shape>> & CoMap
> = true,
>(options: {
value: Simplify<CoMapInitZod<Shape>>;
value: Simplify<CoMapSchemaInit<Shape>>;
unique: CoValueUniqueness["uniqueness"];
owner: Owner;
resolve?: RefsToResolveStrict<
@@ -236,31 +227,12 @@ export function enrichCoMapSchema<
return coValueSchema;
}
export type optionalKeys<Shape extends z.core.$ZodLooseShape> = {
[key in keyof Shape]: Shape[key] extends
| z.core.$ZodOptional<any>
| CoreCoOptionalSchema<any>
? key
: never;
}[keyof Shape];
export type requiredKeys<Shape extends z.core.$ZodLooseShape> = {
[key in keyof Shape]: Shape[key] extends
| z.core.$ZodOptional<any>
| CoreCoOptionalSchema<any>
? never
: key;
}[keyof Shape];
export type CoMapInitZod<Shape extends z.core.$ZodLooseShape> = {
[key in optionalKeys<Shape>]?: NonNullable<
InstanceOrPrimitiveOfSchemaCoValuesNullable<Shape[key]>
>;
} & {
[key in requiredKeys<Shape>]: NonNullable<
InstanceOrPrimitiveOfSchemaCoValuesNullable<Shape[key]>
>;
} & { [key in keyof Shape]?: unknown };
// Due to a TS limitation with types that contain known properties and
// an index signature, we cannot accept catchall properties on creation
export type CoMapSchemaInit<Shape extends z.core.$ZodLooseShape> =
PartialOnUndefined<{
[key in keyof Shape]: CoFieldInit<Shape[key]>;
}>;
export interface CoMapSchemaDefinition<
Shape extends z.core.$ZodLooseShape = z.core.$ZodLooseShape,
@@ -281,9 +253,16 @@ export interface CoreCoMapSchema<
getDefinition: () => CoMapSchemaDefinition;
}
export type CoMapInstance<Shape extends z.core.$ZodLooseShape> = {
export type CoMapInstanceShape<
Shape extends z.core.$ZodLooseShape,
CatchAll extends AnyZodOrCoValueSchema | unknown = unknown,
> = {
-readonly [key in keyof Shape]: InstanceOrPrimitiveOfSchema<Shape[key]>;
} & CoMap;
} & (CatchAll extends AnyZodOrCoValueSchema
? {
[key: string]: InstanceOrPrimitiveOfSchema<CatchAll>;
}
: {});
export type CoMapInstanceCoValuesNullable<Shape extends z.core.$ZodLooseShape> =
{

View File

@@ -5,7 +5,6 @@ import {
CoMapSchemaDefinition,
Group,
ID,
NotNull,
RefsToResolve,
RefsToResolveStrict,
Resolved,
@@ -13,6 +12,7 @@ import {
SubscribeListenerOptions,
} from "../../../internal.js";
import { AnonymousJazzAgent } from "../../anonymousJazzAgent.js";
import { CoFieldInit } from "../typeConverters/CoFieldInit.js";
import { InstanceOrPrimitiveOfSchema } from "../typeConverters/InstanceOrPrimitiveOfSchema.js";
import { InstanceOrPrimitiveOfSchemaCoValuesNullable } from "../typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.js";
import { z } from "../zodReExport.js";
@@ -24,7 +24,7 @@ type CoRecordInit<
K extends z.core.$ZodString<string>,
V extends AnyZodOrCoValueSchema,
> = {
[key in z.output<K>]: NotNull<InstanceOrPrimitiveOfSchemaCoValuesNullable<V>>;
[key in z.output<K>]: CoFieldInit<V>;
};
export interface CoRecordSchema<

View File

@@ -0,0 +1,13 @@
import { NotNull } from "../../../internal.js";
import { z } from "../zodReExport.js";
import { AnyZodOrCoValueSchema } from "../zodSchema.js";
import { InstanceOrPrimitiveOfSchemaCoValuesNullable } from "./InstanceOrPrimitiveOfSchemaCoValuesNullable.js";
/**
* Returns the type of the value that should be used to initialize a coField
* of the given schema.
*/
export type CoFieldInit<T extends AnyZodOrCoValueSchema> =
T extends z.core.$ZodNullable
? InstanceOrPrimitiveOfSchemaCoValuesNullable<T>
: NotNull<InstanceOrPrimitiveOfSchemaCoValuesNullable<T>>;

View File

@@ -36,12 +36,11 @@ export type InstanceOfSchema<S extends CoValueClass | AnyZodOrCoValueSchema> =
: S extends CoreCoMapSchema<infer Shape, infer CatchAll>
? {
[key in keyof Shape]: InstanceOrPrimitiveOfSchema<Shape[key]>;
} & (unknown extends CatchAll
? {}
: {
// @ts-expect-error
} & (CatchAll extends AnyZodOrCoValueSchema
? {
[key: string]: InstanceOrPrimitiveOfSchema<CatchAll>;
}) &
}
: {}) &
CoMap
: S extends CoreCoListSchema<infer T>
? CoList<InstanceOrPrimitiveOfSchema<T>>

View File

@@ -47,13 +47,13 @@ export type InstanceOfSchemaCoValuesNullable<
[key in keyof Shape]: InstanceOrPrimitiveOfSchemaCoValuesNullable<
Shape[key]
>;
} & (unknown extends CatchAll
? {}
: {
} & (CatchAll extends AnyZodOrCoValueSchema
? {
[
key: string // @ts-expect-error
key: string
]: InstanceOrPrimitiveOfSchemaCoValuesNullable<CatchAll>;
}) &
}
: {}) &
CoMap)
| null
: S extends CoreCoListSchema<infer T>

View File

@@ -41,12 +41,11 @@ export type InstanceOrPrimitiveOfSchema<
-readonly [key in keyof Shape]: InstanceOrPrimitiveOfSchema<
Shape[key]
>;
} & (unknown extends CatchAll
? {}
: {
// @ts-expect-error
} & (CatchAll extends AnyZodOrCoValueSchema
? {
[key: string]: InstanceOrPrimitiveOfSchema<CatchAll>;
}) &
}
: {}) &
CoMap
: S extends CoreCoListSchema<infer T>
? CoList<InstanceOrPrimitiveOfSchema<T>>
@@ -66,56 +65,58 @@ export type InstanceOrPrimitiveOfSchema<
: S extends z.core.$ZodType
? S extends z.core.$ZodOptional<infer Inner extends z.core.$ZodType>
? InstanceOrPrimitiveOfSchema<Inner> | undefined
: S extends z.ZodJSONSchema
? JsonValue
: S extends z.core.$ZodUnion<infer Members extends z.core.$ZodType[]>
? InstanceOrPrimitiveOfSchema<Members[number]>
: // primitives below here - we manually traverse to ensure we only allow what we can handle
S extends z.core.$ZodObject<infer Shape>
? {
-readonly [key in keyof Shape]: InstanceOrPrimitiveOfSchema<
Shape[key]
>;
}
: S extends z.core.$ZodArray<infer Item extends z.core.$ZodType>
? InstanceOrPrimitiveOfSchema<Item>[]
: S extends z.core.$ZodTuple<
infer Items extends readonly z.core.$ZodType[]
>
? {
[key in keyof Items]: InstanceOrPrimitiveOfSchema<
Items[key]
>;
}
: S extends z.core.$ZodString
? string
: S extends z.core.$ZodNumber
? number
: S extends z.core.$ZodBoolean
? boolean
: S extends z.core.$ZodLiteral<infer Literal>
? Literal
: S extends z.core.$ZodDate
? Date
: S extends z.core.$ZodEnum<infer Enum>
? Enum[keyof Enum]
: S extends z.core.$ZodTemplateLiteral<
infer pattern
>
? pattern
: S extends z.core.$ZodReadonly<
infer Inner extends z.core.$ZodType
: S extends z.core.$ZodNullable<infer Inner extends z.core.$ZodType>
? InstanceOrPrimitiveOfSchema<Inner> | null
: S extends z.ZodJSONSchema
? JsonValue
: S extends z.core.$ZodUnion<infer Members extends z.core.$ZodType[]>
? InstanceOrPrimitiveOfSchema<Members[number]>
: // primitives below here - we manually traverse to ensure we only allow what we can handle
S extends z.core.$ZodObject<infer Shape>
? {
-readonly [key in keyof Shape]: InstanceOrPrimitiveOfSchema<
Shape[key]
>;
}
: S extends z.core.$ZodArray<infer Item extends z.core.$ZodType>
? InstanceOrPrimitiveOfSchema<Item>[]
: S extends z.core.$ZodTuple<
infer Items extends readonly z.core.$ZodType[]
>
? {
[key in keyof Items]: InstanceOrPrimitiveOfSchema<
Items[key]
>;
}
: S extends z.core.$ZodString
? string
: S extends z.core.$ZodNumber
? number
: S extends z.core.$ZodBoolean
? boolean
: S extends z.core.$ZodLiteral<infer Literal>
? Literal
: S extends z.core.$ZodDate
? Date
: S extends z.core.$ZodEnum<infer Enum>
? Enum[keyof Enum]
: S extends z.core.$ZodTemplateLiteral<
infer pattern
>
? InstanceOrPrimitiveOfSchema<Inner>
: S extends z.core.$ZodDefault<
infer Default extends z.core.$ZodType
? pattern
: S extends z.core.$ZodReadonly<
infer Inner extends z.core.$ZodType
>
? InstanceOrPrimitiveOfSchema<Default>
: S extends z.core.$ZodCatch<
infer Catch extends z.core.$ZodType
? InstanceOrPrimitiveOfSchema<Inner>
: S extends z.core.$ZodDefault<
infer Default extends z.core.$ZodType
>
? InstanceOrPrimitiveOfSchema<Catch>
: never
? InstanceOrPrimitiveOfSchema<Default>
: S extends z.core.$ZodCatch<
infer Catch extends z.core.$ZodType
>
? InstanceOrPrimitiveOfSchema<Catch>
: never
: S extends CoValueClass
? InstanceType<S>
: never;

View File

@@ -49,13 +49,13 @@ export type InstanceOrPrimitiveOfSchemaCoValuesNullable<
-readonly [key in keyof Shape]: InstanceOrPrimitiveOfSchemaCoValuesNullable<
Shape[key]
>;
} & (unknown extends CatchAll
? {}
: {
} & (CatchAll extends AnyZodOrCoValueSchema
? {
[
key: string // @ts-expect-error
key: string
]: InstanceOrPrimitiveOfSchemaCoValuesNullable<CatchAll>;
}) &
}
: {}) &
CoMap)
| null
: S extends CoreCoListSchema<infer T>
@@ -78,58 +78,60 @@ export type InstanceOrPrimitiveOfSchemaCoValuesNullable<
: S extends z.core.$ZodType
? S extends z.core.$ZodOptional<infer Inner extends z.core.$ZodType>
? InstanceOrPrimitiveOfSchemaCoValuesNullable<Inner> | undefined
: S extends z.ZodJSONSchema
? JsonValue
: S extends z.core.$ZodUnion<
infer Members extends readonly z.core.$ZodType[]
>
? InstanceOrPrimitiveOfSchemaCoValuesNullable<Members[number]>
: // primitives below here - we manually traverse to ensure we only allow what we can handle
S extends z.core.$ZodObject<infer Shape>
? {
-readonly [key in keyof Shape]: InstanceOrPrimitiveOfSchema<
Shape[key]
>;
}
: S extends z.core.$ZodArray<infer Item extends z.core.$ZodType>
? InstanceOrPrimitiveOfSchema<Item>[]
: S extends z.core.$ZodTuple<
infer Items extends z.core.$ZodType[]
>
? {
[key in keyof Items]: InstanceOrPrimitiveOfSchema<
Items[key]
>;
}
: S extends z.core.$ZodString
? string
: S extends z.core.$ZodNumber
? number
: S extends z.core.$ZodBoolean
? boolean
: S extends z.core.$ZodLiteral<infer Literal>
? Literal
: S extends z.core.$ZodDate
? Date
: S extends z.core.$ZodEnum<infer Enum>
? Enum[keyof Enum]
: S extends z.core.$ZodTemplateLiteral<
infer pattern
>
? pattern
: S extends z.core.$ZodReadonly<
infer Inner extends z.core.$ZodType
: S extends z.core.$ZodNullable<infer Inner extends z.core.$ZodType>
? InstanceOrPrimitiveOfSchemaCoValuesNullable<Inner> | null
: S extends z.ZodJSONSchema
? JsonValue
: S extends z.core.$ZodUnion<
infer Members extends readonly z.core.$ZodType[]
>
? InstanceOrPrimitiveOfSchemaCoValuesNullable<Members[number]>
: // primitives below here - we manually traverse to ensure we only allow what we can handle
S extends z.core.$ZodObject<infer Shape>
? {
-readonly [key in keyof Shape]: InstanceOrPrimitiveOfSchema<
Shape[key]
>;
}
: S extends z.core.$ZodArray<infer Item extends z.core.$ZodType>
? InstanceOrPrimitiveOfSchema<Item>[]
: S extends z.core.$ZodTuple<
infer Items extends z.core.$ZodType[]
>
? {
[key in keyof Items]: InstanceOrPrimitiveOfSchema<
Items[key]
>;
}
: S extends z.core.$ZodString
? string
: S extends z.core.$ZodNumber
? number
: S extends z.core.$ZodBoolean
? boolean
: S extends z.core.$ZodLiteral<infer Literal>
? Literal
: S extends z.core.$ZodDate
? Date
: S extends z.core.$ZodEnum<infer Enum>
? Enum[keyof Enum]
: S extends z.core.$ZodTemplateLiteral<
infer pattern
>
? InstanceOrPrimitiveOfSchema<Inner>
: S extends z.core.$ZodDefault<
infer Default extends z.core.$ZodType
? pattern
: S extends z.core.$ZodReadonly<
infer Inner extends z.core.$ZodType
>
? InstanceOrPrimitiveOfSchema<Default>
: S extends z.core.$ZodCatch<
infer Catch extends z.core.$ZodType
? InstanceOrPrimitiveOfSchema<Inner>
: S extends z.core.$ZodDefault<
infer Default extends z.core.$ZodType
>
? InstanceOrPrimitiveOfSchema<Catch>
: never
? InstanceOrPrimitiveOfSchema<Default>
: S extends z.core.$ZodCatch<
infer Catch extends z.core.$ZodType
>
? InstanceOrPrimitiveOfSchema<Catch>
: never
: S extends CoValueClass
? InstanceType<S> | null
: never;

View File

@@ -108,7 +108,7 @@ export const coListDefiner = <T extends AnyZodOrCoValueSchema>(
element: T,
): CoListSchema<T> => {
const coreSchema = createCoreCoListSchema(element);
return hydrateCoreCoValueSchema(coreSchema) as unknown as CoListSchema<T>;
return hydrateCoreCoValueSchema(coreSchema);
};
export const coProfileDefiner = <
@@ -121,7 +121,7 @@ export const coProfileDefiner = <
inbox: z.optional(z.string()),
inboxInvite: z.optional(z.string()),
});
return coMapDefiner(ehnancedShape) as CoProfileSchema<Shape>;
return coMapDefiner(ehnancedShape) as unknown as CoProfileSchema<Shape>;
};
export const coFeedDefiner = <T extends AnyZodOrCoValueSchema>(

View File

@@ -24,8 +24,8 @@ import {
import { CoFeedSchema, CoreCoFeedSchema } from "./schemaTypes/CoFeedSchema.js";
import { CoListSchema, CoreCoListSchema } from "./schemaTypes/CoListSchema.js";
import {
CoMapInitZod,
CoMapSchema,
CoMapSchemaInit,
CoreCoMapSchema,
} from "./schemaTypes/CoMapSchema.js";
import {
@@ -126,5 +126,5 @@ export type ResolveQueryStrict<
export type InitFor<T extends CoValueClassOrSchema> = T extends CoreCoMapSchema<
infer Shape
>
? Simplify<CoMapInitZod<Shape>>
? Simplify<CoMapSchemaInit<Shape>>
: never;

View File

@@ -1,3 +1,12 @@
/**
* Make any property optional if its type includes `undefined`, preserving the type as-is
*/
export type PartialOnUndefined<T> = {
[K in keyof T as undefined extends T[K] ? never : K]: T[K];
} & {
[K in keyof T as undefined extends T[K] ? K : never]?: T[K];
};
/**
* Useful to flatten the type output to improve type hints shown in editors.
* And also to transform an interface into a type to aide with assignability.

View File

@@ -13,15 +13,9 @@ import {
FileStream,
Group,
co,
cojsonInternals,
isControlledAccount,
z,
} from "../index.js";
import {
Loaded,
createJazzContextFromExistingCredentials,
randomSessionProvider,
} from "../internal.js";
import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
import { setupTwoNodes } from "./utils.js";
@@ -58,6 +52,14 @@ describe("Simple CoFeed operations", async () => {
expect(stream.perSession[me.sessionID]?.value).toEqual("milk");
});
test("Construction with nullable values", () => {
const NullableTestStream = co.feed(z.string().nullable());
const stream = NullableTestStream.create(["milk", null], { owner: me });
expect(stream.perAccount[me.id]?.value).toEqual(null);
expect(stream.perSession[me.sessionID]?.value).toEqual(null);
});
test("Construction with an Account", () => {
const stream = TestStream.create(["milk"], me);

View File

@@ -52,6 +52,16 @@ describe("Simple CoList operations", async () => {
expect(list[2]).toBe("c");
});
test("list with nullable content", () => {
const List = co.list(z.string().nullable());
const list = List.create(["a", "b", "c", null]);
expect(list.length).toBe(4);
expect(list[0]).toBe("a");
expect(list[1]).toBe("b");
expect(list[2]).toBe("c");
expect(list[3]).toBeNull();
});
test("Construction with an Account", () => {
const list = TestList.create(["milk"], me);

View File

@@ -52,6 +52,15 @@ describe("CoMap.Record", async () => {
expect(Object.keys(person)).toEqual(["age"]);
});
test("create a Record with nullable values", () => {
const Person = co.record(z.string(), z.string().nullable());
const person = Person.create({ name: "John", age: null });
person.bio = null;
expect(person.name).toEqual("John");
expect(person.age).toEqual(null);
expect(person.bio).toEqual(null);
});
test("property existence", () => {
const Person = co.record(z.string(), z.string());

View File

@@ -1,7 +1,7 @@
import { assert, describe, expectTypeOf, test } from "vitest";
import { Group, co, z } from "../exports.js";
import { Account } from "../index.js";
import { Loaded } from "../internal.js";
import { CoMap, Loaded } from "../internal.js";
describe("CoMap", async () => {
describe("init", () => {
@@ -408,4 +408,32 @@ describe("CoMap resolution", async () => {
| null
>();
});
test("loading a map with a nullable field", async () => {
const Dog = co.map({
name: z.string(),
breed: z.string(),
});
const Person = co.map({
name: z.string(),
age: z.number().nullable(),
dog: Dog,
});
const person = Person.create({
name: "John",
age: 20,
dog: Dog.create({ name: "Rex", breed: "Labrador" }),
});
const loadedPerson = await Person.load(person.id);
expectTypeOf(loadedPerson!).toEqualTypeOf<
{
name: string;
age: number | null;
dog: Loaded<typeof Dog> | null;
} & CoMap
>();
});
});

View File

@@ -143,8 +143,7 @@ describe("CoMap", async () => {
const Person = co.map({
name: z.string(),
age: z.number(),
// TODO: would be nice if this didn't need a type annotation
get friend(): co.Optional<typeof Person> {
get friend() {
return co.optional(Person);
},
});
@@ -291,6 +290,74 @@ describe("CoMap", async () => {
age: 30,
});
});
it("should allow extra properties when catchall is provided", () => {
const Person = co
.map({
name: z.string(),
age: z.number(),
})
.catchall(z.string());
const person = Person.create({ name: "John", age: 20 });
expect(person.name).toEqual("John");
expect(person.age).toEqual(20);
expect(person.extra).toBeUndefined();
person.name = "Jane";
person.age = 28;
person.extra = "extra";
expect(person.name).toEqual("Jane");
expect(person.age).toEqual(28);
expect(person.extra).toEqual("extra");
});
test("CoMap with reference can be created with a shallowly resolved reference", async () => {
const Dog = co.map({
name: z.string(),
breed: z.string(),
});
const Person = co.map({
name: z.string(),
age: z.number(),
pet: Dog,
get friend() {
return Person.optional();
},
});
const group = Group.create();
group.addMember("everyone", "writer");
const pet = Dog.create({ name: "Rex", breed: "Labrador" }, group);
const personA = Person.create(
{
name: "John",
age: 20,
pet,
},
{ owner: group },
);
const userB = await createJazzTestAccount();
const loadedPersonA = await Person.load(personA.id, {
resolve: true,
loadAs: userB,
});
expect(loadedPersonA).not.toBeNull();
assert(loadedPersonA);
const personB = Person.create({
name: "Jane",
age: 28,
pet,
friend: loadedPersonA,
});
expect(personB.friend?.pet.name).toEqual("Rex");
});
});
describe("Mutation", () => {

View File

@@ -60,6 +60,44 @@ describe("co.map and Zod schema compatibility", () => {
expect(map.createdAt).toEqual(undefined);
});
it("should not handle nullable date fields", () => {
const schema = co.map({
updatedAt: z.date().nullable(),
});
expect(() => schema.create({ updatedAt: null })).toThrow(
"Nullable z.date() is not supported",
);
});
it("should handle nullable fields", () => {
const schema = co.map({
updatedAt: z.string().nullable(),
});
const map = schema.create({
updatedAt: null,
});
expect(map.updatedAt).toBeNull();
map.updatedAt = "Test";
expect(map.updatedAt).toEqual("Test");
});
it("should handle nullish fields", () => {
const schema = co.map({
updatedAt: z.string().nullish(),
});
const map = schema.create({});
expect(map.updatedAt).toBeUndefined();
map.updatedAt = null;
expect(map.updatedAt).toBeNull();
map.updatedAt = "Test";
expect(map.updatedAt).toEqual("Test");
});
it("should handle literal fields", async () => {
const schema = co.map({
status: z.literal("active"),

8
pnpm-lock.yaml generated
View File

@@ -1842,19 +1842,19 @@ importers:
specifier: ^0.25.5
version: 0.25.8(effect@3.11.9)
cojson:
specifier: workspace:0.16.0
specifier: workspace:0.16.1
version: link:../cojson
cojson-storage-sqlite:
specifier: workspace:0.16.0
specifier: workspace:0.16.1
version: link:../cojson-storage-sqlite
cojson-transport-ws:
specifier: workspace:0.16.0
specifier: workspace:0.16.1
version: link:../cojson-transport-ws
effect:
specifier: ^3.6.5
version: 3.11.9
jazz-tools:
specifier: workspace:0.16.0
specifier: workspace:0.16.1
version: link:../jazz-tools
ws:
specifier: ^8.14.2

View File

@@ -1,5 +1,12 @@
# jazz-react-tailwind-starter
## 0.0.138
### Patch Changes
- Updated dependencies [c62abef]
- jazz-tools@0.16.1
## 0.0.137
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-react-passkey-auth-starter",
"private": true,
"version": "0.0.137",
"version": "0.0.138",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,12 @@
# svelte-passkey-auth
## 0.0.112
### Patch Changes
- Updated dependencies [c62abef]
- jazz-tools@0.16.1
## 0.0.111
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "svelte-passkey-auth",
"version": "0.0.111",
"version": "0.0.112",
"type": "module",
"private": true,
"scripts": {