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: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
Task) { const
type Task = { title: string; 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); for (const
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
const field: string
field ofconst fields: string[]
fields) { constconst editField: "title" | "status"
editField =const field: string
field as keyof typeoftask.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits; if (!
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
task.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits[
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
const editField: "title" | "status"
editField]) continue; for (constconst edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit oftask.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits[
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
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: { title: string; 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 (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.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: ({ name: string; status: "todo" | "in-progress" | "completed"; } & CoMap)[]
Project[],
type Project = { name: string; status: "todo" | "in-progress" | "completed"; } & CoMap
since: Date
since: Date) { constconst activity: any[]
activity = []; for (constproject of
const project: { name: string; status: "todo" | "in-progress" | "completed"; } & CoMap
projects) { // Get all fields that might have edits const
projects: ({ name: string; 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 for (const
const project: { name: string; status: "todo" | "in-progress" | "completed"; } & CoMap
const field: string
field ofconst fields: string[]
fields) { constconst editField: "name" | "status"
editField =const field: string
field as keyof typeofproject.
const project: { name: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits; // Skip if no edits exist for this field if (!
CoMap._edits: { name?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
project.
const project: { name: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits[
CoMap._edits: { name?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
const editField: "name" | "status"
editField]) continue; for (constconst edit: CoMapEdit<string> | CoMapEdit<"todo" | "in-progress" | "completed">
edit ofproject.
const project: { name: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits[
CoMap._edits: { name?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
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: { name: string; 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: ({ name: string; 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: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
Task) { // Find the most recent edit across all fields let
type Task = { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
let lastEdit: any
lastEdit: any = null; 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: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
const editField: "title" | "status"
editField =const field: string
field as keyof typeoftask.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits; // Skip if no edits exist for this field if (!
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
task.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits[
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
const editField: "title" | "status"
editField]) continue; constconst fieldEdit: LastAndAllCoMapEdits<string> | LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
fieldEdit =task.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits[
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
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: { title: string; 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 (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.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: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
Task): Date | null { if (!
type Task = { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
task.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits.
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
status) 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 =task.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits.
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
status.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: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
Task): Date | null { if (!
type Task = { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
task.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits.
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
status) return null; // Reverse and find (stops at first match) constconst latestCompletionEdit: CoMapEdit<"todo" | "in-progress" | "completed"> | undefined
latestCompletionEdit =task.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits.
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
status.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 (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.log(function findCompletionTime(task: Task): Date | null
findCompletionTime(task)); // First completion
const task: { title: string; 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 (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.log(function findLatestCompletionTime(task: Task): Date | null
findLatestCompletionTime(task)); // Most recent completion // Find who made a specific change function
const task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
function findWhoChanged(task: Task, field: string, value: any): Account | null
findWhoChanged(task:
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
Task,
type Task = { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
field: string
field: string,value: any
value: any) { constconst edits: LastAndAllCoMapEdits<string> | LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
edits =task.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits[
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
field: string
field as keyof typeoftask.
task: { title: string; status: "todo" | "in-progress" | "completed"; } & CoMap
_edits]; if (!
CoMap._edits: { title?: LastAndAllCoMapEdits<string> | undefined; status?: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined; }
const edits: LastAndAllCoMapEdits<string> | LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefined
edits) return null; constconst matchingEdit: CoMapEdit<string> | undefined
matchingEdit =const edits: LastAndAllCoMapEdits<string> | LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">
edits.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: { title: string; 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 (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v20.x/api/util.html#utilformatformat-args) for more information.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