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.BinaryCoStream.loadAsBlob(id, options):
Promise<Blob | undefined>
function fn(...args: [
id: ID<FileStream>,
options: { allowUnfinished: boolean, loadAs: AnonymousJazzAgent | Account }
]) {}
FileStream
as a Blob
BinaryCoStream.createFromBlob(blob, options):
Promise<FileStream>
function fn(...args: [
blob: File | Blob,
options: { owner: Group | Account, onProgress: (progress: number) => void } | Group | Account
]) {}
FileStream
from a Blob
or File
import { co, FileStream } from "jazz-tools";
const fileStream = await FileStream.createFromBlob(file, {owner: group})
.id:
class X {
prop:
ID<FileStream>
FileStream
.toJSON():
{ id: string, _type: "BinaryCoStream", mimeType: string, totalSizeBytes: number, fileName: string, chunks: Uint8Array<ArrayBufferLike>[], finished: boolean }
FileStream
BinaryCoStream.create<S>(options):
S
class Thing<
S extends FileStream
]> {}
function fn(...args: [
this: CoValueClass<S>,
options: { owner: Group | Account } | Group | Account
]) {}
FileStream
instance.// Create owned by an account
const stream = FileStream.create({ owner: myAccount });
// Create owned by a group
const stream = FileStream.create({ owner: teamGroup });
// Create with implicit owner
const stream = FileStream.create(myAccount);
BinaryCoStream.load<C>(id, options):
Promise<C | null>
class Thing<
C extends FileStream
]> {}
function fn(...args: [
this: CoValueClass<C>,
id: ID<C>,
options: { loadAs: AnonymousJazzAgent | Account }
]) {}
FileStream
BinaryCoStream.subscribe<C>(id, options, listener):
() => void
class Thing<
C extends FileStream
]> {}
function fn(...args: [
this: CoValueClass<C>,
id: ID<C>,
options: { loadAs: AnonymousJazzAgent | Account },
listener: (value: C) => void
]) {}
FileStream
, when you have an ID but don't have a FileStream
instance yet.subscribe<B>(listener):
() => void
class Thing<
B extends FileStream
]> {}
function fn(...args: [
this: B,
listener: (value: B) => void
]) {}
FileStream
.waitForSync(options):
Promise<unknown[]>
function fn(...args: [
options: { timeout: number }
]) {}
FileStream
to be uploaded to the other peers.._owner:
class X {
prop:
Group | Account
BinaryCoStream.fromRaw<V>(raw):
V
class Thing<
V extends CoValue
]> {}
function fn(...args: [
this: CoValueClass<V>,
raw: RawCoValue
]) {}
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
"BinaryCoStream"
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
.constructor:
class X {
prop:
NO TYPE
.getChunks(options):
BinaryStreamInfo & { chunks: Uint8Array<ArrayBufferLike>[], finished: boolean } | undefined
function fn(...args: [
options: { allowUnfinished: boolean }
]) {}
.isBinaryStreamEnded():
boolean
.start(options):
void
function fn(...args: [
options: BinaryStreamInfo
]) {}
.push(data):
void
function fn(...args: [
data: Uint8Array
]) {}
.end():
void
.toBlob(options):
Blob | undefined
function fn(...args: [
options: { allowUnfinished: boolean }
]) {}
CoFeed.Of<Item>(item):
CoFeed
function fn(...args: [
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:
class X {
prop:
ID<CoFeed<Item>>
CoFeed
.byMe:
class X {
prop:
CoFeedEntry<Item> | undefined
CoFeed
.perSession:
class X {
prop:
{ undefined }
CoFeed
.inCurrentSession:
class X {
prop:
CoFeedEntry<Item> | undefined
CoFeed
This is a shortcut for
this.perSession
where the session ID is the current session ID..push(items):
void
function fn(...args: [
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
class Thing<
S extends CoFeed<any>
]> {}
function fn(...args: [
this: CoValueClass<S>,
init: TODO type conditional,
options: { owner: Group | Account } | Group | Account
]) {}
CoFeed
CoFeed.load<F, R>(id, options):
Promise<Resolved<F, R> | null>
class Thing<
F extends CoFeed<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<F>,
id: ID<F>,
options: { resolve: RefsToResolveStrict<F, R>, loadAs: AnonymousJazzAgent | Account }
]) {}
CoFeed
CoFeed.subscribe<F, R>(id, listener):
() => void
class Thing<
F extends CoFeed<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<F>,
id: ID<F>,
listener: (value: Resolved<F, R>, unsubscribe: () => void) => void
]) {}
CoFeed
, when you have an ID but don't have a CoFeed
instance yetCoFeed.subscribe<F, R>(id, options, listener):
() => void
class Thing<
F extends CoFeed<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<F>,
id: ID<F>,
options: SubscribeListenerOptions<F, R>,
listener: (value: Resolved<F, R>, unsubscribe: () => void) => void
]) {}
CoFeed
, when you have an ID but don't have a CoFeed
instance yet.ensureLoaded<F, R>(options):
Promise<Resolved<F, R>>
class Thing<
F extends CoFeed<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: F,
options: { resolve: RefsToResolveStrict<F, R> }
]) {}
CoFeed
is loaded to the specified depth.subscribe<F, R>(listener):
() => void
class Thing<
F extends CoFeed<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: F,
listener: (value: Resolved<F, R>, unsubscribe: () => void) => void
]) {}
CoFeed
No need to provide an ID or Account since they're already part of the instance.
.subscribe<F, R>(options, listener):
() => void
class Thing<
F extends CoFeed<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: F,
options: { resolve: RefsToResolveStrict<F, R> },
listener: (value: Resolved<F, R>, unsubscribe: () => void) => void
]) {}
CoFeed
No need to provide an ID or Account since they're already part of the instance.
.waitForSync(options):
Promise<unknown[]>
function fn(...args: [
options: { timeout: number }
]) {}
CoFeed
to be uploaded to the other peers.._owner:
class X {
prop:
Group | Account
CoFeed.fromRaw<V>(raw):
V
class Thing<
V extends CoValue
]> {}
function fn(...args: [
this: CoValueClass<V>,
raw: RawCoValue
]) {}
._raw:
class X {
prop:
RawCoStream
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
"CoStream"
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
.constructor:
class X {
prop:
NO TYPE
.toJSON():
{ id: string, _type: "CoStream", in: { undefined } }
CoFeed
CoList.Of<Item>(item):
CoList
function fn(...args: [
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:
class X {
prop:
ID<CoList<Item>>
CoList
._refs:
class X {
prop:
{ 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
class Thing<
L extends CoList<any>
]> {}
function fn(...args: [
this: CoValueClass<L>,
items: UnCo<L[number]>[],
options: { owner: Group | Account } | 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, R>(id, options):
Promise<Resolved<L, R> | null>
class Thing<
L extends CoList<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<L>,
id: ID<L>,
options: { resolve: RefsToResolveStrict<L, R>, loadAs: AnonymousJazzAgent | Account }
]) {}
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, R>(id, listener):
() => void
class Thing<
L extends CoList<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<L>,
id: ID<L>,
listener: (value: Resolved<L, R>, unsubscribe: () => void) => 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)
);
CoList.subscribe<L, R>(id, options, listener):
() => void
class Thing<
L extends CoList<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<L>,
id: ID<L>,
options: SubscribeListenerOptions<L, R>,
listener: (value: Resolved<L, R>, unsubscribe: () => void) => 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, R>(options):
Promise<Resolved<L, R>>
class Thing<
L extends CoList<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: L,
options: { resolve: RefsToResolveStrict<L, R> }
]) {}
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, R>(listener):
() => void
class Thing<
L extends CoList<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: L,
listener: (value: Resolved<L, R>, unsubscribe: () => void) => 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.
.subscribe<L, R>(options, listener):
() => void
class Thing<
L extends CoList<any>,
R extends { $each: RefsToResolve<any, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: L,
options: { resolve: RefsToResolveStrict<L, R> },
listener: (value: Resolved<L, R>, unsubscribe: () => void) => 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.
.waitForSync(options):
Promise<unknown[]>
function fn(...args: [
options: { timeout: number }
]) {}
CoList
to be uploaded to the other peers.._owner:
class X {
prop:
Group | Account
.toJSON(_key, seenAbove):
any[]
function fn(...args: [
_key: string,
seenAbove: ID<CoValue>[]
]) {}
.[inspect]():
any[]
CoList.fromRaw<V>(raw):
V & CoList<any>
class Thing<
V extends CoList<any>
]> {}
function fn(...args: [
this: CoValueClass<V> & CoList,
raw: RawCoList
]) {}
._raw:
class X {
prop:
RawCoList
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
"CoList"
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
CoList[species]:
class X {
prop:
ArrayConstructor
CoList.isArray(arg):
arg is any[]
function fn(...args: [
arg: any
]) {}
CoList.from<T>(arrayLike):
T[]
function fn(...args: [
arrayLike: ArrayLike<T>
]) {}
CoList.from<T, U>(arrayLike, mapfn, thisArg):
U[]
function fn(...args: [
arrayLike: ArrayLike<T>,
mapfn: (v: T, k: number) => U,
thisArg: any
]) {}
CoList.from<T>(iterable):
T[]
function fn(...args: [
iterable: ArrayLike<T> | Iterable<T, any, any>
]) {}
CoList.from<T, U>(iterable, mapfn, thisArg):
U[]
function fn(...args: [
iterable: ArrayLike<T> | Iterable<T, any, any>,
mapfn: (v: T, k: number) => U,
thisArg: any
]) {}
CoList.fromAsync<T>(iterableOrArrayLike):
Promise<T[]>
function fn(...args: [
iterableOrArrayLike: ArrayLike<PromiseLike<T> | T> | Iterable<PromiseLike<T> | T, any, any> | AsyncIterable<T, any, any>
]) {}
CoList.fromAsync<T, U>(iterableOrArrayLike, mapFn, thisArg):
Promise<Awaited<U>[]>
function fn(...args: [
iterableOrArrayLike: ArrayLike<T> | Iterable<T, any, any> | AsyncIterable<T, any, any>,
mapFn: (value: Awaited<T>, index: number) => U,
thisArg: any
]) {}
.constructor:
class X {
prop:
NO TYPE
._edits:
class X {
prop:
{ undefined }
.push(items):
number
function fn(...args: [
items: Item[]
]) {}
.unshift(items):
number
function fn(...args: [
items: Item[]
]) {}
.pop():
Item | undefined
If the array is empty, undefined is returned and the array is not modified.
.shift():
Item | undefined
If the array is empty, undefined is returned and the array is not modified.
.splice(start, deleteCount, items):
Item[]
function fn(...args: [
start: number,
deleteCount: number,
items: Item[]
]) {}
CoList
at a given index..applyDiff(result):
void
function fn(...args: [
result: Item[]
]) {}
CoList
to match another list, where the changes are managed internally..length:
class X {
prop:
number
.toString():
string
.toLocaleString():
string
.toLocaleString(locales, options):
string
function fn(...args: [
locales: string[] | string,
options: NumberFormatOptions & DateTimeFormatOptions
]) {}
.concat(items):
Item[]
function fn(...args: [
items: ConcatArray<Item>[]
]) {}
This method returns a new array without modifying any existing arrays.
.concat(items):
Item[]
function fn(...args: [
items: ConcatArray<Item> | Item[]
]) {}
This method returns a new array without modifying any existing arrays.
.join(separator):
string
function fn(...args: [
separator: string
]) {}
.reverse():
Item[]
This method mutates the array and returns a reference to the same array.
.slice(start, end):
Item[]
function fn(...args: [
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
function fn(...args: [
compareFn: (a: Item, b: Item) => number
]) {}
This method mutates the array and returns a reference to the same array.
.indexOf(searchElement, fromIndex):
number
function fn(...args: [
searchElement: Item,
fromIndex: number
]) {}
.lastIndexOf(searchElement, fromIndex):
number
function fn(...args: [
searchElement: Item,
fromIndex: number
]) {}
.every<S>(predicate, thisArg):
this is S[]
function fn(...args: [
predicate: (value: Item, index: number, array: Item[]) => value is S,
thisArg: any
]) {}
.every(predicate, thisArg):
boolean
function fn(...args: [
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
]) {}
.some(predicate, thisArg):
boolean
function fn(...args: [
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
]) {}
.forEach(callbackfn, thisArg):
void
function fn(...args: [
callbackfn: (value: Item, index: number, array: Item[]) => void,
thisArg: any
]) {}
.map<U>(callbackfn, thisArg):
U[]
function fn(...args: [
callbackfn: (value: Item, index: number, array: Item[]) => U,
thisArg: any
]) {}
.filter<S>(predicate, thisArg):
S[]
function fn(...args: [
predicate: (value: Item, index: number, array: Item[]) => value is S,
thisArg: any
]) {}
.filter(predicate, thisArg):
Item[]
function fn(...args: [
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
]) {}
.reduce(callbackfn):
Item
function fn(...args: [
callbackfn: (previousValue: Item, currentValue: Item, currentIndex: number, array: Item[]) => Item
]) {}
.reduce(callbackfn, initialValue):
Item
function fn(...args: [
callbackfn: (previousValue: Item, currentValue: Item, currentIndex: number, array: Item[]) => Item,
initialValue: Item
]) {}
.reduce<U>(callbackfn, initialValue):
U
function fn(...args: [
callbackfn: (previousValue: U, currentValue: Item, currentIndex: number, array: Item[]) => U,
initialValue: U
]) {}
.reduceRight(callbackfn):
Item
function fn(...args: [
callbackfn: (previousValue: Item, currentValue: Item, currentIndex: number, array: Item[]) => Item
]) {}
.reduceRight(callbackfn, initialValue):
Item
function fn(...args: [
callbackfn: (previousValue: Item, currentValue: Item, currentIndex: number, array: Item[]) => Item,
initialValue: Item
]) {}
.reduceRight<U>(callbackfn, initialValue):
U
function fn(...args: [
callbackfn: (previousValue: U, currentValue: Item, currentIndex: number, array: Item[]) => U,
initialValue: U
]) {}
.find<S>(predicate, thisArg):
S | undefined
function fn(...args: [
predicate: (value: Item, index: number, obj: Item[]) => value is S,
thisArg: any
]) {}
otherwise.
.find(predicate, thisArg):
Item | undefined
function fn(...args: [
predicate: (value: Item, index: number, obj: Item[]) => unknown,
thisArg: any
]) {}
.findIndex(predicate, thisArg):
number
function fn(...args: [
predicate: (value: Item, index: number, obj: Item[]) => unknown,
thisArg: any
]) {}
otherwise.
.fill(value, start, end):
this
function fn(...args: [
value: Item,
start: number,
end: number
]) {}
start
to end
index to a static value
and returns the modified array.copyWithin(target, start, end):
this
function fn(...args: [
target: number,
start: number,
end: number
]) {}
to the same array starting at position target
.entries():
ArrayIterator<[number, Item]>
.keys():
ArrayIterator<number>
.values():
ArrayIterator<Item>
.includes(searchElement, fromIndex):
boolean
function fn(...args: [
searchElement: Item,
fromIndex: number
]) {}
.flatMap<U, This>(callback, thisArg):
U[]
function fn(...args: [
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>[]
class Thing<
D extends number
]> {}
function fn(...args: [
this: A,
depth: D
]) {}
specified depth.
.at(index):
Item | undefined
function fn(...args: [
index: number
]) {}
.findLast<S>(predicate, thisArg):
S | undefined
function fn(...args: [
predicate: (value: Item, index: number, array: Item[]) => value is S,
thisArg: any
]) {}
otherwise.
.findLast(predicate, thisArg):
Item | undefined
function fn(...args: [
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
]) {}
.findLastIndex(predicate, thisArg):
number
function fn(...args: [
predicate: (value: Item, index: number, array: Item[]) => unknown,
thisArg: any
]) {}
otherwise.
.toReversed():
Item[]
.toSorted(compareFn):
Item[]
function fn(...args: [
compareFn: (a: Item, b: Item) => number
]) {}
.toSpliced(start, deleteCount, items):
Item[]
function fn(...args: [
start: number,
deleteCount: number,
items: Item[]
]) {}
.toSpliced(start, deleteCount):
Item[]
function fn(...args: [
start: number,
deleteCount: number
]) {}
.with(index, value):
Item[]
function fn(...args: [
index: number,
value: Item
]) {}
given value. If the index is negative, then it replaces from the end
of the array.
.[iterator]():
ArrayIterator<Item>
[unscopables]:
class X {
prop:
{ length: boolean, toString: boolean, toLocaleString: boolean, pop: boolean, push: boolean, concat: boolean, join: boolean, reverse: boolean, shift: boolean, slice: boolean, sort: boolean, splice: boolean, unshift: boolean, indexOf: boolean, lastIndexOf: boolean, every: boolean, some: boolean, forEach: boolean, map: boolean, filter: boolean, reduce: boolean, reduceRight: boolean, find: boolean, findIndex: boolean, fill: boolean, copyWithin: boolean, entries: boolean, keys: boolean, values: boolean, includes: boolean, flatMap: boolean, flat: boolean, at: boolean, findLast: boolean, findLastIndex: boolean, toReversed: boolean, toSorted: boolean, toSpliced: boolean, with: boolean, [iterator]: boolean, [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
function fn(...args: [
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:
class X {
prop:
ID<CoMap>
CoMap
._refs:
class X {
prop:
{[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[]
function fn(...args: [
_key: string,
seenAbove: ID<CoValue>[]
]) {}
CoMap
CoMap.create<M>(init, options):
M
class Thing<
M extends CoMap
]> {}
function fn(...args: [
this: CoValueClass<M>,
init: Simplify<CoMapInit<M>>,
options: { owner: Group | Account, unique: JsonValue } | Group | Account
]) {}
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, R>(id, options):
Promise<Resolved<M, R> | null>
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
options: { resolve: RefsToResolveStrict<M, R>, loadAs: AnonymousJazzAgent | Account }
]) {}
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",
{ pet: {} }
);
CoMap.subscribe<M, R>(id, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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",
{ pet: {} },
(person) => console.log(person)
);
CoMap.subscribe<M, R>(id, options, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
options: SubscribeListenerOptions<M, R>,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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",
{ pet: {} },
(person) => console.log(person)
);
.ensureLoaded<M, R>(options):
Promise<Resolved<M, R>>
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
options: { resolve: RefsToResolveStrict<M, R> }
]) {}
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, R>(listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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.
.subscribe<M, R>(options, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
options: { resolve: RefsToResolveStrict<M, R> },
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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.
.waitForSync(options):
Promise<unknown[]>
function fn(...args: [
options: { timeout: number }
]) {}
CoMap
to be uploaded to the other peers.._edits:
class X {
prop:
{[Key in string]: IfCo<this[Key], LastAndAllCoMapEdits<this[Key]>>}
._owner:
class X {
prop:
Group | Account
.[inspect]():
any[]
CoMap.fromRaw<V>(raw):
V
class Thing<
V extends CoValue
]> {}
function fn(...args: [
this: CoValueClass<V>,
raw: RawCoValue
]) {}
._raw:
class X {
prop:
RawCoMap
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
"CoMap"
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
CoMap.findUnique<M>(unique, ownerID, as):
ID<M>
class Thing<
M extends CoMap
]> {}
function fn(...args: [
this: CoValueClass<M>,
unique: JsonValue,
ownerID: ID<Group> | ID<Account>,
as: Group | AnonymousJazzAgent | Account
]) {}
.applyDiff<N>(newValues):
CoMap
class Thing<
N extends Partial<CoMapInit<CoMap>>
]> {}
function fn(...args: [
newValues: N
]) {}
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
class Thing<
V extends CoValue
]> {}
function fn(...args: [
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:
class X {
prop:
ID<SchemaUnion>
._owner:
class X {
prop:
Group | Account
.toJSON():
any[] | string | object
.[inspect]():
any[] | string | object
._raw:
class X {
prop:
RawCoValue
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
string
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
.constructor:
class X {
prop:
NO TYPE
Context Creation
type JazzAuthContext
type JazzAuthContext<Acc extends Account> = { me: Acc, node: LocalNode, authenticate: AuthenticateAccountFunction, register: RegisterAccountFunction, logOut: () => Promise<void>, done: () => void, isAuthenticated: boolean }
Identity & Permissions
.id:
class X {
prop:
ID<Account>
Account.load<A, R>(id, options):
Promise<Resolved<A, R> | null>
class Thing<
A extends Account,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<A>,
id: ID<A>,
options: { resolve: RefsToResolveStrict<A, R>, loadAs: AnonymousJazzAgent | Account }
]) {}
Account.subscribe<A, R>(id, listener):
() => void
class Thing<
A extends Account,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<A>,
id: ID<A>,
listener: (value: Resolved<A, R>, unsubscribe: () => void) => void
]) {}
Account.subscribe<A, R>(id, options, listener):
() => void
class Thing<
A extends Account,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<A>,
id: ID<A>,
options: SubscribeListenerOptions<A, R>,
listener: (value: Resolved<A, R>, unsubscribe: () => void) => void
]) {}
.ensureLoaded<A, R>(options):
Promise<Resolved<A, R>>
class Thing<
A extends Account,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: A,
options: { resolve: RefsToResolveStrict<A, R> }
]) {}
.subscribe<A, R>(listener):
() => void
class Thing<
A extends Account,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: A,
listener: (value: Resolved<A, R>, unsubscribe: () => void) => void
]) {}
.subscribe<A, R>(options, listener):
() => void
class Thing<
A extends Account,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: A,
options: { resolve: RefsToResolveStrict<A, R> },
listener: (value: Resolved<A, R>, unsubscribe: () => void) => void
]) {}
.waitForSync(options):
Promise<unknown[]>
function fn(...args: [
options: { timeout: number }
]) {}
Account
to be uploaded to the other peers..waitForAllCoValuesSync(options):
Promise<unknown[][]>
function fn(...args: [
options: { timeout: number }
]) {}
CoValues
to be uploaded to the other peers.._owner:
class X {
prop:
Account
.toJSON():
any[] | object
.[inspect]():
any[] | object
Account.fromRaw<V>(raw):
V
class Thing<
V extends CoValue
]> {}
function fn(...args: [
this: CoValueClass<V>,
raw: RawCoValue
]) {}
._raw:
class X {
prop:
RawAccount<AccountMeta> | RawControlledAccount<AccountMeta>
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
"Account"
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
Account._schema:
class X {
prop:
any
Account.getMe<A>():
A
class Thing<
A extends Account
]> {}
function fn(...args: [
this: CoValueClass<A> & Account
]) {}
Account.createAs<A>(as, options):
Promise<A>
class Thing<
A extends Account
]> {}
function fn(...args: [
this: CoValueClass<A> & Account,
as: Account,
options: { creationProps: { name: string } }
]) {}
Account.fromNode<A>(node):
A
class Thing<
A extends Account
]> {}
function fn(...args: [
this: CoValueClass<A>,
node: LocalNode
]) {}
.constructor:
class X {
prop:
NO TYPE
._schema:
class X {
prop:
{ profile: Schema, root: Schema }
.profile:
class X {
prop:
Profile | null
.root:
class X {
prop:
CoMap | null
._refs:
class X {
prop:
{ profile: Ref<Profile> | undefined, root: Ref<CoMap> | undefined }
.isMe:
class X {
prop:
boolean
.isLocalNodeOwner:
class X {
prop:
boolean
.sessionID:
class X {
prop:
TODO type templateLiteral | TODO type templateLiteral | undefined
.myRole():
"admin" | undefined
.getRoleOf(member):
"admin" | undefined
function fn(...args: [
member: "me" | "everyone" | ID<Account>
]) {}
.getParentGroups():
Group[]
.members:
class X {
prop:
{ id: "everyone" | ID<Account>, role: Role, ref: Ref<Account> | undefined, account: Account | null | undefined }[]
.canRead(value):
boolean
function fn(...args: [
value: CoValue
]) {}
.canWrite(value):
boolean
function fn(...args: [
value: CoValue
]) {}
.canAdmin(value):
boolean
function fn(...args: [
value: CoValue
]) {}
.acceptInvite<V>(valueID, inviteSecret, coValueClass):
Promise<V | null>
class Thing<
V extends CoValue
]> {}
function fn(...args: [
valueID: ID<V>,
inviteSecret: TODO type templateLiteral,
coValueClass: CoValueClass<V>
]) {}
.applyMigration(creationProps):
Promise<void>
function fn(...args: [
creationProps: AccountCreationProps
]) {}
.migrate(creationProps):
void
function fn(...args: [
creationProps: AccountCreationProps
]) {}
function
isControlledAccount(account):
{}
account is Account & { isLocalNodeOwner: true, sessionID: TODO type templateLiteral | TODO type templateLiteral, _raw: RawControlledAccount }
function fn(...args: [
account: Account
]) {}
.id:
class X {
prop:
ID<Group>
Group.load<G, R>(id, options):
Promise<Resolved<G, R> | null>
class Thing<
G extends Group,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<G>,
id: ID<G>,
options: { resolve: RefsToResolveStrict<G, R>, loadAs: Account }
]) {}
Group.subscribe<G, R>(id, listener):
() => void
class Thing<
G extends Group,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<G>,
id: ID<G>,
listener: (value: Resolved<G, R>, unsubscribe: () => void) => void
]) {}
Group.subscribe<G, R>(id, options, listener):
() => void
class Thing<
G extends Group,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: CoValueClass<G>,
id: ID<G>,
options: SubscribeListenerOptions<G, R>,
listener: (value: Resolved<G, R>, unsubscribe: () => void) => void
]) {}
.ensureLoaded<G, R>(options):
Promise<Resolved<G, R>>
class Thing<
G extends Group,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: G,
options: { resolve: RefsToResolveStrict<G, R> }
]) {}
.subscribe<G, R>(listener):
() => void
class Thing<
G extends Group,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: G,
listener: (value: Resolved<G, R>, unsubscribe: () => void) => void
]) {}
.subscribe<G, R>(options, listener):
() => void
class Thing<
G extends Group,
R extends { profile: RefsToResolve<Profile, 10, [0]>, root: RefsToResolve<CoMap, 10, [0]> } | boolean
]> {}
function fn(...args: [
this: G,
options: { resolve: RefsToResolveStrict<G, R> },
listener: (value: Resolved<G, R>, unsubscribe: () => void) => void
]) {}
.waitForSync(options):
Promise<unknown[]>
function fn(...args: [
options: { timeout: number }
]) {}
Group
to be uploaded to the other peers.._owner:
class X {
prop:
Group | Account
.toJSON():
any[] | string | object
.[inspect]():
any[] | string | object
Group.fromRaw<V>(raw):
V
class Thing<
V extends CoValue
]> {}
function fn(...args: [
this: CoValueClass<V>,
raw: RawCoValue
]) {}
._raw:
class X {
prop:
RawGroup
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
"Group"
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
Group._schema:
class X {
prop:
any
Group.create<G>(options):
G
class Thing<
G extends Group
]> {}
function fn(...args: [
this: CoValueClass<G>,
options: { owner: Account } | Account
]) {}
.constructor:
class X {
prop:
NO TYPE
._schema:
class X {
prop:
{ profile: Schema, root: Schema }
.profile:
class X {
prop:
Profile | null
.root:
class X {
prop:
CoMap | null
._refs:
class X {
prop:
{ profile: Ref<Profile> | undefined, root: Ref<CoMap> | undefined }
.myRole():
Role | undefined
.addMember(member, role):
void
function fn(...args: [
member: "everyone",
role: "writer" | "reader"
]) {}
.addMember(member, role):
void
function fn(...args: [
member: Account,
role: AccountRole
]) {}
.removeMember(member):
Promise<void>
function fn(...args: [
member: "everyone" | Account
]) {}
.members:
class X {
prop:
{ id: ID<Account>, role: AccountRole, ref: Ref<Account>, account: Account }[]
.getRoleOf(member):
Role | undefined
function fn(...args: [
member: "me" | "everyone" | ID<Account>
]) {}
.getParentGroups():
Group[]
.extend(parent, roleMapping):
Group
function fn(...args: [
parent: Group,
roleMapping: "inherit" | "admin" | "writer" | "reader"
]) {}
.revokeExtend(parent):
Promise<Group>
function fn(...args: [
parent: Group
]) {}
Profile.Record<Value>(value):
RecordLikeCoMap
function fn(...args: [
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:
class X {
prop:
ID<Profile>
CoMap
._refs:
class X {
prop:
{[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[]
function fn(...args: [
_key: string,
seenAbove: ID<CoValue>[]
]) {}
CoMap
Profile.create<M>(init, options):
M
class Thing<
M extends CoMap
]> {}
function fn(...args: [
this: CoValueClass<M>,
init: Simplify<CoMapInit<M>>,
options: { owner: Group } | Group
]) {}
The owner (a Group) determines access rights to the Profile.
Profile.load<M, R>(id, options):
Promise<Resolved<M, R> | null>
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
options: { resolve: RefsToResolveStrict<M, R>, loadAs: AnonymousJazzAgent | Account }
]) {}
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",
{ pet: {} }
);
Profile.subscribe<M, R>(id, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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",
{ pet: {} },
(person) => console.log(person)
);
Profile.subscribe<M, R>(id, options, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
options: SubscribeListenerOptions<M, R>,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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",
{ pet: {} },
(person) => console.log(person)
);
.ensureLoaded<M, R>(options):
Promise<Resolved<M, R>>
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
options: { resolve: RefsToResolveStrict<M, R> }
]) {}
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, R>(listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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.
.subscribe<M, R>(options, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
options: { resolve: RefsToResolveStrict<M, R> },
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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.
.waitForSync(options):
Promise<unknown[]>
function fn(...args: [
options: { timeout: number }
]) {}
CoMap
to be uploaded to the other peers.._owner:
class X {
prop:
Group
._edits:
class X {
prop:
{[Key in string]: IfCo<this[Key], LastAndAllCoMapEdits<this[Key]>>}
.[inspect]():
any[]
Profile.fromRaw<V>(raw):
V
class Thing<
V extends CoValue
]> {}
function fn(...args: [
this: CoValueClass<V>,
raw: RawCoValue
]) {}
._raw:
class X {
prop:
RawCoMap
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
"CoMap"
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
Profile.findUnique<M>(unique, ownerID, as):
ID<M>
class Thing<
M extends CoMap
]> {}
function fn(...args: [
this: CoValueClass<M>,
unique: JsonValue,
ownerID: ID<Group> | ID<Account>,
as: Group | AnonymousJazzAgent | Account
]) {}
.name:
class X {
prop:
co<string>
.inbox:
class X {
prop:
co<CoID<InboxRoot> | undefined>
.inboxInvite:
class X {
prop:
co<TODO type templateLiteral | undefined>
.applyDiff<N>(newValues):
Profile
class Thing<
N extends Partial<CoMapInit<Profile>>
]> {}
function fn(...args: [
newValues: N
]) {}
Schema definition
Encoders reflection
co reflection
type co
type co<T> = T & CoMarker | T
Abstract interfaces
.id:
class X {
prop:
ID<CoValue>
._owner:
class X {
prop:
Group | Account
.toJSON(key, seenAbove):
any[] | string | object
function fn(...args: [
key: string,
seenAbove: ID<CoValue>[]
]) {}
.[inspect]():
any
._raw:
class X {
prop:
RawCoValue
._type:
class X {
prop:
string
.id:
class X {
prop:
ID<CoPlainText>
CoPlainText.load<T>(id, options):
Promise<T | null>
class Thing<
T extends CoPlainText
]> {}
function fn(...args: [
this: CoValueClass<T>,
id: ID<T>,
options: { loadAs: AnonymousJazzAgent | Account }
]) {}
CoPlainText
with a given ID, as a given account.CoPlainText.subscribe<T>(id, listener):
() => void
class Thing<
T extends CoPlainText
]> {}
function fn(...args: [
this: CoValueClass<T>,
id: ID<T>,
listener: (value: T, unsubscribe: () => void) => void
]) {}
CoPlainText
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.
Check out the
load
methods on CoMap
/CoList
/CoStream
/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.CoPlainText.subscribe<T>(id, options, listener):
() => void
class Thing<
T extends CoPlainText
]> {}
function fn(...args: [
this: CoValueClass<T>,
id: ID<T>,
options: Omit<SubscribeListenerOptions<T, true>, "resolve">,
listener: (value: T, unsubscribe: () => void) => void
]) {}
CoPlainText
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.
Check out the
load
methods on CoMap
/CoList
/CoStream
/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..subscribe<T>(listener):
() => void
class Thing<
T extends CoPlainText
]> {}
function fn(...args: [
this: T,
listener: (value: T, unsubscribe: () => void) => void
]) {}
CoPlainText
, subscribe to updates to the CoPlainText
and ensure that the specified fields are loaded to the specified depth.Works like
CoPlainText.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:
class X {
prop:
Group | Account
.toJSON():
string
.[inspect]():
string
._raw:
class X {
prop:
RawCoPlainText
._type:
class X {
prop:
"CoPlainText"
CoPlainText.create<T>(text, options):
T
class Thing<
T extends CoPlainText
]> {}
function fn(...args: [
this: CoValueClass<T>,
text: string,
options: { owner: Group | Account }
]) {}
CoPlainText.fromRaw<V>(raw):
V & CoPlainText
class Thing<
V extends CoPlainText
]> {}
function fn(...args: [
this: CoValueClass<V> & CoPlainText,
raw: RawCoPlainText
]) {}
CoPlainText.fromCharCode(codes):
string
function fn(...args: [
codes: number[]
]) {}
CoPlainText.fromCodePoint(codePoints):
string
function fn(...args: [
codePoints: number[]
]) {}
If length is 0, the empty string is returned.
CoPlainText.raw(template, substitutions):
string
function fn(...args: [
template: { raw: ArrayLike<string> | TODO type typeOperator },
substitutions: any[]
]) {}
such, the first argument will be a well formed template call site object and the rest
parameter will contain the substitution values. It can also be called directly, for example,
to interleave strings and values from your own tag function, and in this case the only thing
it needs from the first argument is the raw property.
.constructor:
class X {
prop:
NO TYPE
.length:
class X {
prop:
number
.toString():
string
.valueOf():
string
.insertAfter(idx, text):
void
function fn(...args: [
idx: number,
text: string
]) {}
.deleteRange(range):
void
function fn(...args: [
range: { from: number, to: number }
]) {}
.posBefore(idx):
OpID | undefined
function fn(...args: [
idx: number
]) {}
.posAfter(idx):
OpID | undefined
function fn(...args: [
idx: number
]) {}
.idxBefore(pos):
undefined | number
function fn(...args: [
pos: OpID
]) {}
.idxAfter(pos):
undefined | number
function fn(...args: [
pos: OpID
]) {}
.charAt(pos):
string
function fn(...args: [
pos: number
]) {}
.charCodeAt(index):
number
function fn(...args: [
index: number
]) {}
.concat(strings):
string
function fn(...args: [
strings: string[]
]) {}
.indexOf(searchString, position):
number
function fn(...args: [
searchString: string,
position: number
]) {}
.lastIndexOf(searchString, position):
number
function fn(...args: [
searchString: string,
position: number
]) {}
.localeCompare(that):
number
function fn(...args: [
that: string
]) {}
.localeCompare(that, locales, options):
number
function fn(...args: [
that: string,
locales: string[] | string,
options: CollatorOptions
]) {}
.localeCompare(that, locales, options):
number
function fn(...args: [
that: string,
locales: LocalesArgument,
options: CollatorOptions
]) {}
.match(regexp):
RegExpMatchArray | null
function fn(...args: [
regexp: RegExp | string
]) {}
.match(matcher):
RegExpMatchArray | null
function fn(...args: [
matcher: { [match]: NO TYPE }
]) {}
containing the results of that search, or null if no matches are found.
.replace(searchValue, replaceValue):
string
function fn(...args: [
searchValue: RegExp | string,
replaceValue: string
]) {}
.replace(searchValue, replacer):
string
function fn(...args: [
searchValue: RegExp | string,
replacer: (substring: string, args: any[]) => string
]) {}
.replace(searchValue, replaceValue):
string
function fn(...args: [
searchValue: { [replace]: NO TYPE },
replaceValue: string
]) {}
@linkcode replaceValue
to the [Symbol.replace]
method on @linkcode searchValue
. This method is expected to implement its own replacement algorithm..replace(searchValue, replacer):
string
function fn(...args: [
searchValue: { [replace]: NO TYPE },
replacer: (substring: string, args: any[]) => string
]) {}
.search(regexp):
number
function fn(...args: [
regexp: RegExp | string
]) {}
.search(searcher):
number
function fn(...args: [
searcher: { [search]: NO TYPE }
]) {}
.slice(start, end):
string
function fn(...args: [
start: number,
end: number
]) {}
.split(separator, limit):
string[]
function fn(...args: [
separator: RegExp | string,
limit: number
]) {}
.split(splitter, limit):
string[]
function fn(...args: [
splitter: { [split]: NO TYPE },
limit: number
]) {}
.substring(start, end):
string
function fn(...args: [
start: number,
end: number
]) {}
.toLowerCase():
string
.toLocaleLowerCase(locales):
string
function fn(...args: [
locales: string[] | string
]) {}
.toLocaleLowerCase(locales):
string
function fn(...args: [
locales: LocalesArgument
]) {}
.toUpperCase():
string
.toLocaleUpperCase(locales):
string
function fn(...args: [
locales: string[] | string
]) {}
.toLocaleUpperCase(locales):
string
function fn(...args: [
locales: LocalesArgument
]) {}
.trim():
string
.substr(from, length):
string
function fn(...args: [
from: number,
length: number
]) {}
.codePointAt(pos):
undefined | number
function fn(...args: [
pos: number
]) {}
value of the UTF-16 encoded code point starting at the string element at position pos in
the String resulting from converting this object to a String.
If there is no element at that position, the result is undefined.
If a valid UTF-16 surrogate pair does not begin at pos, the result is the code unit at pos.
.includes(searchString, position):
boolean
function fn(...args: [
searchString: string,
position: number
]) {}
object to a String, at one or more positions that are
greater than or equal to position; otherwise, returns false.
.endsWith(searchString, endPosition):
boolean
function fn(...args: [
searchString: string,
endPosition: number
]) {}
same as the corresponding elements of this object (converted to a String) starting at
endPosition – length(this). Otherwise returns false.
.normalize(form):
string
function fn(...args: [
form: "NFKD" | "NFKC" | "NFD" | "NFC"
]) {}
named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.
.normalize(form):
string
function fn(...args: [
form: string
]) {}
named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.
.repeat(count):
string
function fn(...args: [
count: number
]) {}
the empty string is returned.
.startsWith(searchString, position):
boolean
function fn(...args: [
searchString: string,
position: number
]) {}
same as the corresponding elements of this object (converted to a String) starting at
position. Otherwise returns false.
.anchor(name):
string
function fn(...args: [
name: string
]) {}
<a>
HTML anchor element and sets the name attribute to the text value.big():
string
<big>
HTML element.blink():
string
<blink>
HTML element.bold():
string
<b>
HTML element.fixed():
string
<tt>
HTML element.fontcolor(color):
string
function fn(...args: [
color: string
]) {}
<font>
HTML element and sets the color attribute value.fontsize(size):
string
function fn(...args: [
size: number
]) {}
<font>
HTML element and sets the size attribute value.fontsize(size):
string
function fn(...args: [
size: string
]) {}
<font>
HTML element and sets the size attribute value.italics():
string
<i>
HTML element.link(url):
string
function fn(...args: [
url: string
]) {}
<a>
HTML element and sets the href attribute value.small():
string
<small>
HTML element.strike():
string
<strike>
HTML element.sub():
string
<sub>
HTML element.sup():
string
<sup>
HTML element.padStart(maxLength, fillString):
string
function fn(...args: [
maxLength: number,
fillString: string
]) {}
The padding is applied from the start (left) of the current string.
.padEnd(maxLength, fillString):
string
function fn(...args: [
maxLength: number,
fillString: string
]) {}
The padding is applied from the end (right) of the current string.
.trimEnd():
string
.trimStart():
string
.trimLeft():
string
.trimRight():
string
.matchAll(regexp):
RegExpStringIterator<RegExpExecArray>
function fn(...args: [
regexp: RegExp
]) {}
containing the results of that search.
.replaceAll(searchValue, replaceValue):
string
function fn(...args: [
searchValue: RegExp | string,
replaceValue: string
]) {}
.replaceAll(searchValue, replacer):
string
function fn(...args: [
searchValue: RegExp | string,
replacer: (substring: string, args: any[]) => string
]) {}
.at(index):
undefined | string
function fn(...args: [
index: number
]) {}
.isWellFormed():
boolean
.toWellFormed():
string
.[iterator]():
StringIterator<string>
class Thing<
Value extends CoValue
]> {}
Media
ImageDefinition.Record<Value>(value):
RecordLikeCoMap
function fn(...args: [
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:
class X {
prop:
ID<ImageDefinition>
CoMap
._refs:
class X {
prop:
{[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[]
function fn(...args: [
_key: string,
seenAbove: ID<CoValue>[]
]) {}
CoMap
ImageDefinition.create<M>(init, options):
M
class Thing<
M extends CoMap
]> {}
function fn(...args: [
this: CoValueClass<M>,
init: Simplify<CoMapInit<M>>,
options: { owner: Group | Account, unique: JsonValue } | Group | Account
]) {}
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, R>(id, options):
Promise<Resolved<M, R> | null>
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
options: { resolve: RefsToResolveStrict<M, R>, loadAs: AnonymousJazzAgent | Account }
]) {}
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",
{ pet: {} }
);
ImageDefinition.subscribe<M, R>(id, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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",
{ pet: {} },
(person) => console.log(person)
);
ImageDefinition.subscribe<M, R>(id, options, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
options: SubscribeListenerOptions<M, R>,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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",
{ pet: {} },
(person) => console.log(person)
);
.ensureLoaded<M, R>(options):
Promise<Resolved<M, R>>
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
options: { resolve: RefsToResolveStrict<M, R> }
]) {}
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, R>(listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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.
.subscribe<M, R>(options, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
options: { resolve: RefsToResolveStrict<M, R> },
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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.
.waitForSync(options):
Promise<unknown[]>
function fn(...args: [
options: { timeout: number }
]) {}
CoMap
to be uploaded to the other peers.._edits:
class X {
prop:
{[Key in string]: IfCo<this[Key], LastAndAllCoMapEdits<this[Key]>>}
._owner:
class X {
prop:
Group | Account
.[inspect]():
any[]
ImageDefinition.fromRaw<V>(raw):
V
class Thing<
V extends CoValue
]> {}
function fn(...args: [
this: CoValueClass<V>,
raw: RawCoValue
]) {}
._raw:
class X {
prop:
RawCoMap
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
"CoMap"
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
ImageDefinition.findUnique<M>(unique, ownerID, as):
ID<M>
class Thing<
M extends CoMap
]> {}
function fn(...args: [
this: CoValueClass<M>,
unique: JsonValue,
ownerID: ID<Group> | ID<Account>,
as: Group | AnonymousJazzAgent | Account
]) {}
.originalSize:
class X {
prop:
co<[number, number]>
.highestResAvailable(options):
{ res: TODO type templateLiteral, stream: FileStream } | undefined
function fn(...args: [
options: { maxWidth: number, targetWidth: number }
]) {}
.$items$:
class X {
prop:
co<FileStream | null>
.applyDiff<N>(newValues):
ImageDefinition
class Thing<
N extends Partial<CoMapInit<ImageDefinition>>
]> {}
function fn(...args: [
newValues: N
]) {}
.placeholderDataURL:
class X {
prop:
co<string>
Auth Providers
DemoAuth
provides a JazzAuth
object for demo authentication.Demo authentication is useful for quickly testing your app, as it allows you to create new accounts and log in as existing ones.
import { DemoAuth } from "jazz-tools";
const auth = new DemoAuth(jazzContext.authenticate, new AuthSecretStorage());
PassphraseAuth
provides a JazzAuth
object for passphrase authentication.import { PassphraseAuth } from "jazz-tools";
const auth = new PassphraseAuth(crypto, jazzContext.authenticate, new AuthSecretStorage(), wordlist);
Invite Links
function
createInviteLink<C>(value, role, baseURL, valueHint):
{}
string
function fn(...args: [
value: C,
role: "writeOnly" | "admin" | "writer" | "reader",
baseURL: string,
valueHint: string
]) {}
function
parseInviteLink<C>(inviteURL):
{}
{ valueID: ID<C>, inviteSecret: TODO type templateLiteral, valueHint: string } | undefined
function fn(...args: [
inviteURL: string
]) {}
function
consumeInviteLink<V>({ inviteURL, invitedObjectSchema, as?, forValueHint? }):
{}
Promise<{ valueID: ID<V>, inviteSecret: TODO type templateLiteral, valueHint: string } | undefined>
function fn(...args: [
{ inviteURL: string, invitedObjectSchema: CoValueClass<V>, as: Account, forValueHint: string }
]) {}
Other
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
class Thing<
I extends CoValue,
O extends CoValue | undefined
]> {}
type AccountClass
type AccountClass<Acc extends Account> = CoValueClass<Acc> & { fromNode: Account["fromNode"] }
type AccountCreationProps
type AccountCreationPropsundefined = { name: string, onboarding: boolean }
CoStream
type CoFeedEntry
type CoFeedEntry<Item> = SingleCoFeedEntry<Item> & { all: IterableIterator<SingleCoFeedEntry<Item>> }
FileStream
type CoMapInit
type CoMapInit<Map extends object> = {[Key in CoKeys<Map>]: ForceRequiredRef<Map[Key]>} & {[Key in CoKeys<Map>]: ForceRequiredRef<Map[Key]>}
type TextPos
type TextPosundefined = OpID
Combines plain text with a list of marks for formatting and annotations.
Provides methods for text manipulation, mark insertion, and tree conversion.
CoRichText.Record<Value>(value):
RecordLikeCoMap
function fn(...args: [
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:
class X {
prop:
ID<CoRichText>
CoMap
._refs:
class X {
prop:
{[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[]
function fn(...args: [
_key: string,
seenAbove: ID<CoValue>[]
]) {}
CoMap
CoRichText.create<M>(init, options):
M
class Thing<
M extends CoMap
]> {}
function fn(...args: [
this: CoValueClass<M>,
init: Simplify<CoMapInit<M>>,
options: { owner: Group | Account, unique: JsonValue } | Group | Account
]) {}
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 });
CoRichText.load<M, R>(id, options):
Promise<Resolved<M, R> | null>
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
options: { resolve: RefsToResolveStrict<M, R>, loadAs: AnonymousJazzAgent | Account }
]) {}
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",
{ pet: {} }
);
CoRichText.subscribe<M, R>(id, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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",
{ pet: {} },
(person) => console.log(person)
);
CoRichText.subscribe<M, R>(id, options, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: CoValueClass<M>,
id: ID<M>,
options: SubscribeListenerOptions<M, R>,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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",
{ pet: {} },
(person) => console.log(person)
);
.ensureLoaded<M, R>(options):
Promise<Resolved<M, R>>
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
options: { resolve: RefsToResolveStrict<M, R> }
]) {}
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, R>(listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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.
.subscribe<M, R>(options, listener):
() => void
class Thing<
M extends CoMap,
R extends { undefined } | boolean
]> {}
function fn(...args: [
this: M,
options: { resolve: RefsToResolveStrict<M, R> },
listener: (value: Resolved<M, R>, unsubscribe: () => void) => 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.
.waitForSync(options):
Promise<unknown[]>
function fn(...args: [
options: { timeout: number }
]) {}
CoMap
to be uploaded to the other peers.._edits:
class X {
prop:
{[Key in string]: IfCo<this[Key], LastAndAllCoMapEdits<this[Key]>>}
._owner:
class X {
prop:
Group | Account
.[inspect]():
any[]
CoRichText.fromRaw<V>(raw):
V
class Thing<
V extends CoValue
]> {}
function fn(...args: [
this: CoValueClass<V>,
raw: RawCoValue
]) {}
._raw:
class X {
prop:
RawCoMap
._instanceID:
class X {
prop:
string
._type:
class X {
prop:
"CoMap"
.castAs<Cl>(cl):
InstanceType<Cl>
class Thing<
Cl extends CoValueClass<CoValue> & CoValueFromRaw<CoValue>
]> {}
function fn(...args: [
cl: Cl
]) {}
CoRichText.createFromPlainText(text, options):
CoRichText
function fn(...args: [
text: string,
options: { owner: Group | Account }
]) {}
CoRichText.createFromPlainTextAndMark<MarkClass>(text, WrapIn, extraArgs, options):
CoRichText
class Thing<
MarkClass extends (args: any[]) => Mark
]> {}
function fn(...args: [
text: string,
WrapIn: MarkClass,
extraArgs: Omit<CoMapInit<InstanceType<MarkClass>>, "endBefore" | "endAfter" | "startBefore" | "startAfter">,
options: { owner: Group | Account }
]) {}
CoRichText.findUnique<M>(unique, ownerID, as):
ID<M>
class Thing<
M extends CoMap
]> {}
function fn(...args: [
this: CoValueClass<M>,
unique: JsonValue,
ownerID: ID<Group> | ID<Account>,
as: Group | AnonymousJazzAgent | Account
]) {}
.text:
class X {
prop:
co<CoPlainText | null>
.marks:
class X {
prop:
co<CoList<co<Mark | null>> | null>
.insertAfter(idx, text):
void
function fn(...args: [
idx: number,
text: string
]) {}
.deleteRange(range):
void
function fn(...args: [
range: { from: number, to: number }
]) {}
.posBefore(idx):
OpID | undefined
function fn(...args: [
idx: number
]) {}
.posAfter(idx):
OpID | undefined
function fn(...args: [
idx: number
]) {}
.idxBefore(pos):
undefined | number
function fn(...args: [
pos: OpID
]) {}
.idxAfter(pos):
undefined | number
function fn(...args: [
pos: OpID
]) {}
.insertMark<MarkClass>(start, end, RangeClass, extraArgs, options):
void
class Thing<
MarkClass extends (args: any[]) => Mark
]> {}
function fn(...args: [
start: number,
end: number,
RangeClass: MarkClass,
extraArgs: Omit<CoMapInit<InstanceType<MarkClass>>, "endBefore" | "endAfter" | "startBefore" | "startAfter">,
options: { markOwner: Group | Account }
]) {}
.removeMark<MarkClass>(start, end, RangeClass, options):
void
class Thing<
MarkClass extends (args: any[]) => Mark
]> {}
function fn(...args: [
start: number,
end: number,
RangeClass: MarkClass,
options: { tag: string }
]) {}
.resolveMarks():
ResolvedMark<Mark>[]
.resolveAndDiffuseMarks():
ResolvedAndDiffusedMark<Mark>[]
.resolveAndDiffuseAndFocusMarks():
ResolvedAndFocusedMark<Mark>[]
.toTree(tagPrecedence):
TreeNode
function fn(...args: [
tagPrecedence: string[]
]) {}
.length:
class X {
prop:
number
.toString():
string
.applyDiff<N>(newValues):
CoRichText
class Thing<
N extends Partial<CoMapInit<CoRichText>>
]> {}
function fn(...args: [
newValues: N
]) {}
Marks reflection
type TreeLeaf
type TreeLeafundefined = { type: "leaf", start: number, end: number }
Contains plain text without any marks.
type TreeNode
type TreeNodeundefined = { type: "node", tag: string, start: number, end: number, children: TreeLeaf | TreeNode[], range: ResolvedAndFocusedMark }
Can contain other nodes or leaves, and includes formatting information.
type ResolvedMark
type ResolvedMark<R extends Mark> = { startAfter: number, startBefore: number, endAfter: number, endBefore: number, sourceMark: R }
Contains both position information and reference to the source mark.
type DeeplyLoaded
type DeeplyLoaded<V, Depth, DepthLimit extends number, CurrentDepth extends number[]> = TODO type conditional
type Resolved
type Resolved<T, R extends RefsToResolve<T> | undefined> = DeeplyLoaded<T, R, 10, []>
type RefsToResolve
type RefsToResolve<V, DepthLimit extends number, CurrentDepth extends number[]> = (TODO type conditional) | boolean
type RefsToResolveStrict
type RefsToResolveStrict<T, V> = TODO type conditional
function
createCoValueObservable<V, R>():
{}
{ getCurrentValue: () => Resolved<V, R> | null | undefined, subscribe: (cls: CoValueClass<V>, id: ID<CoValue>, options: { loadAs: AnonymousJazzAgent | Account, resolve: RefsToResolveStrict<V, R>, onUnavailable: () => void, onUnauthorized: () => void, syncResolution: boolean }, listener: () => void) => () => void }
function
loadCoValue<V, R>(cls, id, options):
{}
Promise<Resolved<V, R> | null>
function fn(...args: [
cls: CoValueClass<V>,
id: ID<CoValue>,
options: { loadAs: AnonymousJazzAgent | Account, resolve: RefsToResolveStrict<V, R> }
]) {}
function
subscribeToCoValue<V, R>(cls, id, options, listener):
{}
() => void
function fn(...args: [
cls: CoValueClass<V>,
id: ID<CoValue>,
options: { loadAs: AnonymousJazzAgent | Account, resolve: RefsToResolveStrict<V, R>, onUnavailable: () => void, onUnauthorized: () => void, syncResolution: boolean },
listener: SubscribeListener<V, R>
]) {}
class Thing<
Acc extends Account,
P extends JazzContextManagerBaseProps<Acc>
]> {}
type JazzContextManagerAuthProps
type JazzContextManagerAuthPropsundefined = { credentials: AuthCredentials, newAccountProps: { secret: AgentSecret, creationProps: { name: string } } }
function
createAnonymousJazzContext({ peersToLoadFrom, crypto }):
{}
Promise<JazzContextWithAgent>
function fn(...args: [
{ peersToLoadFrom: Peer[], crypto: CryptoProvider }
]) {}
function
createJazzContextFromExistingCredentials<Acc>({ credentials, peersToLoadFrom, crypto, sessionProvider, AccountSchema?, onLogOut? }):
{}
Promise<JazzContextWithAccount<Acc>>
function fn(...args: [
{ credentials: Credentials, peersToLoadFrom: Peer[], crypto: CryptoProvider, sessionProvider: SessionProvider, AccountSchema: AccountClass<Acc>, onLogOut: () => void }
]) {}
function
createJazzContextForNewAccount<Acc>({ creationProps, peersToLoadFrom, crypto, initialAgentSecret?, AccountSchema?, onLogOut? }):
{}
Promise<JazzContextWithAccount<Acc>>
function fn(...args: [
{ creationProps: { name: string }, peersToLoadFrom: Peer[], crypto: CryptoProvider, initialAgentSecret: TODO type templateLiteral, AccountSchema: AccountClass<Acc>, onLogOut: () => Promise<void> }
]) {}
function
createJazzContext<Acc>(options):
{}
Promise<{ authSecretStorage: AuthSecretStorage, node: LocalNode, account: Acc, done: () => void, logOut: () => Promise<void> }>
function fn(...args: [
options: { peersToLoadFrom: Peer[], crypto: CryptoProvider, sessionProvider: SessionProvider, authSecretStorage: AuthSecretStorage, credentials: AuthCredentials, newAccountProps: NewAccountProps, defaultProfileName: string, AccountSchema: AccountClass<Acc> }
]) {}
function
randomSessionProvider(accountID, crypto):
{}
Promise<{ sessionID: TODO type templateLiteral | TODO type templateLiteral, sessionDone: () => void }>
function fn(...args: [
accountID: ID<Account>,
crypto: CryptoProvider
]) {}
type AuthResult
type AuthResultundefined = { type: "new", creationProps: { name: string, anonymous: boolean, other: Record<string, unknown> }, saveCredentials: (credentials: Credentials) => Promise<void>, onSuccess: () => void, onError: (error: Error | string) => void, logOut: () => Promise<void>, initialSecret: AgentSecret } | { type: "existing", credentials: Credentials, onSuccess: () => void, onError: (error: Error | string) => void, logOut: () => Promise<void>, username: string, saveCredentials: (credentials: Credentials) => Promise<void> }
type Credentials
type Credentialsundefined = { accountID: ID<Account>, secret: AgentSecret }
type JazzContextWithAccount
type JazzContextWithAccount<Acc extends Account> = { node: LocalNode, account: Acc, done: () => void, logOut: () => Promise<void> }
type AuthCredentials
type AuthCredentialsundefined = { accountID: ID<Account>, accountSecret: AgentSecret, secretSeed: Uint8Array, provider: "passphrase" | "passkey" | "demo" | "clerk" | "anonymous" | string }
type AuthenticateAccountFunction
type AuthenticateAccountFunctionundefined = (credentials: AuthCredentials) => Promise<void>
type RegisterAccountFunction
type RegisterAccountFunctionundefined = (accountSecret: AgentSecret, creationProps: { name: string }) => Promise<ID<Account>>
type JazzGuestContext
type JazzGuestContextundefined = { guest: AnonymousJazzAgent, node: LocalNode, authenticate: AuthenticateAccountFunction, register: RegisterAccountFunction, logOut: () => void, done: () => void, isAuthenticated: boolean }
type JazzContextType
type JazzContextType<Acc extends Account> = JazzGuestContext | JazzAuthContext<Acc>
type NewAccountProps
type NewAccountPropsundefined = { secret: AgentSecret, creationProps: { name: string } }
type SyncConfig
type SyncConfigundefined = { when: "never", peer: TODO type templateLiteral | TODO type templateLiteral } | { peer: TODO type templateLiteral | TODO type templateLiteral, when: "signedUp" | "always" }
type RegisteredAccount
type RegisteredAccountundefined = TODO type conditional