Skip to content

Data and managed files

Named PostgreSQL full-text, vector and hybrid search is a Function-context capability in the unpublished SDK 2.4/platform candidate. The browser SDK does not expose opencloud.data.search; call a declared Function and retain the normal Data RLS boundary. See Function search for data.search(name, options), manifest declarations and ranking evidence.

These APIs hide REST syntax, Storage buckets, object paths, bearer tokens, retry keys, timeouts, and raw responses.

Data tables

Every app table must declare id as its primary key. Create one handle per logical table:

js
const items = opencloud.data.table("items");
const rows = await items.list({
  select: ["id", "title", "state", "created_at"],
  where: { state: "open" },
  orderBy: { column: "created_at", direction: "desc" },
  limit: 50,
});
const item = await items.getById(itemId);

Writes return application values:

js
const created = await items.create({ title: "Review evidence", state: "open" });
const batch = await items.createMany([{ title: "First" }, { title: "Second" }]);
const updated = await items.updateById(created.id, { state: "closed" });
const deleted = await items.deleteById(created.id); // boolean

There is no .rows wrapper, custom idColumn, insert, upsert, raw filter, or broad update/delete method. PostgreSQL constraints and RLS remain authoritative.

Upload a file

Declare managed Files in opencloud.yaml:

yaml
files:
  access: user
  maxUploadBytes: 52428800

Use one object. data is a browser File or Blob:

js
const stored = await opencloud.files.upload({
  data: selectedFile,
  name: selectedFile.name,
  contentType: selectedFile.type || "application/octet-stream",
  onProgress: ({ percent }) => renderUploadProgress(percent),
});

The result is { id, name, contentType, size, createdAt, updatedAt }. The shared FileRef shape is simply { id }; every read or mutation accepts that object or its ID.

js
const metadata = await opencloud.files.info(stored);
const download = await opencloud.files.download(stored);
renderBlob(download.data);
await opencloud.files.save(stored);
const replaced = await opencloud.files.replace(stored, {
  data: replacementFile,
  name: replacementFile.name,
});
await opencloud.files.remove(replaced);

The SDK sanitizes names, checks the deployment limit, creates a private idempotency key, and retries one transient failure with that same key. App code must not create retry tokens or repeat an ambiguous upload itself.

Attach a file to a row safely

Use the flattened compound helper when a product needs a managed file and an RLS-protected metadata row:

js
const result = await opencloud.files.attach({
  data: selectedFile,
  name: selectedFile.name,
  onProgress: ({ percent }) => renderUploadProgress(percent),
  table: "item_attachments",
  values: { item_id: itemId },
});

renderAttachment(result.record, result.file);

By default the row receives file_id, file_name, file_type, and file_size. Use columns: { id, name, contentType, size } only for an existing schema with different lowercase identifiers.

attach reconciles an ambiguous row write and cleans up a definite failure. If it throws FILE_ATTACHMENT_INCOMPLETE, retain details.file for explicit cleanup instead of uploading another copy. Never construct a bucket, object name, owner prefix, Storage URL, or authorization header.

Self-hosted infrastructure for agent-built applications.