Skip to content

Blob

import { Blob } from '@dxos/echo';

A blob holds bytes, such as an image or a file. The Blob object stores the hash, size and type of the bytes and where they are; small blobs hold the bytes inline. An object points at a blob with a reference.

import * as
import Schema
Schema
from 'effect/Schema';
import {
import Blob
Blob
,
import DXN
DXN
,
import Ref
Ref
,
import Type
Type
} from '@dxos/echo';
class
class Photo
Photo
extends
import Type
Type
.
const makeObject: <Photo>(dxn: DXN.DXN, options?: {
id?: EntityId;
}) => Type.MakeObject<Photo>

Factory function to create an ECHO object type.

Returns a Type.Type entity — a live, in-memory TypeSchema instance, NOT a Schema.Schema. Use Type.InstanceType<typeof Foo> for the instance type and Type.getSchema(Foo) to obtain the underlying Effect Schema.

The entity's id defaults to EntityId.deterministic(typename, version) so constructing a type never reaches crypto.getRandomValues() — required for Cloudflare workerd, which forbids RNG calls in global (module-evaluation) scope. Pass { id } to override (e.g. with EntityId.random() from a request handler).

Giving the type a nominal class name keeps its inferred type portable for declaration emit: structural expansion (which can pull in unnameable union members from referenced schemas) is replaced by a reference to the class.

The second call takes either a schema, or struct fields (wrapped in Schema.Struct) with an optional function that pipes annotations onto the struct.

@example

export class Person extends Type.makeObject<Person>(DXN.make('com.example.type.myType', '0.1.0'))(Schema.Struct({
name: Schema.String,
})) {}
export class Tag extends Type.makeObject<Tag>(DXN.make('com.example.type.tag', '0.1.0'))(
{ label: Schema.String },
Annotation.LabelAnnotation.set(['label']),
) {}

@performance ― O(schema size) once at definition time; builds the type entity eagerly, so call it at module scope, not per use.

makeObject
<
class Photo
Photo
>(
import DXN
DXN
.
const make: <"com.example.type.photo">(nsid: "com.example.type.photo", version?: string) => DXN.DXN

Constructs a DXN from an NSID (and optional version). Throws if the result is not a valid DXN. Use tryMake for non-throwing string parsing.

Static NSID strings are validated at compile time via

Name

: the final segment must be camelCase (no hyphens). Template-literal strings with a runtime prefix are accepted here but still validated at runtime.

@example make('org.dxos.type.calendar') → 'dxn:org.dxos.type.calendar'

@example make('org.dxos.type.calendar', '1.0.0') → 'dxn:org.dxos.type.calendar:1.0.0'

make
('com.example.type.photo', '0.1.0'),
)({
caption: Schema.String
caption
:
import Schema
Schema
.
const String: Schema.String

Type-level representation of

String

.

Schema for string values. Validates that the input is typeof "string".

@stability ― stable

@category ― models

@since ― 4.0.0

@stability ― stable

@category ― schemas

@since ― 4.0.0

String
,
image: Ref.RefSchema<Blob.Blob & OfKind<EntityKind.Object> & Obj.Unknown>
image
:
import Ref
Ref
.
const Ref: <typeof Blob.Blob>(type: typeof Blob.Blob) => Ref.RefSchema<Blob.Blob & OfKind<EntityKind.Object> & Obj.Unknown> (+3 overloads)
Ref
(
import Blob
Blob
.
class Blob

Runtime schema for a Blob object.

NOTE: This export shadows the DOM Blob global within modules that import it as a namespace. Code that needs the DOM class should use globalThis.Blob explicitly.

@example

const blob = yield* Blob.fromBytes(bytes, { type: 'image/png' });

Blob
),
}) {}

db.createBlob hashes the bytes and uploads them to the storage backend, and returns a Blob object that is not yet in the space. Add it, then reference it. Bytes over the backend’s size limit reject with BlobTooLargeError.

import {
import Obj
Obj
,
import Ref
Ref
} from '@dxos/echo';
// Hashes the bytes and uploads them; the blob is not in the space yet.
const
const blob: Blob.Blob
blob
= await
const db: Database.Database
db
.
Database.createBlob(bytes: Uint8Array, options?: {
type?: string;
storage?: string;
}): Promise<Blob.Blob>

Hashes and uploads bytes via the chosen storage backend, returning an un-added Blob object. Rejects with Error.BlobTooLargeError (over inline storage's fixed cap, or the backend's own maxSize), Error.BlobWriteError (backend upload failure), or Error.BlobNotAvailableError (reason: 'backend-not-registered' — the requested storage name has no registered backend).

@performance ― Async; O(size) to hash, plus the backend upload (a no-op for inline storage).

createBlob
(
const bytes: Uint8Array<ArrayBufferLike>
bytes
, {
type?: string | undefined
type
: 'image/png' });
const db: Database.Database
db
.
Database.add<Blob.Blob>(obj: Blob.Blob, opts?: Database.AddOptions): Blob.Blob

Adds an object or relation to the database.

Only Object and Relation entities are accepted. To persist a Type definition use

addType

— passing a Type entity is rejected at compile time (and at runtime).

Pass { to: feed } to append to a feed instead (synchronous; confirm with

flush

).

