History Patterns
Jazz's automatic history tracking enables powerful patterns for building collaborative features. Here's how to implement common history-based functionality.
Audit Logs
Build a complete audit trail showing all changes to your data:
function
getAuditLog(
function getAuditLog(task: Task): { field: string; value: string | undefined; by: Account | null; at: Date; }[]
task:
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
Task) { const
type Task = { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
const changes: any[]
changes = []; // Collect edits for all fields constconst fields: string[]
fields =var Object: ObjectConstructor
Provides functionality common to all JavaScript objects.Object.ObjectConstructor.keys(o: {}): string[] (+1 overload)
Returns the names of the enumerable string properties and methods of an object.keys(task); const
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
edits =
const edits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
task.
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
CoMap.$jazz: CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Jazz methods for CoMaps are inside this property. This allows CoMaps to be used as plain objects while still having access to Jazz methods, and also doesn't limit which key names can be used inside CoMaps.$jazz.
CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>.getEdits(): CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Get the edits made to the CoMap.getEdits(); for (constconst field: string
field ofconst fields: string[]
fields) { constconst editField: "title" | "status"
editField =const field: string
field as keyof typeofedits; if (!
const edits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
edits[
const edits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
const editField: "title" | "status"
editField]) continue; for (constconst edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit ofedits[
const edits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
const editField: "title" | "status"
editField].all: CoMapEdit<string>[] | CoMapEdit<"todo" | "in-progress" | "completed">[]
all) {const changes: any[]
changes.Array<any>.push(...items: any[]): number
Appends new elements to the end of an array, and returns the new length of the array.push({field: string
field,value: string | undefined
value:const edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit.value?: string | undefined
value,by: Account | null
by:const edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit.by: Account | null
by,at: Date
at:const edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit.madeAt: Date
madeAt, }); } } // Sort by timestamp (newest first) returnchanges.
const changes: { field: string; value: string | undefined; by: Account | null; at: Date; }[]
Array<{ field: string; value: string | undefined; by: Account | null; at: Date; }>.sort(compareFn?: ((a: { field: string; value: string | undefined; by: Account | null; at: Date; }, b: { field: string; value: string | undefined; by: Account | null; at: Date; }) => number) | undefined): { field: string; value: string | undefined; by: Account | null; at: Date; }[]
Sorts an array in place. This method mutates the array and returns a reference to the same array.sort((a,
a: { field: string; value: string | undefined; by: Account | null; at: Date; }
b) =>
b: { field: string; value: string | undefined; by: Account | null; at: Date; }
b.
b: { field: string; value: string | undefined; by: Account | null; at: Date; }
at: Date
at.Date.getTime(): number
Returns the stored time value in milliseconds since midnight, January 1, 1970 UTC.getTime() -a.
a: { field: string; value: string | undefined; by: Account | null; at: Date; }
at: Date
at.Date.getTime(): number
Returns the stored time value in milliseconds since midnight, January 1, 1970 UTC.getTime()); } // Use it to show change history constauditLog =
const auditLog: { field: string; value: string | undefined; by: Account | null; at: Date; }[]
getAuditLog(
function getAuditLog(task: Task): { field: string; value: string | undefined; by: Account | null; at: Date; }[]
task);
const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
auditLog.
const auditLog: { field: string; value: string | undefined; by: Account | null; at: Date; }[]
Array<{ field: string; value: string | undefined; by: Account | null; at: Date; }>.forEach(callbackfn: (value: { field: string; value: string | undefined; by: Account | null; at: Date; }, index: number, array: { field: string; value: string | undefined; by: Account | null; at: Date; }[]) => void, thisArg?: any): void
Performs the specified action for each element in an array.forEach((entry) => { const
entry: { field: string; value: string | undefined; by: Account | null; at: Date; }
const when: string
when =entry.
entry: { field: string; value: string | undefined; by: Account | null; at: Date; }
at: Date
at.Date.toLocaleString(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string (+2 overloads)
Converts a date and time to a string by using the current or specified locale.toLocaleString(); constconst who: string | undefined
who =entry.
entry: { field: string; value: string | undefined; by: Account | null; at: Date; }
by: Account | null
by?.Account.profile: Profile | null | undefined
profile?.Profile.name: string | undefined
name; constconst what: string
what =entry.
entry: { field: string; value: string | undefined; by: Account | null; at: Date; }
field: string
field; constconst value: string | undefined
value =entry.
entry: { field: string; value: string | undefined; by: Account | null; at: Date; }
value: string | undefined
value;var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```console.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(`${const when: string
when} - ${const who: string | undefined
who} changed ${const what: string
what} to "${const value: string | undefined
value}"`); // 22/05/2025, 12:00:00 - Alice changed title to "New task" });
Activity Feeds
Show recent activity across your application:
function
getRecentActivity(
function getRecentActivity(projects: Project[], since: Date): { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }[]
projects:
projects: ({ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap)[]
Project[],
type Project = { readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
since: Date
since: Date) { constconst activity: any[]
activity = []; for (constproject of
const project: { readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
projects) { // Get all fields that might have edits const
projects: ({ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap)[]
const fields: string[]
fields =var Object: ObjectConstructor
Provides functionality common to all JavaScript objects.Object.ObjectConstructor.keys(o: {}): string[] (+1 overload)
Returns the names of the enumerable string properties and methods of an object.keys(project); // Check each field for edit history const
const project: { readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
edits =
const edits: CoMapEdits<{ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
project.
const project: { readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
CoMap.$jazz: CoMapJazzApi<{ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Jazz methods for CoMaps are inside this property. This allows CoMaps to be used as plain objects while still having access to Jazz methods, and also doesn't limit which key names can be used inside CoMaps.$jazz.
CoMapJazzApi<{ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>.getEdits(): CoMapEdits<{ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Get the edits made to the CoMap.getEdits(); for (constconst field: string
field ofconst fields: string[]
fields) { constconst editField: "name" | "status"
editField =const field: string
field as keyof typeofedits; // Skip if no edits exist for this field if (!
const edits: CoMapEdits<{ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
edits[
const edits: CoMapEdits<{ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
const editField: "name" | "status"
editField]) continue; for (constconst edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit ofedits[
const edits: CoMapEdits<{ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
const editField: "name" | "status"
editField].all: CoMapEdit<string>[] | CoMapEdit<"todo" | "in-progress" | "completed">[]
all) { // Only include edits made after the 'since' date if (const edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit.madeAt: Date
madeAt >since: Date
since) {const activity: any[]
activity.Array<any>.push(...items: any[]): number
Appends new elements to the end of an array, and returns the new length of the array.push({project: string
project:project.
const project: { readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
name: string
name,field: string
field,value: string | undefined
value:const edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit.value?: string | undefined
value,by: Account | null
by:const edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit.by: Account | null
by,at: Date
at:const edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit.madeAt: Date
madeAt }); } } } } returnactivity.
const activity: { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }[]
Array<{ project: string; field: string; value: string | undefined; by: Account | null; at: Date; }>.sort(compareFn?: ((a: { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }, b: { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }) => number) | undefined): { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }[]
Sorts an array in place. This method mutates the array and returns a reference to the same array.sort((a,
a: { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }
b) =>
b: { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }
b.
b: { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }
at: Date
at.Date.getTime(): number
Returns the stored time value in milliseconds since midnight, January 1, 1970 UTC.getTime() -a.
a: { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }
at: Date
at.Date.getTime(): number
Returns the stored time value in milliseconds since midnight, January 1, 1970 UTC.getTime()); } // Show activity from the last hour constconst hourAgo: Date
hourAgo = newDate(
var Date: DateConstructor new (value: number | string | Date) => Date (+4 overloads)
var Date: DateConstructor
Enables basic storage and retrieval of dates and times.Date.DateConstructor.now(): number
Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC).now() - 60 * 60 * 1000); constrecentActivity =
const recentActivity: { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }[]
getRecentActivity(
function getRecentActivity(projects: Project[], since: Date): { project: string; field: string; value: string | undefined; by: Account | null; at: Date; }[]
myProjects,
const myProjects: ({ readonly name: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap)[]
const hourAgo: Date
hourAgo); // [{ // project: "New project", // field: "name", // value: "New project", // by: Account, // at: Date // }]
Change Indicators
Show when something was last updated:
function
getLastUpdated(
function getLastUpdated(task: Task): { updatedBy: any; updatedAt: any; message: string; } | null
task:
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
Task) { // Find the most recent edit across all fields let
type Task = { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
let lastEdit: any
lastEdit: any = null; constedits =
const edits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
task.
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
CoMap.$jazz: CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Jazz methods for CoMaps are inside this property. This allows CoMaps to be used as plain objects while still having access to Jazz methods, and also doesn't limit which key names can be used inside CoMaps.$jazz.
CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>.getEdits(): CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Get the edits made to the CoMap.getEdits(); for (constconst field: string
field ofvar Object: ObjectConstructor
Provides functionality common to all JavaScript objects.Object.ObjectConstructor.keys(o: {}): string[] (+1 overload)
Returns the names of the enumerable string properties and methods of an object.keys(task)) { const
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
const editField: "title" | "status"
editField =const field: string
field as keyof typeofedits; // Skip if no edits exist for this field if (!
const edits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
edits[
const edits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
const editField: "title" | "status"
editField]) continue; constconst fieldEdit: LastAndAllCoMapEdits<string> | LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
fieldEdit =edits[
const edits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
const editField: "title" | "status"
editField]; if (const fieldEdit: LastAndAllCoMapEdits<string> | LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
fieldEdit && (!let lastEdit: any
lastEdit ||const fieldEdit: LastAndAllCoMapEdits<string> | LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
fieldEdit.madeAt: Date
madeAt >let lastEdit: any
lastEdit.madeAt)) {let lastEdit: any
lastEdit =const fieldEdit: LastAndAllCoMapEdits<string> | LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
fieldEdit; } } if (!let lastEdit: any
lastEdit) return null; return {updatedBy: any
updatedBy:let lastEdit: any
lastEdit.by?.profile?.name,updatedAt: any
updatedAt:let lastEdit: any
lastEdit.madeAt,message: string
message: `Last updated by ${let lastEdit: any
lastEdit.by?.profile?.name} at ${let lastEdit: any
lastEdit.madeAt.toLocaleString()}` }; } constlastUpdated =
const lastUpdated: { updatedBy: any; updatedAt: any; message: string; } | null
getLastUpdated(
function getLastUpdated(task: Task): { updatedBy: any; updatedAt: any; message: string; } | null
task);
const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```console.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(lastUpdated?.
const lastUpdated: { updatedBy: any; updatedAt: any; message: string; } | null
message: string | undefined
message); // "Last updated by Alice at 22/05/2025, 12:00:00"
Finding Specific Changes
Query history for specific events:
// Find when a task was completed function
function findCompletionTime(task: Task): Date | null
findCompletionTime(task:
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
Task): Date | null { const
type Task = { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
const statusEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
statusEdits =task.
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
CoMap.$jazz: CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Jazz methods for CoMaps are inside this property. This allows CoMaps to be used as plain objects while still having access to Jazz methods, and also doesn't limit which key names can be used inside CoMaps.$jazz.
CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>.getEdits(): CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Get the edits made to the CoMap.getEdits().status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
status; if (!const statusEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
statusEdits) return null; // find() returns the FIRST completion time // If status toggles (completed → in-progress → completed), // this gives you the earliest completion, not the latest constconst completionEdit: CoMapEdit<"todo" | "in-progress" | "completed"> | undefined
completionEdit =const statusEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
statusEdits.all: CoMapEdit<"todo" | "in-progress" | "completed">[]
all.Array<CoMapEdit<"todo" | "in-progress" | "completed">>.find(predicate: (value: CoMapEdit<"todo" | "in-progress" | "completed">, index: number, obj: CoMapEdit<"todo" | "in-progress" | "completed">[]) => unknown, thisArg?: any): CoMapEdit<...> | undefined (+1 overload)
Returns the value of the first element in the array where predicate is true, and undefined otherwise.find(edit: CoMapEdit<"todo" | "in-progress" | "completed">
edit =>edit: CoMapEdit<"todo" | "in-progress" | "completed">
edit.value?: "todo" | "in-progress" | "completed" | undefined
value === "completed" ); returnconst completionEdit: CoMapEdit<"todo" | "in-progress" | "completed"> | undefined
completionEdit?.madeAt: Date | undefined
madeAt || null; } // To get the LATEST completion time instead reverse the array, then find: functionfunction findLatestCompletionTime(task: Task): Date | null
findLatestCompletionTime(task:
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
Task): Date | null { const
type Task = { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
const statusEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
statusEdits =task.
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
CoMap.$jazz: CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Jazz methods for CoMaps are inside this property. This allows CoMaps to be used as plain objects while still having access to Jazz methods, and also doesn't limit which key names can be used inside CoMaps.$jazz.
CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>.getEdits(): CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Get the edits made to the CoMap.getEdits().status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
status; if (!const statusEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
statusEdits) return null; // Reverse and find (stops at first match) constconst latestCompletionEdit: CoMapEdit<"todo" | "in-progress" | "completed"> | undefined
latestCompletionEdit =const statusEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
statusEdits.all: CoMapEdit<"todo" | "in-progress" | "completed">[]
all .Array<CoMapEdit<"todo" | "in-progress" | "completed">>.slice(start?: number, end?: number): CoMapEdit<"todo" | "in-progress" | "completed">[]
Returns a copy of a section of an array. 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.slice() // Create copy to avoid mutating original .Array<CoMapEdit<"todo" | "in-progress" | "completed">>.reverse(): CoMapEdit<"todo" | "in-progress" | "completed">[]
Reverses the elements in an array in place. This method mutates the array and returns a reference to the same array.reverse() .Array<CoMapEdit<"todo" | "in-progress" | "completed">>.find(predicate: (value: CoMapEdit<"todo" | "in-progress" | "completed">, index: number, obj: CoMapEdit<"todo" | "in-progress" | "completed">[]) => unknown, thisArg?: any): CoMapEdit<...> | undefined (+1 overload)
Returns the value of the first element in the array where predicate is true, and undefined otherwise.find(edit: CoMapEdit<"todo" | "in-progress" | "completed">
edit =>edit: CoMapEdit<"todo" | "in-progress" | "completed">
edit.value?: "todo" | "in-progress" | "completed" | undefined
value === "completed"); returnconst latestCompletionEdit: CoMapEdit<"todo" | "in-progress" | "completed"> | undefined
latestCompletionEdit?.madeAt: Date | undefined
madeAt || null; }var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```console.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(function findCompletionTime(task: Task): Date | null
findCompletionTime(task)); // First completion
const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```console.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(function findLatestCompletionTime(task: Task): Date | null
findLatestCompletionTime(task)); // Most recent completion // Find who made a specific change function
const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
function findWhoChanged(task: Task, field: string, value: any): Account | null
findWhoChanged(task:
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
Task,
type Task = { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
field: string
field: string,value: any
value: any) { consttaskEdits =
const taskEdits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
task.
task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
CoMap.$jazz: CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Jazz methods for CoMaps are inside this property. This allows CoMaps to be used as plain objects while still having access to Jazz methods, and also doesn't limit which key names can be used inside CoMaps.$jazz.
CoMapJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>.getEdits(): CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
Get the edits made to the CoMap.getEdits(); constconst fieldEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | LastAndAllCoMapEdits<string> | undefined
fieldEdits =taskEdits[
const taskEdits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
field: string
field as keyof typeoftaskEdits]; if (!
const taskEdits: CoMapEdits<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>
const fieldEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | LastAndAllCoMapEdits<string> | undefined
fieldEdits) return null; constconst matchingEdit: CoMapEdit<string> | undefined
matchingEdit =const fieldEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | LastAndAllCoMapEdits<string>
fieldEdits.all: CoMapEdit<"todo" | "in-progress" | "completed">[] | CoMapEdit<string>[]
all.Array<T>.find(predicate: (value: CoMapEdit<string>, index: number, obj: CoMapEdit<string>[]) => unknown, thisArg?: any): CoMapEdit<string> | undefined
Returns the value of the first element in the array where predicate is true, and undefined otherwise.find(edit: CoMapEdit<string>
edit =>edit: CoMapEdit<string>
edit.value?: string | undefined
value ===value: any
value); returnconst matchingEdit: CoMapEdit<string> | undefined
matchingEdit?.by: Account | null | undefined
by || null; } constconst account: Account | null
account =function findWhoChanged(task: Task, field: string, value: any): Account | null
findWhoChanged(task, "status", "completed");
const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```console.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const account: Account | null
account?.Account.profile: Profile | null | undefined
profile?.Profile.name: string | undefined
name); // Alice
Further Reading
- History - Complete reference for the history API
- Subscription & Loading - Ensure CoValues are loaded before accessing history