ImageDefinition
ImageDefinition
is a specialized CoValue designed specifically for managing images in Jazz applications. It extends beyond basic file storage by supporting multiple resolutions of the same image and progressive loading patterns.
We also offer createImage()
, a higher-level function to create an ImageDefinition
from a file.
If you're building with React, we recommend starting with our React-specific image documentation which covers higher-level components and hooks for working with images.
The Image Upload example demonstrates use of ImageDefinition
.
Creating Images
The easiest way to create and use images in your Jazz application is with the createImage()
function:
import {
createImage } from "jazz-browser-media-images"; // Create an image from a file input async function
function createImage(imageBlobOrFile: Blob | File, options?: { owner?: Group | Account; maxSize?: 256 | 1024 | 2048; }): Promise<co.loaded<typeof ImageDefinition>>
function handleFileUpload(event: Event): Promise<void>
handleFileUpload(event: Event
event: Event) { constconst file: File | undefined
file = (event: Event
event.Event.target: EventTarget | null
Returns the object to which event is dispatched (its target). [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target)target as HTMLInputElement).HTMLInputElement.files: FileList | null
Returns a FileList object on a file type input object. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLInputElement/files)files?.[0]; if (const file: File | undefined
file) { // Creates ImageDefinition with multiple resolutions automatically constimage = await
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
createImage(
function createImage(imageBlobOrFile: Blob | File, options?: { owner?: Group | Account; maxSize?: 256 | 1024 | 2048; }): Promise<co.loaded<typeof ImageDefinition>>
const file: File
file, {owner?: Group | Account | undefined
owner:const myGroup: Group
myGroup }); // Store the image in your application datame.
const me: AccountInstance<{ root: CoMapSchema<{}>; profile: CoProfileSchema<{ name: z.z.ZodString; image: z.ZodOptional<WithHelpers<CoMapSchema<{ originalSize: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; placeholderDataURL: z.ZodOptional<z.z.ZodString>; }, z.z.core.$catchall<...>, Group | Account>, { ...; }>>; }>; }>
profile.
Account.profile: { name: string; image: ({ originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap) | undefined; inbox: string | undefined; inboxInvite: string | undefined; } & CoMap & Profile
image =
image: ({ originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap) | undefined
image; } }
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
Note: createImage()
requires a browser environment as it uses browser APIs to process images.
The createImage()
function:
- Creates an
ImageDefinition
with the right properties - Generates a small placeholder for immediate display
- Creates multiple resolution variants of your image
- Returns the ID of the created
ImageDefinition
Configuration Options
You can configure createImage()
with additional options:
// Configuration options const
options = {
const options: { owner: Account | ({ [x: string]: any; } & Account); maxSize: 1024; }
owner:
owner: Account | ({ [x: string]: any; } & Account)
me, // Owner for access control
const me: Account | ({ [x: string]: any; } & Account)
maxSize: 1024
maxSize: 1024 as 1024 // Maximum resolution to generate }; // Setting maxSize controls which resolutions are generated: // 256: Only creates the smallest resolution (256px on longest side) // 1024: Creates 256px and 1024px resolutions // 2048: Creates 256px, 1024px, and 2048px resolutions // undefined: Creates all resolutions including the original size constimage = await
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
createImage(
function createImage(imageBlobOrFile: Blob | File, options?: { owner?: Group | Account; maxSize?: 256 | 1024 | 2048; }): Promise<Loaded<typeof ImageDefinition>>
const file: File
file,options);
const options: { owner: Account | ({ [x: string]: any; } & Account); maxSize: 1024; }
Ownership
Like other CoValues, you can specify ownership when creating image definitions.
const
const teamGroup: Group
teamGroup =class Group
Group.create();
Group.create<Group>(this: CoValueClass<Group>, options?: { owner: Account; } | Account): Group
const teamGroup: Group
teamGroup.Group.addMember(member: Account, role: AccountRole): void (+1 overload)
addMember(colleagueAccount, "writer"); // Create an image with shared ownership const
const colleagueAccount: Account | ({ [x: string]: any; } & Account)
teamImage = await
const teamImage: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
createImage(
function createImage(imageBlobOrFile: Blob | File, options?: { owner?: Group | Account; maxSize?: 256 | 1024 | 2048; }): Promise<Loaded<typeof ImageDefinition>>
const file: File
file, {owner?: Group | Account | undefined
owner:const teamGroup: Group
teamGroup });
See Groups as permission scopes for more information on how to use groups to control access to images.
Creating ImageDefinitions
Create an ImageDefinition
by specifying the original dimensions and an optional placeholder:
import {
ImageDefinition } from "jazz-tools"; // Create with original dimensions const
type ImageDefinition = { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap const ImageDefinition: WithHelpers<CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<...>, Account | Group>, { ...; }>
image =
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
ImageDefinition.
const ImageDefinition: WithHelpers<CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<...>, Account | Group>, { ...; }>
create({
create: (init: { placeholderDataURL?: string | undefined; originalSize: [number, number]; }, options?: Account | Group | { owner: Account | Group; unique?: CoValueUniqueness["uniqueness"]; } | undefined) => { ...; } & ... 1 more ... & CoMap
originalSize: [number, number]
originalSize: [1920, 1080], }); // With a placeholder for immediate display constimageWithPlaceholder =
const imageWithPlaceholder: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
ImageDefinition.
const ImageDefinition: WithHelpers<CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<...>, Account | Group>, { ...; }>
create({
create: (init: { placeholderDataURL?: string | undefined; originalSize: [number, number]; }, options?: Account | Group | { owner: Account | Group; unique?: CoValueUniqueness["uniqueness"]; } | undefined) => { ...; } & ... 1 more ... & CoMap
originalSize: [number, number]
originalSize: [1920, 1080],placeholderDataURL?: string | undefined
placeholderDataURL: "data:image/jpeg;base64,/9j/4AAQSkZJ...", });
Structure
ImageDefinition
stores:
- The original image dimensions (
originalSize
) - An optional placeholder (
placeholderDataURL
, typically a tiny base64-encoded preview) - Multiple resolution variants of the same image as
FileStream
s
Each resolution is stored with a key in the format "widthxheight"
(e.g., "1920x1080"
, "800x450"
).
import {
ImageDefinition,
type ImageDefinition = { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap const ImageDefinition: WithHelpers<CoMapSchema<{ originalSize: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; placeholderDataURL: z.ZodOptional<z.z.ZodString>; }, z.z.core.$catchall<...>, Account | Group>, { ...; }>
import co
co,import z
z } from "jazz-tools"; constGallery =
const Gallery: CoMapSchema<{ title: z.z.ZodString; images: CoListSchema<WithHelpers<CoMapSchema<{ originalSize: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; placeholderDataURL: z.ZodOptional<z.z.ZodString>; }, z.z.core.$catchall<...>, Account | Group>, { ...; }>>; }>
import co
co.map({
map<{ title: z.z.ZodString; images: CoListSchema<WithHelpers<CoMapSchema<{ originalSize: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; placeholderDataURL: z.ZodOptional<z.z.ZodString>; }, z.z.core.$catchall<...>, Account | Group>, { ...; }>>; }>(shape: { title: z.z.ZodString; images: CoListSchema<WithHelpers<CoMapSchema<{ originalSize: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; placeholderDataURL: z.ZodOptional<z.z.ZodString>; }, z.z.core.$catchall<...>, Account | Group>, { ...; }>>; }): CoMapSchema<...> export map
title: z.z.ZodString
title:import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
images:
images: CoListSchema<WithHelpers<CoMapSchema<{ originalSize: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; placeholderDataURL: z.ZodOptional<z.z.ZodString>; }, z.z.core.$catchall<...>, Account | Group>, { ...; }>>
import co
co.list(
list<WithHelpers<CoMapSchema<{ originalSize: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; placeholderDataURL: z.ZodOptional<z.z.ZodString>; }, z.z.core.$catchall<...>, Account | Group>, { ...; }>>(element: WithHelpers<...>): CoListSchema<...> export list
import co
co.image()), });
function image(): typeof ImageDefinition export image
Adding Image Resolutions
Add multiple resolutions to an ImageDefinition
by creating FileStream
s for each size:
// Create FileStreams for different resolutions const
const fullRes: FileStream
fullRes = awaitclass FileStream
FileStreams are `CoFeed`s that contain binary data, collaborative versions of `Blob`s.FileStream.
FileStream.createFromBlob(blob: Blob | File, options?: { owner?: Group | Account; onProgress?: (progress: number) => void; } | Account | Group): Promise<FileStream>
Create a `FileStream` from a `Blob` or `File`createFromBlob(const fullSizeBlob: Blob
fullSizeBlob); constconst mediumRes: FileStream
mediumRes = awaitclass FileStream
FileStreams are `CoFeed`s that contain binary data, collaborative versions of `Blob`s.FileStream.
FileStream.createFromBlob(blob: Blob | File, options?: { owner?: Group | Account; onProgress?: (progress: number) => void; } | Account | Group): Promise<FileStream>
Create a `FileStream` from a `Blob` or `File`createFromBlob(const mediumSizeBlob: Blob
mediumSizeBlob); constconst thumbnailRes: FileStream
thumbnailRes = awaitclass FileStream
FileStreams are `CoFeed`s that contain binary data, collaborative versions of `Blob`s.FileStream.
FileStream.createFromBlob(blob: Blob | File, options?: { owner?: Group | Account; onProgress?: (progress: number) => void; } | Account | Group): Promise<FileStream>
Create a `FileStream` from a `Blob` or `File`createFromBlob(const thumbnailBlob: Blob
thumbnailBlob); // Add to the ImageDefinition with appropriate resolution keysimage["1920x1080"] =
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
const fullRes: FileStream
fullRes;image["800x450"] =
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
const mediumRes: FileStream
mediumRes;image["320x180"] =
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
const thumbnailRes: FileStream
thumbnailRes;
Retrieving Images
The highestResAvailable
method helps select the best image resolution for the current context:
// Get highest resolution available (unconstrained) const
highestRes =
const highestRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
ImageDefinition.
const ImageDefinition: WithHelpers<CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<...>, Account | Group>, { ...; }>
highestResAvailable(
function highestResAvailable(imageDef: Loaded<import("/vercel/path0/packages/jazz-tools/dist/internal").CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<import("/vercel/path0/packages/jazz-tools/dist/internal").FileStreamSchema>, import("/vercel/path0/packages/jazz-tools/dist/internal").Account | import("/vercel/path0/packages/jazz-tools/dist/internal").Group>>, options?: { maxWidth?: number; targetWidth?: number; }): { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
image);
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & 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(highestRes); if (
const highestRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
highestRes) { const
const highestRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
const blob: Blob | undefined
blob =highestRes.
const highestRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; }
stream: FileStream
stream.toBlob(); if (
FileStream.toBlob(options?: { allowUnfinished?: boolean; }): Blob | undefined
const blob: Blob | undefined
blob) { // Create a URL for the blob constconst url: string
url =
var URL: { new (url: string | URL, base?: string | URL): URL; prototype: URL; canParse(url: string | URL, base?: string | URL): boolean; createObjectURL(obj: Blob | MediaSource): string; parse(url: string | URL, base?: string | URL): URL | null; revokeObjectURL(url: string): void; }
The URL interface represents an object providing static methods used for creating object URLs. [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) `URL` class is a global reference for `import { URL } from 'node:url'` https://nodejs.org/api/url.html#the-whatwg-url-apiURL.function createObjectURL(obj: Blob | MediaSource): string
[MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/createObjectURL_static)createObjectURL(const blob: Blob
blob);const imageElement: HTMLImageElement
imageElement.HTMLImageElement.src: string
The address or URL of the a media resource that is to be considered. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLImageElement/src)src =const url: string
url; // Revoke the URL when the image is loadedconst imageElement: HTMLImageElement
imageElement.GlobalEventHandlers.onload: ((this: GlobalEventHandlers, ev: Event) => any) | null
Fires immediately after the browser loads the object.onload = () =>
var URL: { new (url: string | URL, base?: string | URL): URL; prototype: URL; canParse(url: string | URL, base?: string | URL): boolean; createObjectURL(obj: Blob | MediaSource): string; parse(url: string | URL, base?: string | URL): URL | null; revokeObjectURL(url: string): void; }
The URL interface represents an object providing static methods used for creating object URLs. [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) `URL` class is a global reference for `import { URL } from 'node:url'` https://nodejs.org/api/url.html#the-whatwg-url-apiURL.function revokeObjectURL(url: string): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL_static)revokeObjectURL(const url: string
url); } } // Get appropriate resolution for specific width constappropriateRes =
const appropriateRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
ImageDefinition.
const ImageDefinition: WithHelpers<CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<...>, Account | Group>, { ...; }>
highestResAvailable(
function highestResAvailable(imageDef: Loaded<import("/vercel/path0/packages/jazz-tools/dist/internal").CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<import("/vercel/path0/packages/jazz-tools/dist/internal").FileStreamSchema>, import("/vercel/path0/packages/jazz-tools/dist/internal").Account | import("/vercel/path0/packages/jazz-tools/dist/internal").Group>>, options?: { maxWidth?: number; targetWidth?: number; }): { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
image, {
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
targetWidth?: number | undefined
targetWidth:var window: Window & typeof globalThis
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/window)window.innerWidth: number
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/innerWidth)innerWidth, });
Fallback Behavior
highestResAvailable
returns the largest resolution that fits your constraints. If a resolution has incomplete data, it falls back to the next available lower resolution.
const
image =
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
ImageDefinition.
const ImageDefinition: WithHelpers<CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<...>, Account | Group>, { ...; }>
create({
create: (init: { placeholderDataURL?: string | undefined; originalSize: [number, number]; }, options?: Account | Group | { owner: Account | Group; unique?: CoValueUniqueness["uniqueness"]; } | undefined) => { ...; } & ... 1 more ... & CoMap
originalSize: [number, number]
originalSize: [1920, 1080], });image["1920x1080"] =
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
class FileStream
FileStreams are `CoFeed`s that contain binary data, collaborative versions of `Blob`s.FileStream.
FileStream.create<FileStream>(this: CoValueClass<FileStream>, options?: { owner?: Account | Group; } | Account | Group): FileStream
Create a new empty `FileStream` instance.create(); // Empty image uploadimage["800x450"] = await
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
class FileStream
FileStreams are `CoFeed`s that contain binary data, collaborative versions of `Blob`s.FileStream.
FileStream.createFromBlob(blob: Blob | File, options?: { owner?: Group | Account; onProgress?: (progress: number) => void; } | Account | Group): Promise<FileStream>
Create a `FileStream` from a `Blob` or `File`createFromBlob(const mediumSizeBlob: Blob
mediumSizeBlob); consthighestRes =
const highestRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
ImageDefinition.
const ImageDefinition: WithHelpers<CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<...>, Account | Group>, { ...; }>
highestResAvailable(
function highestResAvailable(imageDef: Loaded<import("/vercel/path0/packages/jazz-tools/dist/internal").CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<import("/vercel/path0/packages/jazz-tools/dist/internal").FileStreamSchema>, import("/vercel/path0/packages/jazz-tools/dist/internal").Account | import("/vercel/path0/packages/jazz-tools/dist/internal").Group>>, options?: { maxWidth?: number; targetWidth?: number; }): { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
image);
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & 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(highestRes?.
const highestRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
res: `${number}x${number}` | undefined
res); // 800x450
Progressive Loading Patterns
ImageDefinition
supports simple progressive loading with placeholders and resolution selection:
// Start with placeholder for immediate display if (
image.
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
placeholderDataURL: string | undefined
placeholderDataURL) {const imageElement: HTMLImageElement
imageElement.HTMLImageElement.src: string
The address or URL of the a media resource that is to be considered. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLImageElement/src)src =image.
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
placeholderDataURL: string
placeholderDataURL; } // Then load the best resolution for the current display constconst screenWidth: number
screenWidth =var window: Window & typeof globalThis
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/window)window.innerWidth: number
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/innerWidth)innerWidth; constbestRes =
const bestRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
ImageDefinition.
const ImageDefinition: WithHelpers<CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<...>, Account | Group>, { ...; }>
highestResAvailable(
function highestResAvailable(imageDef: Loaded<import("/vercel/path0/packages/jazz-tools/dist/internal").CoMapSchema<{ originalSize: ZodTuple<[ZodNumber, ZodNumber], null>; placeholderDataURL: ZodOptional<ZodString>; }, $catchall<import("/vercel/path0/packages/jazz-tools/dist/internal").FileStreamSchema>, import("/vercel/path0/packages/jazz-tools/dist/internal").Account | import("/vercel/path0/packages/jazz-tools/dist/internal").Group>>, options?: { maxWidth?: number; targetWidth?: number; }): { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
image, {
const image: { originalSize: [number, number]; placeholderDataURL: string | undefined; } & { [key: string]: FileStream; } & CoMap
targetWidth?: number | undefined
targetWidth:const screenWidth: number
screenWidth, }); if (bestRes) { const
const bestRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; } | undefined
const blob: Blob | undefined
blob =bestRes.
const bestRes: { res: `${number}x${number}`; stream: import("/vercel/path0/packages/jazz-tools/dist/coValues/coFeed").BinaryCoStream; }
stream: FileStream
stream.toBlob(); if (
FileStream.toBlob(options?: { allowUnfinished?: boolean; }): Blob | undefined
const blob: Blob | undefined
blob) { constconst url: string
url =
var URL: { new (url: string | URL, base?: string | URL): URL; prototype: URL; canParse(url: string | URL, base?: string | URL): boolean; createObjectURL(obj: Blob | MediaSource): string; parse(url: string | URL, base?: string | URL): URL | null; revokeObjectURL(url: string): void; }
The URL interface represents an object providing static methods used for creating object URLs. [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) `URL` class is a global reference for `import { URL } from 'node:url'` https://nodejs.org/api/url.html#the-whatwg-url-apiURL.function createObjectURL(obj: Blob | MediaSource): string
[MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/createObjectURL_static)createObjectURL(const blob: Blob
blob);const imageElement: HTMLImageElement
imageElement.HTMLImageElement.src: string
The address or URL of the a media resource that is to be considered. [MDN Reference](https://developer.mozilla.org/docs/Web/API/HTMLImageElement/src)src =const url: string
url; // Remember to revoke the URL when no longer neededconst imageElement: HTMLImageElement
imageElement.GlobalEventHandlers.onload: ((this: GlobalEventHandlers, ev: Event) => any) | null
Fires immediately after the browser loads the object.onload = () => {
var URL: { new (url: string | URL, base?: string | URL): URL; prototype: URL; canParse(url: string | URL, base?: string | URL): boolean; createObjectURL(obj: Blob | MediaSource): string; parse(url: string | URL, base?: string | URL): URL | null; revokeObjectURL(url: string): void; }
The URL interface represents an object providing static methods used for creating object URLs. [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL) `URL` class is a global reference for `import { URL } from 'node:url'` https://nodejs.org/api/url.html#the-whatwg-url-apiURL.function revokeObjectURL(url: string): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/revokeObjectURL_static)revokeObjectURL(const url: string
url); }; } }
Best Practices
- Generate resolutions server-side when possible for optimal quality
- Use placeholders (like LQIP - Low Quality Image Placeholders) for instant rendering
- Prioritize loading the resolution appropriate for the current viewport
- Consider device pixel ratio (window.devicePixelRatio) for high-DPI displays
- Always call URL.revokeObjectURL after the image loads to prevent memory leaks