@performance ― Synchronous; O(n) in object size to write it into a new linked document (or the root), persisted in the background.

add
(
const blob: Blob.Blob
blob
);
const
const photo: BaseObj & Photo & OfKind<EntityKind.Object>
photo
=
const db: Database.Database
db
.
Database.add<BaseObj & Photo & OfKind<EntityKind.Object>>(obj: BaseObj & Photo & OfKind<EntityKind.Object>, opts?: Database.AddOptions): BaseObj & Photo & OfKind<EntityKind.Object>

Adds an object or relation to the database.

Only Object and Relation entities are accepted. To persist a Type definition use

addType

— passing a Type entity is rejected at compile time (and at runtime).

Pass { to: feed } to append to a feed instead (synchronous; confirm with

flush

).

@performance ― Synchronous; O(n) in object size to write it into a new linked document (or the root), persisted in the background.

add
(
import Obj
Obj
.
function make<typeof Photo>(type: typeof Photo, props: NoInfer<Obj.MakeProps<typeof Photo>>, options?: Obj.MakeOptions): Obj.OfShape<Photo & OfKind<EntityKind.Object>>

Creates a new echo object of the given schema or Type.Type.

@param ― typeOrSchema - A static object schema (Type.makeObject(...)) or a Type.Type entity (e.g. one returned by db.addType(schemaEntity)).

@param ― props - Object properties.

@param ―

options - See MakeOptions.

Meta can be passed as a symbol in props.

Example:

const obj = Obj.make(Person, { [Obj.Meta]: { keys: [...] }, name: 'John' });

Note: Only accepts object schemas / object-kind types, not relation schemas. Use Relation.make for relations.

@performance ― O(n) in props size; validates props against the schema and allocates a reactive proxy, with no database I/O.

make
(
class Photo
Photo
, {
caption: string
caption
: 'Launch day',
image: Ref<Blob.Blob & OfKind<EntityKind.Object> & Obj.Unknown>
image
:
import Ref
Ref
.
const make: <Blob.Blob>(object: Blob.Blob) => Ref<Blob.Blob>

Create a reference to an entity.

@performance ― O(1); allocates a ref that inlines the target, with no lookup.

make
(
const blob: Blob.Blob
blob
) }),
);

db.readBlob loads the bytes, from the object itself or from the backend, and rejects with BlobNotAvailableError when it cannot. db.getBlobUrl gives a URL to show the blob in a page.

const
const image: Blob.Blob & OfKind<EntityKind.Object> & Obj.Unknown
image
= await
const photo: BaseObj & Photo & OfKind<EntityKind.Object>
photo
.
image: Ref<Blob.Blob & OfKind<EntityKind.Object> & Obj.Unknown>
image
.
Ref<Blob & OfKind<EntityKind.Object> & Unknown>.load(options?: LoadOptions): Promise<Blob.Blob & OfKind<EntityKind.Object> & Obj.Unknown>

@returns ― Promise that will resolves with the target object. Will load the object from disk if it is not present in the working set. Short-circuits immediately when the target is already loaded.

@throws ― If the object is not available locally.

@idiom ― org.dxos.echo.refLoad applies: Resolving a ref inside an async function or Effect handler — guarantees the object is available before proceeding instead-of: ref.target — not guaranteed to be defined in async contexts; use await ref.load() (or yield* Database.load(ref) in Effect) to ensure the target is present uses: load related: org.dxos.echo-react.useObjectReactive

@performance ― Async; resolves immediately for an inlined or loaded target, otherwise loads from disk or the network.

load
();
const
const data: Uint8Array<ArrayBufferLike>
data
= await
const db: Database.Database
db
.
Database.readBlob(blob: Blob.Blob): Promise<Uint8Array>

Loads a blob's bytes. Rejects with Error.BlobNotAvailableError if the backend for the blob's storage scheme is not registered, offline, or cannot find the bytes.

@performance ― Async; O(size), read inline or fetched from the backend.

readBlob
(
const image: Blob.Blob & OfKind<EntityKind.Object> & Obj.Unknown
image
); // Uint8Array
const
const url: string | undefined
url
= await
const db: Database.Database
db
.
Database.getBlobUrl(blob: Blob.Blob): Promise<string | undefined>

Returns a renderable URL for the blob, if one can be produced.

@performance ― Async; an inline blob encodes all of its bytes into a data: URL (O(size)), an external one asks the backend.

getBlobUrl
(
const image: Blob.Blob & OfKind<EntityKind.Object> & Obj.Unknown
image
); // for an <img>, if one can be made
const
const available: boolean
available
= await
const db: Database.Database
db
.
Database.blobExists(blob: Blob.Blob): Promise<boolean>

Checks whether a blob's bytes are currently available.

@performance ― Async; one backend check, with no byte transfer.

blobExists
(
const image: Blob.Blob & OfKind<EntityKind.Object> & Obj.Unknown
image
);
Member Summary
Blob The blob object type
db.createBlob db.createBlobFromUpload Store bytes, or adopt bytes uploaded elsewhere
db.readBlob db.blobExists db.getBlobUrl Read bytes, check them, or get a URL
MAX_INLINE_SIZE The largest blob stored inline

The full list is in the API reference.