History
Jazz tracks every change to your data automatically. See who changed what, when they did it, and even look at your data from any point in the past.
See the version history example for reference.
Let's use the following schema to see how we can use the edit history.
constTask =const Task: co.Map<{ title: z.z.ZodString; status: z.z.ZodLiteral<"todo" | "in-progress" | "completed">; }, unknown, Account | Group>import coco.map({map<{ title: z.z.ZodString; status: z.z.ZodLiteral<"todo" | "in-progress" | "completed">; }>(shape: { title: z.z.ZodString; status: z.z.ZodLiteral<"todo" | "in-progress" | "completed">; }): co.Map<...> export maptitle: z.z.ZodStringtitle:import zz.string(),function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload) export stringstatus: z.z.ZodLiteral<"todo" | "in-progress" | "completed">status:import zz.literal(["todo", "in-progress", "completed"]), }); export typeliteral<readonly ["todo", "in-progress", "completed"]>(value: readonly ["todo", "in-progress", "completed"], params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"todo" | "in-progress" | "completed"> (+1 overload) export literalTask =type Task = { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapimport coco.loaded<typeoftype loaded<T extends CoValueClassOrSchema, R extends ResolveQuery<T> = true> = R extends boolean | undefined ? NonNullable<InstanceOfSchemaCoValuesNullable<T>> : [NonNullable<InstanceOfSchemaCoValuesNullable<T>>] extends [...] ? Exclude<...> extends CoValue ? R extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean ... export loadedTask>;const Task: co.Map<{ title: z.z.ZodString; status: z.z.ZodLiteral<"todo" | "in-progress" | "completed">; }, unknown, Account | Group>
The $jazz.getEdits() method
Every CoValue has a $jazz.getEdits() method that contains the complete history for each field. Here's
how to get the edit history for task.status:
// Access edit history for a fieldtask.const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapCoMap.$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"> | undefinedstatus // Returns the latest edittask.const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapCoMap.$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"> | undefinedstatus?.all: CoMapEdit<"todo" | "in-progress" | "completed">[] | undefinedall // Returns array of all edits in chronological order // Check if edits exist constconst statusEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefinedstatusEdits =task.const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapCoMap.$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"> | undefinedstatus; if (const statusEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefinedstatusEdits) { constconst name: string | undefinedname =const statusEdits: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed">statusEdits.by: Account | nullby?.Account.profile: Profile | null | undefinedprofile?.Profile.name: string | undefinedname;var console: ConsoleThe `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(`Last changed by ${const name: string | undefinedname}`); }
Edit Structure
Each edit contains:
constconst edit: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefinededit =task.const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapCoMap.$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"> | undefinedstatus; // The edit object contains:const edit: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefinededit?.value?: "todo" | "in-progress" | "completed" | undefinedvalue // The new value: "in-progress"const edit: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefinededit?.by: Account | null | undefinedby // Account that made the changeconst edit: LastAndAllCoMapEdits<"todo" | "in-progress" | "completed"> | undefinededit?.madeAt: Date | undefinedmadeAt // Date when the change occurred
Accessing History
Latest Edit
Get the most recent change to a field:
// Direct access to latest edit constconst latest: LastAndAllCoMapEdits<string> | undefinedlatest =task.const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapCoMap.$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().title?: LastAndAllCoMapEdits<string> | undefinedtitle; if (const latest: LastAndAllCoMapEdits<string> | undefinedlatest) {var console: ConsoleThe `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(`Title is now "${const latest: LastAndAllCoMapEdits<string>latest.value?: string | undefinedvalue}"`); }
All Edits
Get the complete history for a field:
// Get all edits (chronologically) constconst allStatusEdits: CoMapEdit<"todo" | "in-progress" | "completed">[]allStatusEdits =task.const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapCoMap.$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"> | undefinedstatus?.all: CoMapEdit<"todo" | "in-progress" | "completed">[] | undefinedall || [];const allStatusEdits: CoMapEdit<"todo" | "in-progress" | "completed">[]allStatusEdits.Array<CoMapEdit<"todo" | "in-progress" | "completed">>.forEach(callbackfn: (value: CoMapEdit<"todo" | "in-progress" | "completed">, index: number, array: CoMapEdit<"todo" | "in-progress" | "completed">[]) => void, thisArg?: any): voidPerforms the specified action for each element in an array.forEach((edit: CoMapEdit<"todo" | "in-progress" | "completed">edit,index: numberindex) => {var console: ConsoleThe `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(`Edit ${index: numberindex}: ${edit: CoMapEdit<"todo" | "in-progress" | "completed">edit.value?: "todo" | "in-progress" | "completed" | undefinedvalue} at ${edit: CoMapEdit<"todo" | "in-progress" | "completed">edit.madeAt: DatemadeAt.Date.toISOString(): stringReturns a date as a string value in ISO format.toISOString()}`); }); // Edit 0: todo at 2025-05-22T13:00:00.000Z // Edit 1: in-progress at 2025-05-22T14:00:00.000Z // Edit 2: completed at 2025-05-22T15:30:00.000Z
Initial Values
The first edit contains the initial value:
constconst allEdits: CoMapEdit<"todo" | "in-progress" | "completed">[]allEdits =task.const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapCoMap.$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"> | undefinedstatus?.all: CoMapEdit<"todo" | "in-progress" | "completed">[] | undefinedall || []; constconst initialValue: "todo" | "in-progress" | "completed" | undefinedinitialValue =const allEdits: CoMapEdit<"todo" | "in-progress" | "completed">[]allEdits[0]?.value?: "todo" | "in-progress" | "completed" | undefinedvalue;var console: ConsoleThe `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(`Started as: ${const initialValue: "todo" | "in-progress" | "completed" | undefinedinitialValue}`); // Started as: todo
Created Date and Last Updated Date
To show created date and last updated date, use the $jazz.createdAt and $jazz.lastUpdatedAt getters.
var console: ConsoleThe `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(newDate(var Date: DateConstructor new (value: number | string | Date) => Date (+4 overloads)task.const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapCoMap.$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.CoValueJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>.createdAt: numberThe timestamp of the creation time of the CoValuecreatedAt));var console: ConsoleThe `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(newDate(var Date: DateConstructor new (value: number | string | Date) => Date (+4 overloads)task.const task: { readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMapCoMap.$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.CoValueJazzApi<{ readonly title: string; readonly status: "todo" | "in-progress" | "completed"; } & CoMap>.lastUpdatedAt: numberThe timestamp of the last updated time of the CoValue Returns the creation time if there are no updates.lastUpdatedAt));
Requirements
- CoValues must be loaded to access history (see Subscription & Loading)
- History is only available for fields defined in your schema
- Edit arrays are ordered chronologically (oldest to newest)
Common Patterns
For practical implementations using history, see History Patterns:
- Building audit logs
- Creating activity feeds
- Implementing undo/redo
- Showing change indicators
- Querying historical data