jazz-tools
CoValues
type ID
type ID<T> = CojsonInternalTypes.RawCoID & IDMarker<T>
CoValue
s.Can be used with a type argument to refer to a specific
CoValue
type.CoFeed
s that contain binary data, collaborative versions of Blob
s.FileStream.loadAsBlob(id, as, options):
Promise<Blob | undefined>
id: ID<FileStream>,
as: Account,
options: { allowUnfinished: boolean }
FileStream
as a Blob
FileStream.createFromBlob(blob, options):
Promise<FileStream>
blob: File | Blob,
options: { owner: Group | Account, onProgress: (progress: number) => void }
FileStream
from a Blob
or File
import { co, FileStream } from "jazz-tools";
const fileStream = await FileStream.createFromBlob(file, {owner: group})
.id:
ID<FileStream>
FileStream
.toJSON():
{ id: string, _type: "BinaryCoStream", mimeType: string, totalSizeBytes: number, fileName: string, chunks: Uint8Array[], finished: boolean }
FileStream
FileStream.load<B, Depth>(id, as, depth):
Promise<DeeplyLoaded<B, Depth> | undefined>
B extends FileStream
this: CoValueClass<B>,
id: ID<B>,
as: Account,
depth: Depth & DepthsIn<B>
FileStream
FileStream.subscribe<B, Depth>(id, as, depth, listener):
() => void
B extends FileStream
this: CoValueClass<B>,
id: ID<B>,
as: Account,
depth: Depth & DepthsIn<B>,
listener: (value: DeeplyLoaded<B, Depth>) => void
FileStream
, when you have an ID but don't have a FileStream
instance yet.subscribe<B, Depth>(depth, listener):
() => void
B extends FileStream
this: B,
depth: Depth & DepthsIn<B>,
listener: (value: DeeplyLoaded<B, Depth>) => void
FileStream
._owner:
Group | Account
FileStream.fromRaw<V>(raw):
V
V extends CoValue
this: CoValueClass<V>,
raw: RawCoValue
._instanceID:
string
._type:
"BinaryCoStream"
.castAs<Cl>(cl):
InstanceType<Cl>
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
cl: Cl
FileStream.create<S>(options):
S
S extends FileStream
this: CoValueClass<S>,
options: { owner: Group | Account }
.constructor:
NO TYPE
.getChunks(options):
BinaryStreamInfo & { chunks: Uint8Array[], finished: boolean } | undefined
options: { allowUnfinished: boolean }
.isBinaryStreamEnded():
boolean
.start(options):
void
options: BinaryStreamInfo
.push(data):
void
data: Uint8Array
.end():
void
.toBlob(options):
Blob | undefined
options: { allowUnfinished: boolean }
.ensureLoaded<B, Depth>(depth):
Promise<DeeplyLoaded<B, Depth> | undefined>
B extends FileStream
this: B,
depth: Depth & DepthsIn<B>
._loadedAs:
AnonymousJazzAgent | Account
CoList.Of<Item>(item):
CoList
item: Item
CoList
by subclassing CoList.Of(...)
and passing the item schema using co
.class ColorList extends CoList.Of(
co.string
) {}
class AnimalList extends CoList.Of(
co.ref(Animal)
) {}
CoList
as if they were normal items on a plain array, using []
notation, etc.Since
CoList
is a subclass of Array
, you can use all the normal array methods like push
, pop
, splice
, etc.colorList[0];
colorList[3] = "yellow";
colorList.push("Kawazaki Green");
colorList.splice(1, 1);
.id:
ID<CoList<Item>>
CoList
._refs:
{ undefined } & { length: number, [iterator]: NO TYPE }
CoList
's items are a co.ref(...)
, you can use coList._refs[i]
to accessthe
Ref
instead of the potentially loaded/null value.This allows you to always get the ID or load the value manually.
animals._refs[0].id; // => ID<Animal>
animals._refs[0].value;
// => Animal | null
const animal = await animals._refs[0].load();
CoList.create<L>(items, options):
L
L extends CoList<any>
this: CoValueClass<L>,
items: UnCo<L[number]>[],
options: { owner: Group | Account }
The owner (a Group or Account) determines access rights to the CoMap.
The CoList will immediately be persisted and synced to connected peers.
const colours = ColorList.create(
["red", "green", "blue"],
{ owner: me }
);
const animals = AnimalList.create(
[cat, dog, fish],
{ owner: me }
);
CoList.load<L, Depth>(id, as, depth):
Promise<DeeplyLoaded<L, Depth> | undefined>
L extends CoList<any>
this: CoValueClass<L>,
id: ID<L>,
as: Account,
depth: Depth & DepthsIn<L>
CoList
with a given ID, as a given account.depth
specifies if item CoValue references should be loaded as well before resolving.The
DeeplyLoaded
return type guarantees that corresponding referenced CoValues are loaded to the specified depth.You can pass
[]
or for shallowly loading only this CoList, or [itemDepth]
for recursively loading referenced CoValues.Check out the
load
methods on CoMap
/CoList
/CoFeed
/Group
/Account
to see which depth structures are valid to nest.const animalsWithVets =
await ListOfAnimals.load(
"co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
me,
[{ vet: {} }]
);
CoList.subscribe<L, Depth>(id, as, depth, listener):
() => void
L extends CoList<any>
this: CoValueClass<L>,
id: ID<L>,
as: Account,
depth: Depth & DepthsIn<L>,
listener: (value: DeeplyLoaded<L, Depth>) => void
CoList
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.
depth
specifies if item CoValue references should be loaded as well before calling listener
for the first time.The
DeeplyLoaded
return type guarantees that corresponding referenced CoValues are loaded to the specified depth.You can pass
[]
or for shallowly loading only this CoList, or [itemDepth]
for recursively loading referenced CoValues.Check out the
load
methods on CoMap
/CoList
/CoFeed
/Group
/Account
to see which depth structures are valid to nest.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.const unsub = ListOfAnimals.subscribe(
"co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
me,
{ vet: {} },
(animalsWithVets) => console.log(animalsWithVets)
);
.ensureLoaded<L, Depth>(depth):
Promise<DeeplyLoaded<L, Depth> | undefined>
L extends CoList<any>
this: L,
depth: Depth & DepthsIn<L>
CoList
, ensure that items are loaded to the specified depth.Works like
CoList.load()
, but you don't need to pass the ID or the account to load as again..subscribe<L, Depth>(depth, listener):
() => void
L extends CoList<any>
this: L,
depth: Depth & DepthsIn<L>,
listener: (value: DeeplyLoaded<L, Depth>) => void
CoList
, subscribe to updates to the CoList
and ensure that items are loaded to the specified depth.Works like
CoList.subscribe()
, but you don't need to pass the ID or the account to load as again.Returns an unsubscribe function that you should call when you no longer need updates.
._owner:
Group | Account
.toJSON(_key, seenAbove):
any[]
_key: string,
seenAbove: ID<CoValue>[]
.[inspect]():
any[]
CoList.fromRaw<V>(raw):
V & CoList<any>
V extends CoList<any>
this: CoValueClass<V> & CoList,
raw: RawCoList<JsonValue, JsonObject | null>
._raw:
RawCoList<JsonValue, JsonObject | null>
._instanceID:
string
._type:
"CoList"
.castAs<Cl>(cl):
InstanceType<Cl>
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
cl: Cl
CoList[species]:
ArrayConstructor
CoList.isArray(arg):
arg is any[]
arg: any
CoList.from<T>(arrayLike):
T[]
arrayLike: ArrayLike<T>
CoList.from<T, U>(arrayLike, mapfn, thisArg):
U[]
arrayLike: ArrayLike<T>,
mapfn: (v: T, k: number) => U,
thisArg: any
CoList.from<T>(iterable):
T[]
iterable: ArrayLike<T> | Iterable<T>
CoList.from<T, U>(iterable, mapfn, thisArg):
U[]
iterable: ArrayLike<T> | Iterable<T>,
mapfn: (v: T, k: number) => U,
thisArg: any
.constructor:
NO TYPE
._edits:
{ undefined }
._loadedAs:
AnonymousJazzAgent | Account
.push(items):
number
items: Item[]
.unshift(items):
number
items: Item[]
.pop():
Item | undefined
.shift():
Item | undefined
.splice(start, deleteCount, items):
Item[]
start: number,
deleteCount: number,
items: Item[]
.length:
number
.toString():
string
.toLocaleString():
string
.concat(items):
Item[]
items: ConcatArray<Item>[]
This method returns a new array without modifying any existing arrays.
.concat(items):
Item[]
items: ConcatArray<Item> | Item[]
This method returns a new array without modifying any existing arrays.
.join(separator):
string
separator: string
.reverse():
Item[]
This method mutates the array and returns a reference to the same array.
.slice(start, end):
Item[]
start: number,
end: number
For both start and end, a negative index can be used to indicate an offset from the end of the array.
For example, -2 refers to the second to last element of the array.
.sort(compareFn):
this
compareFn: (a: Item, b: Item) => number
This method mutates the array and returns a reference to the same array.
.indexOf(searchElement, fromIndex):
number
searchElement: Item,
fromIndex: number
.lastIndexOf(searchElement, fromIndex):
number
searchElement: Item,
fromIndex: number
.every<S>(predicate, thisArg):
this is S[]
predicate: (value: Item, index: number, array: Item[]) => value is S,
thisArg: any
.every(predicate, thisArg):
boolean
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
.some(predicate, thisArg):
boolean
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
.forEach(callbackfn, thisArg):
void
callbackfn: (value: Item, index: number, array: Item[]) => void,
thisArg: any
.map<U>(callbackfn, thisArg):
U[]
callbackfn: (value: Item, index: number, array: Item[]) => U,
thisArg: any
.filter<S>(predicate, thisArg):
S[]
predicate: (value: Item, index: number, array: Item[]) => value is S,
thisArg: any
.filter(predicate, thisArg):
Item[]
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
.reduce(callbackfn):
Item
callbackfn: (previousValue: Item, currentValue: Item, currentIndex: number, array: Item[]) => Item
.reduce(callbackfn, initialValue):
Item
callbackfn: (previousValue: Item, currentValue: Item, currentIndex: number, array: Item[]) => Item,
initialValue: Item
.reduce<U>(callbackfn, initialValue):
U
callbackfn: (previousValue: U, currentValue: Item, currentIndex: number, array: Item[]) => U,
initialValue: U
.reduceRight(callbackfn):
Item
callbackfn: (previousValue: Item, currentValue: Item, currentIndex: number, array: Item[]) => Item
.reduceRight(callbackfn, initialValue):
Item
callbackfn: (previousValue: Item, currentValue: Item, currentIndex: number, array: Item[]) => Item,
initialValue: Item
.reduceRight<U>(callbackfn, initialValue):
U
callbackfn: (previousValue: U, currentValue: Item, currentIndex: number, array: Item[]) => U,
initialValue: U
.find<S>(predicate, thisArg):
S | undefined
predicate: (value: Item, index: number, obj: Item[]) => value is S,
thisArg: any
otherwise.
.find(predicate, thisArg):
Item | undefined
predicate: (value: Item, index: number, obj: Item[]) => unknown,
thisArg: any
.findIndex(predicate, thisArg):
number
predicate: (value: Item, index: number, obj: Item[]) => unknown,
thisArg: any
otherwise.
.fill(value, start, end):
this
value: Item,
start: number,
end: number
start
to end
index to a static value
and returns the modified array.copyWithin(target, start, end):
this
target: number,
start: number,
end: number
to the same array starting at position target
.entries():
IterableIterator<[number, Item]>
.keys():
IterableIterator<number>
.values():
IterableIterator<Item>
.includes(searchElement, fromIndex):
boolean
searchElement: Item,
fromIndex: number
.flatMap<U, This>(callback, thisArg):
U[]
callback: (this: This, value: Item, index: number, array: Item[]) => TODO type typeOperator | U,
thisArg: This
a new array.
This is identical to a map followed by flat with depth 1.
.flat<A, D>(depth):
FlatArray<A, D>[]
D extends number
this: A,
depth: D
specified depth.
.at(index):
Item | undefined
index: number
.findLast<S>(predicate, thisArg):
S | undefined
predicate: (value: Item, index: number, array: Item[]) => value is S,
thisArg: any
otherwise.
.findLast(predicate, thisArg):
Item | undefined
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
.findLastIndex(predicate, thisArg):
number
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
otherwise.
.toReversed():
Item[]
.toSorted(compareFn):
Item[]
compareFn: (a: Item, b: Item) => number
.toSpliced(start, deleteCount, items):
Item[]
start: number,
deleteCount: number,
items: Item[]
.toSpliced(start, deleteCount):
Item[]
start: number,
deleteCount: number
.with(index, value):
Item[]
index: number,
value: Item
given value. If the index is negative, then it replaces from the end
of the array.
.[iterator]():
IterableIterator<Item>
[unscopables]:
{ length: boolean, toString: NO TYPE, toLocaleString: NO TYPE, pop: NO TYPE, push: NO TYPE, concat: NO TYPE, join: NO TYPE, reverse: NO TYPE, shift: NO TYPE, slice: NO TYPE, sort: NO TYPE, splice: NO TYPE, unshift: NO TYPE, indexOf: NO TYPE, lastIndexOf: NO TYPE, every: NO TYPE, some: NO TYPE, forEach: NO TYPE, map: NO TYPE, filter: NO TYPE, reduce: NO TYPE, reduceRight: NO TYPE, find: NO TYPE, findIndex: NO TYPE, fill: NO TYPE, copyWithin: NO TYPE, entries: NO TYPE, keys: NO TYPE, values: NO TYPE, includes: NO TYPE, flatMap: NO TYPE, flat: NO TYPE, at: NO TYPE, findLast: NO TYPE, findLastIndex: NO TYPE, toReversed: NO TYPE, toSorted: NO TYPE, toSpliced: NO TYPE, with: NO TYPE, [iterator]: NO TYPE, [unscopables]: boolean }
when they will be absent when used in a 'with' statement.
CoMap
and assigning field schemas with co
.Optional
co.ref(...)
fields must be marked with { optional: true }
.import { co, CoMap } from "jazz-tools";
class Person extends CoMap {
name = co.string;
age = co.number;
pet = co.ref(Animal);
car = co.ref(Car, { optional: true });
}
CoMap.Record<Value>(value):
RecordLikeCoMap
value: IfCo<Value, Value>
CoMap.Record(...)
and passing the value schema using co
. Keys are always string
.import { co, CoMap } from "jazz-tools";
class ColorToFruitMap extends CoMap.Record(
co.ref(Fruit)
) {}
// assume we have map: ColorToFruitMap
// and strawberry: Fruit
map["red"] = strawberry;
CoMap
(using co
) as if they were normal properties on a plain object, using dot notation, Object.keys()
, etc.person.name;
person["age"];
person.age = 42;
person.pet?.name;
Object.keys(person);
// => ["name", "age", "pet"]
.id:
ID<CoMap>
CoMap
._refs:
{[Key in string]: IfCo<this[Key], RefIfCoValue<this[Key]>>}
prop
is a co.ref(...)
, you can use coMaps._refs.prop
to accessthe
Ref
instead of the potentially loaded/null value.This allows you to always get the ID or load the value manually.
person._refs.pet.id; // => ID<Animal>
person._refs.pet.value;
// => Animal | null
const pet = await person._refs.pet.load();
.toJSON(_key, seenAbove):
any[]
_key: string,
seenAbove: ID<CoValue>[]
CoMap
CoMap.create<M>(init, options):
M
M extends CoMap
this: CoValueClass<M>,
init: Simplify<CoMapInit<M>>,
options: { owner: Group | Account, unique: JsonValue }
The owner (a Group or Account) determines access rights to the CoMap.
The CoMap will immediately be persisted and synced to connected peers.
const person = Person.create({
name: "Alice",
age: 42,
pet: cat,
}, { owner: friendGroup });
CoMap.load<M, Depth>(id, as, depth):
Promise<DeeplyLoaded<M, Depth> | undefined>
M extends CoMap
this: CoValueClass<M>,
id: ID<M>,
as: Account,
depth: Depth & DepthsIn<M>
CoMap
with a given ID, as a given account.depth
specifies which (if any) fields that reference other CoValues to load as well before resolving.The
DeeplyLoaded
return type guarantees that corresponding referenced CoValues are loaded to the specified depth.You can pass
[]
or {}
for shallowly loading only this CoMap, or { fieldA: depthA, fieldB: depthB }
for recursively loading referenced CoValues.Check out the
load
methods on CoMap
/CoList
/CoFeed
/Group
/Account
to see which depth structures are valid to nest.const person = await Person.load(
"co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
me,
{ pet: {} }
);
CoMap.subscribe<M, Depth>(id, as, depth, listener):
() => void
M extends CoMap
this: CoValueClass<M>,
id: ID<M>,
as: Account,
depth: Depth & DepthsIn<M>,
listener: (value: DeeplyLoaded<M, Depth>) => void
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.
depth
specifies which (if any) fields that reference other CoValues to load as well before calling listener
for the first time.The
DeeplyLoaded
return type guarantees that corresponding referenced CoValues are loaded to the specified depth.You can pass
[]
or {}
for shallowly loading only this CoMap, or { fieldA: depthA, fieldB: depthB }
for recursively loading referenced CoValues.Check out the
load
methods on CoMap
/CoList
/CoFeed
/Group
/Account
to see which depth structures are valid to nest.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.const unsub = Person.subscribe(
"co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
me,
{ pet: {} },
(person) => console.log(person)
);
.ensureLoaded<M, Depth>(depth):
Promise<DeeplyLoaded<M, Depth> | undefined>
M extends CoMap
this: M,
depth: Depth & DepthsIn<M>
CoMap
, ensure that the specified fields are loaded to the specified depth.Works like
CoMap.load()
, but you don't need to pass the ID or the account to load as again..subscribe<M, Depth>(depth, listener):
() => void
M extends CoMap
this: M,
depth: Depth & DepthsIn<M>,
listener: (value: DeeplyLoaded<M, Depth>) => void
CoMap
, subscribe to updates to the CoMap
and ensure that the specified fields are loaded to the specified depth.Works like
CoMap.subscribe()
, but you don't need to pass the ID or the account to load as again.Returns an unsubscribe function that you should call when you no longer need updates.
._edits:
{[Key in string]: IfCo<this[Key], LastAndAllCoMapEdits<this[Key]>>}
._owner:
Group | Account
.[inspect]():
any[]
CoMap.fromRaw<V>(raw):
V
V extends CoValue
this: CoValueClass<V>,
raw: RawCoValue
._raw:
RawCoMap<{ undefined }, JsonObject | null>
._instanceID:
string
._type:
"CoMap"
.castAs<Cl>(cl):
InstanceType<Cl>
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
cl: Cl
CoMap.findUnique<M>(unique, ownerID, as):
ID<M>
M extends CoMap
this: CoValueClass<M>,
unique: JsonValue,
ownerID: ID<Group> | ID<Account>,
as: AnonymousJazzAgent | Group | Account
.applyDiff<N>(newValues):
CoMap
N extends Partial<CoMapInit<CoMap>>
newValues: N
._loadedAs:
AnonymousJazzAgent | Account
CoFeed.Of<Item>(item):
CoFeed
item: IfCo<Item, Item>
CoFeed
by subclassing CoFeed.Of(...)
and passing the item schema using a co
primitive or a co.ref
.class ColorFeed extends CoFeed.Of(co.string) {}
class AnimalFeed extends CoFeed.Of(co.ref(Animal)) {}
CoList
s, but with a few key differences:- They are append-only
- They consist of several internal append-only logs, one per account session (tab, device, app instance, etc.)
- They expose those as a per-account aggregated view (default) or a precise per-session view
favDog.push("Poodle");
favDog.push("Schnowzer");
.id:
ID<CoFeed<Item>>
CoFeed
.byMe:
CoFeedEntry<Item> | undefined
CoFeed
.perSession:
{ undefined }
CoFeed
.inCurrentSession:
CoFeedEntry<Item> | undefined
CoFeed
This is a shortcut for
this.perSession
where the session ID is the current session ID..push(items):
void
items: Item[]
CoFeed
Items are appended to the current session's log. Each session (tab, device, app instance)
maintains its own append-only log, which is then aggregated into the per-account view.
// Adds items to current session's log
feed.push("item1", "item2");
// View items from current session
console.log(feed.inCurrentSession);
// View aggregated items from all sessions for current account
console.log(feed.byMe);
CoFeed.create<S>(init, options):
S
S extends CoFeed<any>
this: CoValueClass<S>,
init: TODO type conditional,
options: { owner: Group | Account }
CoFeed
CoFeed.load<S, Depth>(id, as, depth):
Promise<DeeplyLoaded<S, Depth> | undefined>
S extends CoFeed<any>
this: CoValueClass<S>,
id: ID<S>,
as: Account,
depth: Depth & DepthsIn<S>
CoFeed
CoFeed.subscribe<S, Depth>(id, as, depth, listener):
() => void
S extends CoFeed<any>
this: CoValueClass<S>,
id: ID<S>,
as: Account,
depth: Depth & DepthsIn<S>,
listener: (value: DeeplyLoaded<S, Depth>) => void
CoFeed
, when you have an ID but don't have a CoFeed
instance yet.ensureLoaded<S, Depth>(depth):
Promise<DeeplyLoaded<S, Depth> | undefined>
S extends CoFeed<any>
this: S,
depth: Depth & DepthsIn<S>
CoFeed
is loaded to the specified depth.subscribe<S, Depth>(depth, listener):
() => void
S extends CoFeed<any>
this: S,
depth: Depth & DepthsIn<S>,
listener: (value: DeeplyLoaded<S, Depth>) => void
CoFeed
No need to provide an ID or Account since they're already part of the instance.
._owner:
Group | Account
CoFeed.fromRaw<V>(raw):
V
V extends CoValue
this: CoValueClass<V>,
raw: RawCoValue
._raw:
RawCoStream<JsonValue, JsonObject | null>
._instanceID:
string
._type:
"CoStream"
.castAs<Cl>(cl):
InstanceType<Cl>
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
cl: Cl
.constructor:
NO TYPE
.pushItem(item):
void
item: Item
.toJSON():
{ id: string, _type: "CoStream", in: { undefined } }
CoFeed
._loadedAs:
AnonymousJazzAgent | Account
SchemaUnion.Of(...)
and passing a discriminator function that determines which concrete type to use based on the raw data.import { SchemaUnion, CoMap } from "jazz-tools";
class BaseWidget extends CoMap {
type = co.string;
}
class ButtonWidget extends BaseWidget {
type = co.literal("button");
label = co.string;
}
class SliderWidget extends BaseWidget {
type = co.literal("slider");
min = co.number;
max = co.number;
}
const WidgetUnion = SchemaUnion.Of<BaseWidget>((raw) => {
switch (raw.get("type")) {
case "button": return ButtonWidget;
case "slider": return SliderWidget;
default: throw new Error("Unknown widget type");
}
});
SchemaUnion.Of<V>(discriminator):
CoValueClass<V> & SchemaUnion
V extends CoValue
discriminator: (raw: V["_raw"]) => CoValueClass<V> & CoValueFromRaw<V>
The discriminator function receives the raw data and should return the appropriate concrete class to use for that data.
When loading a SchemaUnion, the correct subclass will be instantiated based on the discriminator.
const WidgetUnion = SchemaUnion.Of<BaseWidget>((raw) => {
switch (raw.get("type")) {
case "button": return ButtonWidget;
case "slider": return SliderWidget;
default: throw new Error("Unknown widget type");
}
});
const widget = await loadCoValue(WidgetUnion, id, me, {});
// You can narrow the returned instance to a subclass by using `instanceof`
if (widget instanceof ButtonWidget) {
console.log(widget.label);
} else if (widget instanceof SliderWidget) {
console.log(widget.min, widget.max);
}
.id:
ID<SchemaUnion>
._owner:
Group | Account
.toJSON():
any[] | string | object
.[inspect]():
any[] | string | object
._raw:
RawCoValue
._instanceID:
string
._type:
string
.castAs<Cl>(cl):
InstanceType<Cl>
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
cl: Cl
.constructor:
NO TYPE
._loadedAs:
AnonymousJazzAgent | Account
Identity & Permissions
.id:
ID<Account>
Account.load<A, Depth>(id, as, depth):
Promise<DeeplyLoaded<A, Depth> | undefined>
A extends Account
this: CoValueClass<A>,
id: ID<A>,
as: Account,
depth: Depth & DepthsIn<A>
Account.subscribe<A, Depth>(id, as, depth, listener):
() => void
A extends Account
this: CoValueClass<A>,
id: ID<A>,
as: Account,
depth: Depth & DepthsIn<A>,
listener: (value: DeeplyLoaded<A, Depth>) => void
.ensureLoaded<A, Depth>(depth):
Promise<DeeplyLoaded<A, Depth> | undefined>
A extends Account
this: A,
depth: Depth & DepthsIn<A>
.subscribe<A, Depth>(depth, listener):
() => void
A extends Account
this: A,
depth: Depth & DepthsIn<A>,
listener: (value: DeeplyLoaded<A, Depth>) => void
._owner:
Account
.toJSON():
any[] | object
.[inspect]():
any[] | object
Account.fromRaw<V>(raw):
V
V extends CoValue
this: CoValueClass<V>,
raw: RawCoValue
._raw:
RawControlledAccount<AccountMeta> | RawAccount<AccountMeta>
._instanceID:
string
._type:
"Account"
.castAs<Cl>(cl):
InstanceType<Cl>
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
cl: Cl
Account._schema:
any
Account.create<A>(options):
Promise<A>
A extends Account
this: CoValueClass<A> & Account,
options: { creationProps: { name: string }, crypto: CryptoProvider<any>, initialAgentSecret: TODO type templateLiteral, peersToLoadFrom: Peer[] }
Account.createAs<A>(as, options):
Promise<A>
A extends Account
this: CoValueClass<A> & Account,
as: Account,
options: { creationProps: { name: string } }
Account.fromNode<A>(node):
A
A extends Account
this: CoValueClass<A>,
node: LocalNode
.constructor:
NO TYPE
._schema:
{ profile: Schema, root: Schema }
._loadedAs:
AnonymousJazzAgent | Account
.profile:
Profile | null
.root:
CoMap | null
._refs:
{ profile: Ref<Profile> | undefined, root: Ref<CoMap> | undefined }
.isMe:
boolean
.sessionID:
TODO type templateLiteral | TODO type templateLiteral | undefined
.myRole():
"admin" | undefined
.acceptInvite<V>(valueID, inviteSecret, coValueClass):
Promise<(TODO type conditional) | undefined>
V extends CoValue
valueID: ID<V>,
inviteSecret: TODO type templateLiteral,
coValueClass: CoValueClass<V>
.migrate(creationProps):
Promise<void> | void
this: Account,
creationProps: { name: string }
.id:
ID<Group>
Group.load<G, Depth>(id, as, depth):
Promise<DeeplyLoaded<G, Depth> | undefined>
G extends Group
this: CoValueClass<G>,
id: ID<G>,
as: Account,
depth: Depth & DepthsIn<G>
Group.subscribe<G, Depth>(id, as, depth, listener):
() => void
G extends Group
this: CoValueClass<G>,
id: ID<G>,
as: Account,
depth: Depth & DepthsIn<G>,
listener: (value: DeeplyLoaded<G, Depth>) => void
.ensureLoaded<G, Depth>(depth):
Promise<DeeplyLoaded<G, Depth> | undefined>
G extends Group
this: G,
depth: Depth & DepthsIn<G>
.subscribe<G, Depth>(depth, listener):
() => void
G extends Group
this: G,
depth: Depth & DepthsIn<G>,
listener: (value: DeeplyLoaded<G, Depth>) => void
._owner:
Group | Account
.toJSON():
any[] | string | object
.[inspect]():
any[] | string | object
Group.fromRaw<V>(raw):
V
V extends CoValue
this: CoValueClass<V>,
raw: RawCoValue
._raw:
RawGroup<JsonObject | null>
._instanceID:
string
._type:
"Group"
.castAs<Cl>(cl):
InstanceType<Cl>
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
cl: Cl
Group._schema:
any
Group.create<G>(options):
G
G extends Group
this: CoValueClass<G>,
options: { owner: Account }
.constructor:
NO TYPE
._schema:
{ profile: Schema, root: Schema, [MembersSym]: RefEncoded<Account> }
.profile:
Profile | null
.root:
CoMap | null
._refs:
{ profile: Ref<Profile> | undefined, root: Ref<CoMap> | undefined }
.myRole():
Role | undefined
.addMember(member, role):
Group
member: Account | "everyone",
role: Role
.removeMember(member):
Group
member: Account | "everyone"
.members:
{ id: ID<this[MembersSym]> | "everyone", role: Role | undefined, ref: Ref<NonNullable<this[MembersSym]>> | undefined, account: NO TYPE }[]
.extend(parent):
Group
parent: Group
[MembersSym]:
Account | null
._loadedAs:
AnonymousJazzAgent | Account
Profile.Record<Value>(value):
RecordLikeCoMap
value: IfCo<Value, Value>
CoMap.Record(...)
and passing the value schema using co
. Keys are always string
.import { co, CoMap } from "jazz-tools";
class ColorToFruitMap extends CoMap.Record(
co.ref(Fruit)
) {}
// assume we have map: ColorToFruitMap
// and strawberry: Fruit
map["red"] = strawberry;
.id:
ID<Profile>
CoMap
._refs:
{[Key in string]: IfCo<this[Key], RefIfCoValue<this[Key]>>}
prop
is a co.ref(...)
, you can use coMaps._refs.prop
to accessthe
Ref
instead of the potentially loaded/null value.This allows you to always get the ID or load the value manually.
person._refs.pet.id; // => ID<Animal>
person._refs.pet.value;
// => Animal | null
const pet = await person._refs.pet.load();
.toJSON(_key, seenAbove):
any[]
_key: string,
seenAbove: ID<CoValue>[]
CoMap
Profile.create<M>(init, options):
M
M extends CoMap
this: CoValueClass<M>,
init: Simplify<CoMapInit<M>>,
options: { owner: Group | Account, unique: JsonValue }
The owner (a Group or Account) determines access rights to the CoMap.
The CoMap will immediately be persisted and synced to connected peers.
const person = Person.create({
name: "Alice",
age: 42,
pet: cat,
}, { owner: friendGroup });
Profile.load<M, Depth>(id, as, depth):
Promise<DeeplyLoaded<M, Depth> | undefined>
M extends CoMap
this: CoValueClass<M>,
id: ID<M>,
as: Account,
depth: Depth & DepthsIn<M>
CoMap
with a given ID, as a given account.depth
specifies which (if any) fields that reference other CoValues to load as well before resolving.The
DeeplyLoaded
return type guarantees that corresponding referenced CoValues are loaded to the specified depth.You can pass
[]
or {}
for shallowly loading only this CoMap, or { fieldA: depthA, fieldB: depthB }
for recursively loading referenced CoValues.Check out the
load
methods on CoMap
/CoList
/CoFeed
/Group
/Account
to see which depth structures are valid to nest.const person = await Person.load(
"co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
me,
{ pet: {} }
);
Profile.subscribe<M, Depth>(id, as, depth, listener):
() => void
M extends CoMap
this: CoValueClass<M>,
id: ID<M>,
as: Account,
depth: Depth & DepthsIn<M>,
listener: (value: DeeplyLoaded<M, Depth>) => void
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.
depth
specifies which (if any) fields that reference other CoValues to load as well before calling listener
for the first time.The
DeeplyLoaded
return type guarantees that corresponding referenced CoValues are loaded to the specified depth.You can pass
[]
or {}
for shallowly loading only this CoMap, or { fieldA: depthA, fieldB: depthB }
for recursively loading referenced CoValues.Check out the
load
methods on CoMap
/CoList
/CoFeed
/Group
/Account
to see which depth structures are valid to nest.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.const unsub = Person.subscribe(
"co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
me,
{ pet: {} },
(person) => console.log(person)
);
.ensureLoaded<M, Depth>(depth):
Promise<DeeplyLoaded<M, Depth> | undefined>
M extends CoMap
this: M,
depth: Depth & DepthsIn<M>
CoMap
, ensure that the specified fields are loaded to the specified depth.Works like
CoMap.load()
, but you don't need to pass the ID or the account to load as again..subscribe<M, Depth>(depth, listener):
() => void
M extends CoMap
this: M,
depth: Depth & DepthsIn<M>,
listener: (value: DeeplyLoaded<M, Depth>) => void
CoMap
, subscribe to updates to the CoMap
and ensure that the specified fields are loaded to the specified depth.Works like
CoMap.subscribe()
, but you don't need to pass the ID or the account to load as again.Returns an unsubscribe function that you should call when you no longer need updates.
._edits:
{[Key in string]: IfCo<this[Key], LastAndAllCoMapEdits<this[Key]>>}
._owner:
Group | Account
.[inspect]():
any[]
Profile.fromRaw<V>(raw):
V
V extends CoValue
this: CoValueClass<V>,
raw: RawCoValue
._raw:
RawCoMap<{ undefined }, JsonObject | null>
._instanceID:
string
._type:
"CoMap"
.castAs<Cl>(cl):
InstanceType<Cl>
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
cl: Cl
Profile.findUnique<M>(unique, ownerID, as):
ID<M>
M extends CoMap
this: CoValueClass<M>,
unique: JsonValue,
ownerID: ID<Group> | ID<Account>,
as: AnonymousJazzAgent | Group | Account
.name:
co<string>
.applyDiff<N>(newValues):
Profile
N extends Partial<CoMapInit<Profile>>
newValues: N
._loadedAs:
AnonymousJazzAgent | Account
isControlledAccount(account):
account is Account & { isMe: true, sessionID: TODO type templateLiteral | TODO type templateLiteral, _raw: RawControlledAccount<AccountMeta> }
account: Account
Schema definition
Encoders reflection
co reflection
type co
type co<T> = T & CoMarker | T
Abstract interfaces
.id:
ID<CoValue>
._owner:
Group | Account
.toJSON(key, seenAbove):
any[] | string | object
key: string,
seenAbove: ID<CoValue>[]
.[inspect]():
any
._raw:
RawCoValue
._type:
string
Value extends CoValue
Media
ImageDefinition.Record<Value>(value):
RecordLikeCoMap
value: IfCo<Value, Value>
CoMap.Record(...)
and passing the value schema using co
. Keys are always string
.import { co, CoMap } from "jazz-tools";
class ColorToFruitMap extends CoMap.Record(
co.ref(Fruit)
) {}
// assume we have map: ColorToFruitMap
// and strawberry: Fruit
map["red"] = strawberry;
.id:
ID<ImageDefinition>
CoMap
._refs:
{[Key in string]: IfCo<this[Key], RefIfCoValue<this[Key]>>}
prop
is a co.ref(...)
, you can use coMaps._refs.prop
to accessthe
Ref
instead of the potentially loaded/null value.This allows you to always get the ID or load the value manually.
person._refs.pet.id; // => ID<Animal>
person._refs.pet.value;
// => Animal | null
const pet = await person._refs.pet.load();
.toJSON(_key, seenAbove):
any[]
_key: string,
seenAbove: ID<CoValue>[]
CoMap
ImageDefinition.create<M>(init, options):
M
M extends CoMap
this: CoValueClass<M>,
init: Simplify<CoMapInit<M>>,
options: { owner: Group | Account, unique: JsonValue }
The owner (a Group or Account) determines access rights to the CoMap.
The CoMap will immediately be persisted and synced to connected peers.
const person = Person.create({
name: "Alice",
age: 42,
pet: cat,
}, { owner: friendGroup });
ImageDefinition.load<M, Depth>(id, as, depth):
Promise<DeeplyLoaded<M, Depth> | undefined>
M extends CoMap
this: CoValueClass<M>,
id: ID<M>,
as: Account,
depth: Depth & DepthsIn<M>
CoMap
with a given ID, as a given account.depth
specifies which (if any) fields that reference other CoValues to load as well before resolving.The
DeeplyLoaded
return type guarantees that corresponding referenced CoValues are loaded to the specified depth.You can pass
[]
or {}
for shallowly loading only this CoMap, or { fieldA: depthA, fieldB: depthB }
for recursively loading referenced CoValues.Check out the
load
methods on CoMap
/CoList
/CoFeed
/Group
/Account
to see which depth structures are valid to nest.const person = await Person.load(
"co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
me,
{ pet: {} }
);
ImageDefinition.subscribe<M, Depth>(id, as, depth, listener):
() => void
M extends CoMap
this: CoValueClass<M>,
id: ID<M>,
as: Account,
depth: Depth & DepthsIn<M>,
listener: (value: DeeplyLoaded<M, Depth>) => void
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.
depth
specifies which (if any) fields that reference other CoValues to load as well before calling listener
for the first time.The
DeeplyLoaded
return type guarantees that corresponding referenced CoValues are loaded to the specified depth.You can pass
[]
or {}
for shallowly loading only this CoMap, or { fieldA: depthA, fieldB: depthB }
for recursively loading referenced CoValues.Check out the
load
methods on CoMap
/CoList
/CoFeed
/Group
/Account
to see which depth structures are valid to nest.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.const unsub = Person.subscribe(
"co_zdsMhHtfG6VNKt7RqPUPvUtN2Ax",
me,
{ pet: {} },
(person) => console.log(person)
);
.ensureLoaded<M, Depth>(depth):
Promise<DeeplyLoaded<M, Depth> | undefined>
M extends CoMap
this: M,
depth: Depth & DepthsIn<M>
CoMap
, ensure that the specified fields are loaded to the specified depth.Works like
CoMap.load()
, but you don't need to pass the ID or the account to load as again..subscribe<M, Depth>(depth, listener):
() => void
M extends CoMap
this: M,
depth: Depth & DepthsIn<M>,
listener: (value: DeeplyLoaded<M, Depth>) => void
CoMap
, subscribe to updates to the CoMap
and ensure that the specified fields are loaded to the specified depth.Works like
CoMap.subscribe()
, but you don't need to pass the ID or the account to load as again.Returns an unsubscribe function that you should call when you no longer need updates.
._edits:
{[Key in string]: IfCo<this[Key], LastAndAllCoMapEdits<this[Key]>>}
._owner:
Group | Account
.[inspect]():
any[]
ImageDefinition.fromRaw<V>(raw):
V
V extends CoValue
this: CoValueClass<V>,
raw: RawCoValue
._raw:
RawCoMap<{ undefined }, JsonObject | null>
._instanceID:
string
._type:
"CoMap"
.castAs<Cl>(cl):
InstanceType<Cl>
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
cl: Cl
ImageDefinition.findUnique<M>(unique, ownerID, as):
ID<M>
M extends CoMap
this: CoValueClass<M>,
unique: JsonValue,
ownerID: ID<Group> | ID<Account>,
as: AnonymousJazzAgent | Group | Account
.originalSize:
co<[number, number]>
.highestResAvailable(options):
{ res: TODO type templateLiteral, stream: FileStream } | undefined
options: { maxWidth: number }
[ItemsSym]:
co<FileStream | null>
.applyDiff<N>(newValues):
ImageDefinition
N extends Partial<CoMapInit<ImageDefinition>>
newValues: N
._loadedAs:
AnonymousJazzAgent | Account
.placeholderDataURL:
co<string>
Other
MAX_RECOMMENDED_TX_SIZE intrinsic
type AgentID
type AgentIDundefined = TODO type templateLiteral
type CoValueUniqueness
type CoValueUniquenessundefined = { uniqueness: JsonValue, createdAt: null | TODO type templateLiteral }
type InviteSecret
type InviteSecretundefined = TODO type templateLiteral
type SessionID
type SessionIDundefined = TODO type templateLiteral
type SyncMessage
type SyncMessageundefined = DoneMessage | NewContentMessage | KnownStateMessage | LoadMessage
BinaryCoStream
CoStream
type AccountClass
type AccountClass<Acc extends Account> = CoValueClass<Acc> & { fromNode: Account["fromNode"] }
type CoMapInit
type CoMapInit<Map extends object> = {[Key in CoKeys<Map>]: ForceRequiredRef<Map[Key]>} & {[Key in CoKeys<Map>]: ForceRequiredRef<Map[Key]>}
type DeeplyLoaded
type DeeplyLoaded<V, Depth, DepthLimit extends number, CurrentDepth extends number[]> = TODO type conditional
type DepthsIn
type DepthsIn<V, DepthLimit extends number, CurrentDepth extends number[]> = never[] | (TODO type conditional)
createCoValueObservable<V, Depth>():
{ getCurrentValue: () => DeeplyLoaded<V, Depth> | undefined, subscribe: (cls: CoValueClass<V>, id: ID<V>, as: AnonymousJazzAgent | Account, depth: Depth & DepthsIn<V>, listener: () => void, onUnavailable: () => void) => () => void }
loadCoValue<V, Depth>(cls, id, as, depth):
Promise<DeeplyLoaded<V, Depth> | undefined>
cls: CoValueClass<V>,
id: ID<V>,
as: AnonymousJazzAgent | Account,
depth: Depth & DepthsIn<V>
subscribeToCoValue<V, Depth>(cls, id, as, depth, listener, onUnavailable):
() => void
cls: CoValueClass<V>,
id: ID<V>,
as: AnonymousJazzAgent | Account,
depth: Depth & DepthsIn<V>,
listener: (value: DeeplyLoaded<V, Depth>) => void,
onUnavailable: () => void
createAnonymousJazzContext({ peersToLoadFrom, crypto }):
Promise<JazzContextWithAgent>
{ peersToLoadFrom: Peer[], crypto: CryptoProvider<any> }
createJazzContext<Acc>(__namedParameters):
Promise<JazzContextWithAccount<Acc>>
ContextParamsWithAuth<Acc>
createJazzContext(__namedParameters):
Promise<JazzContextWithAgent>
BaseContextParams
createJazzContext<Acc>(options):
Promise<JazzContext<Acc>>
options: ContextParamsWithAuth<Acc> | BaseContextParams
ephemeralCredentialsAuth():
AuthMethod
fixedCredentialsAuth(credentials):
AuthMethod
credentials: { accountID: ID<Account>, secret: TODO type templateLiteral }
randomSessionProvider(accountID, crypto):
Promise<{ sessionID: TODO type templateLiteral | TODO type templateLiteral, sessionDone: () => void }>
accountID: ID<Account>,
crypto: CryptoProvider<any>
type AuthResult
type AuthResultundefined = { type: "new", creationProps: { name: string }, saveCredentials: (credentials: Credentials) => Promise<void>, onSuccess: () => void, onError: (error: Error | string) => void, logOut: () => void, initialSecret: AgentSecret } | { type: "existing", credentials: Credentials, onSuccess: () => void, onError: (error: Error | string) => void, logOut: () => void, saveCredentials: (credentials: Credentials) => Promise<void> }
type Credentials
type Credentialsundefined = { accountID: ID<Account>, secret: AgentSecret }