CoFeeds
CoFeeds are append-only data structures that track entries from different user sessions and accounts. Unlike other CoValues where everyone edits the same data, CoFeeds maintain separate streams for each session.
Each account can have multiple sessions (different browser tabs, devices, or app instances), making CoFeeds ideal for building features like activity logs, presence indicators, and notification systems.
The following examples demonstrate a practical use of CoFeeds:
- Multi-cursors - track user presence on a canvas with multiple cursors and out of bounds indicators
- Reactions - store per-user emoji reaction using a CoFeed
Creating CoFeeds
CoFeeds are defined by specifying the type of items they'll contain, similar to how you define CoLists:
// Define a schema for feed items constActivity =const Activity: co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>import coco.map({map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }>(shape: { timestamp: z.z.ZodDate; action: z.z.ZodLiteral<...>; notes: z.ZodOptional<...>; }): co.Map<...> export maptimestamp: z.z.ZodDatetimestamp:import zz.date(),function date(params?: string | z.z.core.$ZodDateParams): z.z.ZodDate export dateaction: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">action:import zz.literal(["watering", "planting", "harvesting", "maintenance"]),literal<readonly ["watering", "planting", "harvesting", "maintenance"]>(value: readonly ["watering", "planting", "harvesting", "maintenance"], params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<...> (+1 overload) export literalnotes: z.ZodOptional<z.z.ZodString>notes:import zz.optional(optional<z.z.ZodString>(innerType: z.z.ZodString): z.ZodOptional<z.z.ZodString> export optionalimport zz.string()), }); export typefunction string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload) export stringActivity =type Activity = { readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & 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 loadedActivity>; // Define a feed of garden activities constconst Activity: co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>ActivityFeed =const ActivityFeed: co.Feed<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>import coco.feed(feed<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>(element: co.Map<...>): co.Feed<...> export feedActivity); // Create a feed instance constconst Activity: co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>activityFeed =const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>ActivityFeed.const ActivityFeed: co.Feed<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>create([]);CoFeedSchema<CoMapSchema<{ timestamp: ZodDate; action: ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: ZodOptional<ZodString>; }, unknown, Account | Group>>.create(init: readonly (({ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap) | { timestamp: Date; action: "watering" | ... 2 more ... | "maintenance"; notes?: string | undefined; })[], options?: { owner: Group; } | Group): CoFeedInstance<...> (+1 overload)
Ownership
Like other CoValues, you can specify ownership when creating CoFeeds.
constconst teamGroup: GroupteamGroup =class GroupGroup.create();Group.create<Group>(this: CoValueClass<Group>, options?: { owner: Account; } | Account): Groupconst teamGroup: GroupteamGroup.Group.addMember(member: Account, role: AccountRole): void (+3 overloads)addMember(colleagueAccount, "writer"); constconst colleagueAccount: Account | ({ readonly [x: string]: any; } & Account)teamFeed =const teamFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Group | Account>>ActivityFeed.const ActivityFeed: co.Feed<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Group | Account>>create([], {CoFeedSchema<CoMapSchema<{ timestamp: ZodDate; action: ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: ZodOptional<ZodString>; }, unknown, Group | Account>>.create(init: readonly (({ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap) | { timestamp: Date; action: "watering" | ... 2 more ... | "maintenance"; notes?: string | undefined; })[], options?: { owner: Group; } | Group): CoFeedInstance<...> (+1 overload)owner: Groupowner:const teamGroup: GroupteamGroup });
See Groups as permission scopes for more information on how to use groups to control access to CoFeeds.
Reading from CoFeeds
Since CoFeeds are made of entries from users over multiple sessions, you can access entries in different ways - from a specific user's session or from their account as a whole.
Per-Session Access
To retrieve entries from a session:
// Get the feed for a specific session constsessionFeed =const sessionFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>activityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.perSession: { [key: `${RawAccountID}_session_z${string}`]: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>; [key: `sealer_z${string}/signer_z${string}_session_z${string}`]: CoFeedEntry<...>; }The per-session view of this `CoFeed`perSession[const sessionId: `${RawAccountID}_session_z${string}` | `sealer_z${string}/signer_z${string}_session_z${string}`sessionId]; // Latest entry from a sessionvar 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(sessionFeed?.const sessionFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>value?.value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | nullaction: "watering" | "planting" | "harvesting" | "maintenance" | undefinedaction); // "watering"
For convenience, you can also access the latest entry from the current session with inCurrentSession:
// Get the feed for the current session constcurrentSessionFeed =const currentSessionFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | undefinedactivityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.inCurrentSession: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | undefinedThe current session's view of this `CoFeed` This is a shortcut for `this.perSession` where the session ID is the current session ID.inCurrentSession; // Latest entry from the current sessionvar 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(currentSessionFeed?.const currentSessionFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | undefinedvalue?.value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | null | undefinedaction: "watering" | "planting" | "harvesting" | "maintenance" | undefinedaction); // "harvesting"
Per-Account Access
To retrieve entries from a specific account (with entries from all sessions combined) use perAccount:
// Get the feed for a specific account constaccountFeed =const accountFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>activityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.perAccount: { [key: string]: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>; }The per-account view of this `CoFeed`perAccount[const accountId: stringaccountId]; // Latest entry from the accountvar 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(accountFeed.const accountFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>value?.value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | nullaction: "watering" | "planting" | "harvesting" | "maintenance" | undefinedaction); // "watering"
For convenience, you can also access the latest entry from the current account with byMe:
// Get the feed for the current account constmyLatestEntry =const myLatestEntry: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | undefinedactivityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.byMe: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | undefinedThe current account's view of this `CoFeed`byMe; // Latest entry from the current accountvar 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(myLatestEntry?.const myLatestEntry: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | undefinedvalue?.value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | null | undefinedaction: "watering" | "planting" | "harvesting" | "maintenance" | undefinedaction); // "harvesting"
Feed Entries
All Entries
To retrieve all entries from a CoFeed:
// Get the feeds for a specific account and session constaccountFeed =const accountFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>activityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.perAccount: { [key: string]: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>; }The per-account view of this `CoFeed`perAccount[const accountId: stringaccountId]; constsessionFeed =const sessionFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>activityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.perSession: { [key: `${RawAccountID}_session_z${string}`]: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>; [key: `sealer_z${string}/signer_z${string}_session_z${string}`]: CoFeedEntry<...>; }The per-session view of this `CoFeed`perSession[const sessionId: `${RawAccountID}_session_z${string}` | `sealer_z${string}/signer_z${string}_session_z${string}`sessionId]; // Iterate over all entries from the account for (constentry ofconst entry: SingleCoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>accountFeed.const accountFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>all) {all: IterableIterator<SingleCoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>>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(entry.const entry: SingleCoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>value); } // Iterate over all entries from the session for (constvalue: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | nullentry ofconst entry: SingleCoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>sessionFeed.const sessionFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>all) {all: IterableIterator<SingleCoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>>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(entry.const entry: SingleCoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>value); }value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | null
Latest Entry
To retrieve the latest entry from a CoFeed, ie. the last update:
// Get the latest entry from the current account constlatestEntry =const latestEntry: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | undefinedactivityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.byMe: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | undefinedThe current account's view of this `CoFeed`byMe;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(`My last action was ${latestEntry?.const latestEntry: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | undefinedvalue?.value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | null | undefinedaction: "watering" | "planting" | "harvesting" | "maintenance" | undefinedaction}`); // "My last action was harvesting" // Get the latest entry from each account constlatestEntriesByAccount =const latestEntriesByAccount: { accountName: string | undefined; value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | null; }[]var Object: ObjectConstructorProvides functionality common to all JavaScript objects.Object.ObjectConstructor.values<CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>>(o: { ...; } | ArrayLike<...>): CoFeedEntry<...>[] (+1 overload)Returns an array of values of the enumerable own properties of an objectvalues(activityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.perAccount: { [key: string]: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>; }The per-account view of this `CoFeed`perAccount).Array<CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>>.map<{ accountName: string | undefined; value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | null; }>(callbackfn: (value: CoFeedEntry<...>, index: number, array: CoFeedEntry<...>[]) => { ...; }, thisArg?: any): { ...; }[]Calls a defined callback function on each element of an array, and returns an array that contains the results.map(entry => ({entry: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>accountName: string | undefinedaccountName:entry.entry: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>by: Account | nullby?.Account.profile: Profile | null | undefinedprofile?.Profile.name: string | undefinedname,value:value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | nullentry.entry: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>value, }));value: NonNullable<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap> | null
Writing to CoFeeds
CoFeeds are append-only; you can add new items, but not modify existing ones. This creates a chronological record of events or activities.
Adding Items
// Log a new activityactivityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>$jazz.CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.$jazz: CoFeedJazzApi<CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>>CoFeedJazzApi<CoFeedInstance<CoMapSchema<{ timestamp: ZodDate; action: ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: ZodOptional<ZodString>; }, unknown, Account | Group>>>.push(...items: (({ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap) | CoMapInit<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>)[]): voidPush items to this `CoFeed` Items are appended to the current session's log. Each session (tab, device, app instance) maintains its own append-only log, which is then aggregated into the per-account view.push(Activity.const Activity: co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>create({CoMapSchema<{ timestamp: ZodDate; action: ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: ZodOptional<ZodString>; }, unknown, Account | Group>.create(init: { timestamp: Date; action: "watering" | "planting" | "harvesting" | "maintenance"; notes?: string | undefined; }, options?: { owner?: Group; unique?: CoValueUniqueness["uniqueness"]; } | Group): { ...; } & CoMap (+1 overload)timestamp: Datetimestamp: newDate(),var Date: DateConstructor new () => Date (+4 overloads)action: "watering" | "planting" | "harvesting" | "maintenance"action: "watering",notes?: string | undefinednotes: "Extra water for new seedlings" }));
Each item is automatically associated with the current user's session. You don't need to specify which session the item belongs to - Jazz handles this automatically.
Understanding Session Context
Each entry is automatically added to the current session's feed. When a user has multiple open sessions (like both a mobile app and web browser), each session creates its own separate entries:
// On mobile device:fromMobileFeed.const fromMobileFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>$jazz.CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.$jazz: CoFeedJazzApi<CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>>CoFeedJazzApi<CoFeedInstance<CoMapSchema<{ timestamp: ZodDate; action: ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: ZodOptional<ZodString>; }, unknown, Account | Group>>>.push(...items: (({ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap) | CoMapInit<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>)[]): voidPush items to this `CoFeed` Items are appended to the current session's log. Each session (tab, device, app instance) maintains its own append-only log, which is then aggregated into the per-account view.push(Activity.const Activity: co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>create({CoMapSchema<{ timestamp: ZodDate; action: ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: ZodOptional<ZodString>; }, unknown, Account | Group>.create(init: { timestamp: Date; action: "watering" | "planting" | "harvesting" | "maintenance"; notes?: string | undefined; }, options?: { owner?: Group; unique?: CoValueUniqueness["uniqueness"]; } | Group): { ...; } & CoMap (+1 overload)timestamp: Datetimestamp: newDate(),var Date: DateConstructor new () => Date (+4 overloads)action: "watering" | "planting" | "harvesting" | "maintenance"action: "harvesting",notes?: string | undefinednotes: "Vegetable patch" })); // On web browser (same user):fromBrowserFeed.const fromBrowserFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>$jazz.CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.$jazz: CoFeedJazzApi<CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>>CoFeedJazzApi<CoFeedInstance<CoMapSchema<{ timestamp: ZodDate; action: ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: ZodOptional<ZodString>; }, unknown, Account | Group>>>.push(...items: (({ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap) | CoMapInit<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>)[]): voidPush items to this `CoFeed` Items are appended to the current session's log. Each session (tab, device, app instance) maintains its own append-only log, which is then aggregated into the per-account view.push(Activity.const Activity: co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>create({CoMapSchema<{ timestamp: ZodDate; action: ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: ZodOptional<ZodString>; }, unknown, Account | Group>.create(init: { timestamp: Date; action: "watering" | "planting" | "harvesting" | "maintenance"; notes?: string | undefined; }, options?: { owner?: Group; unique?: CoValueUniqueness["uniqueness"]; } | Group): { ...; } & CoMap (+1 overload)timestamp: Datetimestamp: newDate(),var Date: DateConstructor new () => Date (+4 overloads)action: "watering" | "planting" | "harvesting" | "maintenance"action: "planting",notes?: string | undefinednotes: "Flower bed" })); // These are separate entries in the same feed, from the same account
Metadata
CoFeeds support metadata, which is useful for tracking information about the feed itself.
By
The by property is the account that made the entry.
constaccountFeed =const accountFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>activityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.perAccount: { [key: string]: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>; }The per-account view of this `CoFeed`perAccount[const accountId: stringaccountId]; // Get the account that made the last entryvar 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(accountFeed?.const accountFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>by: Account | nullby);
MadeAt
The madeAt property is a timestamp of when the entry was added to the feed.
constaccountFeed =const accountFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>activityFeed.const activityFeed: CoFeedInstance<co.Map<{ timestamp: z.z.ZodDate; action: z.z.ZodLiteral<"watering" | "planting" | "harvesting" | "maintenance">; notes: z.ZodOptional<z.z.ZodString>; }, unknown, Account | Group>>CoFeed<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>.perAccount: { [key: string]: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>; }The per-account view of this `CoFeed`perAccount[const accountId: stringaccountId]; // Get the timestamp of the last updatevar 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(accountFeed?.const accountFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>madeAt: DatemadeAt); // Get the timestamp of each entry for (constentry ofconst entry: SingleCoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>accountFeed.const accountFeed: CoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>all) {all: IterableIterator<SingleCoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>>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(entry.const entry: SingleCoFeedEntry<{ readonly timestamp: Date; readonly action: "watering" | "planting" | "harvesting" | "maintenance"; readonly notes: string | undefined; } & CoMap>madeAt: DatemadeAt); }
Best Practices
When to Use CoFeeds
- 
Use CoFeeds when: - You need to track per-user/per-session data
- Time-based information matters (activity logs, presence)
 
- 
Consider alternatives when: - Data needs to be collaboratively edited (use CoMaps or CoLists)
- You need structured relationships (use CoMaps/CoLists with references)