Skip to main content

Connect a Refine application

@taruvi/refine-providers connects Refine data hooks to app-scoped TaruviBase tables. The provider maps Refine resources, filters, sorters, pagination, and query metadata to the same Database API the JavaScript SDK uses.

Use the provider for read-focused Refine views:

  • list, read-one, and read-many hooks;
  • flat and nested AND/OR filters;
  • sorting and server pagination;
  • field projection; and
  • per-record action hints.

Install the packages​

npm install \
@refinedev/core \
@taruvi/refine-providers \
@taruvi/sdk

Register the provider​

Create one browser client and pass it to dataProvider. The resource name maps to the table name unless a hook supplies meta.tableName.

import {Refine} from '@refinedev/core';
import {dataProvider} from '@taruvi/refine-providers';
import {Auth, Client} from '@taruvi/sdk';

const client = new Client({
apiUrl: import.meta.env.VITE_TARUVI_SITE_URL,
appSlug: import.meta.env.VITE_TARUVI_APP_SLUG,
apiKey: 'session-authenticated-client',
});

const auth = new Auth(client);

export function App() {
if (!auth.hasToken()) {
return <button onClick={() => auth.login()}>Sign in to TaruviBase</button>;
}

return (
<Refine
dataProvider={dataProvider(client)}
resources={[{name: 'tasks'}]}
/>
);
}

The JavaScript SDK captures the hosted-login callback's session_token in the browser, stores it locally, and sends it through X-Session-Token. Do not pass the token constructor option in browser code; that option is read only by non-browser runtimes. The session-authenticated-client value is a non-secret constructor placeholder and is not transmitted; never put a real API key in browser code.

Define the record type​

Refine records need an id. Match the remaining fields to the TaruviBase table schema:

type Task = {
id: string;
title: string;
done: boolean;
};

Import the hooks and filter helper once, then keep each task example focused on the operation:

import {useList, useMany, useOne} from '@refinedev/core';
import {toRefineFilters} from '@taruvi/refine-providers';

List records​

Place data hooks inside a component rendered beneath <Refine>.

useList<Task>({
resource: 'tasks',
filters: [{field: 'done', operator: 'eq', value: false}],
sorters: [
{field: 'title', order: 'asc'},
{field: 'id', order: 'asc'},
],
pagination: {
currentPage: 1,
pageSize: 20,
mode: 'server',
},
});

Refine 5 exposes the records and matching count through result.data and result.total. Request state is available through query.

Read one record​

useOne<Task>({
resource: 'tasks',
id: 'TASK_UUID',
});

The provider calls the single-record Database route and maps its data object to the hook result.

Read several records by ID​

Use useMany when a view already has a bounded set of primary keys. In this example, taskIds is an array of task UUIDs.

useMany<Task>({
resource: 'tasks',
ids: taskIds,
});

Refine 5 exposes the returned records through result.data. TaruviBase's provider maps useMany to one Database list query with an in filter on id; set meta.idColumnName only when the table's primary key isn't id.

Select fields​

Use TaruviBase metadata when a query needs only part of each record:

useList<Pick<Task, 'id' | 'title' | 'done'>>({
resource: 'tasks',
pagination: {currentPage: 1, pageSize: 20, mode: 'server'},
meta: {
select: ['id', 'title', 'done'],
},
});

Compose nested filters​

Use toRefineFilters when a query includes TaruviBase-specific operators or a nested logical group. The provider converts the logical object to the Database JSON filter tree.

useList<Task>({
resource: 'tasks',
filters: toRefineFilters({
operator: 'and',
value: [
{field: 'done', operator: 'eq', value: false},
{
operator: 'or',
value: [
{field: 'title', operator: 'contains', value: 'release'},
{field: 'title', operator: 'contains', value: 'docs'},
],
},
],
}),
pagination: {currentPage: 1, pageSize: 20, mode: 'server'},
});

Import toRefineFilters from @taruvi/refine-providers. The filter model supports nested and and or groups. It does not define a logical not node; for negation, use operators such as ne, nin, ncontains, or nnull.

Read the root rows first, collect their foreign-key values, and issue a second bounded useList query for the related table, so each table gets its own access check. Join the results by their foreign-key values in the component or data layer. See the complete related-record workflow.

Request allowed actions​

The provider maps meta.allowedActions to the Database allowed_actions query parameter:

useList<Task>({
resource: 'tasks',
meta: {allowedActions: ['update', 'delete']},
pagination: {currentPage: 1, pageSize: 20, mode: 'server'},
});

When enabled by the service, each row can include an _allowed_actions array for UI affordances. Treat it as a hint for the current response; every mutation is still authorized by the server when it is submitted.

Provider mapping​

Refine inputTaruviBase request
resourceTable name
useMany.idsin filter on id, or meta.idColumnName
pagination.currentPagepage
pagination.pageSizepage_size
sortersordering
Field filtersfield or field__operator
meta.selectfields
meta.tableNameTable-name override
meta.searchsearch
meta.allowedActionsallowed_actions

Keep pagination in server mode for paged TaruviBase collections. Use pagination: {mode: 'off'} only when the request should omit pagination parameters.

Choose an interface for writes​

Use Refine for list, detail, filter, and selection views. Submit application writes through the JavaScript SDK, Python SDK, or REST API, and use TaruviBase Console for one-off changes.

Continue​