Directus
@ginjou/with-directus provides two adapters for the Directus SDK.
It gives you a Ginjou fetcher and a Ginjou auth provider. Most apps pass the same Directus client to both.
This package does not change how higher-level Ginjou hooks are used. It only connects them to Directus.
Installation
Install @directus/sdk together with the adapter.
pnpm add @ginjou/with-directus @directus/sdk
yarn add @ginjou/with-directus @directus/sdk
npm install @ginjou/with-directus @directus/sdk
bun add @ginjou/with-directus @directus/sdk
| Package | Supported version |
|---|---|
@directus/sdk | ^15.0.0 |
Fetcher
Use createFetcher() with a Directus client that has REST support.
| Prop | Required | Meaning |
|---|---|---|
client | Yes | A Directus client with REST capabilities. |
Register it through defineFetchersContext().
import { authentication, createDirectus, rest } from '@directus/sdk'
import { defineFetchersContext } from '@ginjou/vue'
import { createFetcher } from '@ginjou/with-directus'
const directus = createDirectus('https://your-directus.example.com')
.with(rest())
.with(authentication())
defineFetchersContext({
default: createFetcher({ client: directus }),
})
The adapter implements getList, getOne, createOne, updateOne, deleteOne, and custom.
Collections and System Collections
Normal resources use the generic SDK item helpers such as readItems() and updateItem().
System resources are different. If the resource starts with directus_ or directus/, the adapter switches to the matching dedicated SDK helper.
| Resource name | Directus SDK helper pattern |
|---|---|
posts | readItems, readItem, createItem, updateItem, deleteItem |
directus_users | readUsers, readUser, createUser, updateUser, deleteUser |
That lets one resource name work for both normal collections and Directus system collections.
Pagination
List pagination is translated into Directus page and limit.
| Ginjou input | Directus query |
|---|---|
pagination.current | page |
pagination.perPage | limit |
For totals, the adapter runs a second aggregate() request.
By default it asks Directus for countDistinct: 'id'.
Filters
The adapter converts Ginjou filters into Directus filter objects.
| Ginjou operator | Directus operator |
|---|---|
eq | _eq |
ne | _neq |
lt | _lt |
gt | _gt |
lte | _lte |
gte | _gte |
in | _in |
nin | _nin |
contains | _contains |
containss | _icontains |
ncontains | _ncontains |
null | _null |
nnull | _nnull |
between | _between |
nbetween | _nbetween |
startswith | _starts_with |
nstartswith | _nstarts_with |
endswith | _ends_with |
nendswith | _nends_with |
or | _or |
and | _and |
Some case-insensitive negative variants are not currently mapped.
| Ginjou operator | Behavior |
|---|---|
ncontainss | Ignored by the adapter |
startswiths | Ignored by the adapter |
nstartswiths | Ignored by the adapter |
endswiths | Ignored by the adapter |
nendswiths | Ignored by the adapter |
There are two extra rules worth knowing.
| Case | Behavior |
|---|---|
Filter on search | Routed into Directus search. |
getList() default status | Excludes status: archived unless you override it. |
If that default status filter is not what you want, override it through meta.query.filter.status.
Sorters
Sorters are converted into Directus sort strings.
| Ginjou sorter | Directus sort entry |
|---|---|
{ field: 'title', order: 'asc' } | title |
{ field: 'createdAt', order: 'desc' } | -createdAt |
Multiple sorters are joined with commas.
For example, title asc plus createdAt desc becomes title,-createdAt.
Meta
The verified meta entry points are meta.query and meta.aggregate.
| Meta field | Used by | What it does |
|---|---|---|
meta.query | getList, getOne, createOne, updateOne | Pass through Directus query options such as fields, filter, sort, page, and limit. |
meta.aggregate | getList | Override the aggregate descriptor used for total count. |
groupBy exists in the current type, but it is not used by the implementation.
Do not rely on it as a working feature yet.
import { useGetList } from '@ginjou/vue'
useGetList({
resource: 'posts',
meta: {
query: {
fields: ['id', 'title', 'user_created.first_name'],
filter: {
status: {
_eq: 'published',
},
},
},
},
})
import { useGetList } from '@ginjou/vue'
useGetList({
resource: 'posts',
meta: {
aggregate: {
count: '*',
},
},
})
Auth
Use createAuth() with a Directus client that has authentication and REST support.
Most apps reuse the same Directus client they already passed to createFetcher().
Register it through defineAuthContext().
import { authentication, createDirectus, rest } from '@directus/sdk'
import { defineAuthContext } from '@ginjou/vue'
import { createAuth } from '@ginjou/with-directus'
const directus = createDirectus('https://your-directus.example.com')
.with(rest())
.with(authentication())
defineAuthContext(createAuth({ client: directus }))
Login
login() maps to client.login().
The adapter currently supports two verified login types.
| Login type | Input | Directus call |
|---|---|---|
password | email, password, optional options | client.login(email, password, options) |
sso | provider, optional options | client.login('placeholder', 'placeholder', { provider, ...options }) |
Password login:
import { useLogin } from '@ginjou/vue'
const { mutateAsync: login } = useLogin()
await login({
type: 'password',
params: {
email: 'user@example.com',
password: 'password123',
},
})
SSO login:
import { useLogin } from '@ginjou/vue'
const { mutateAsync: login } = useLogin()
await login({
type: 'sso',
params: {
provider: 'google',
},
})
Logout
logout() maps to client.logout().
It clears the Directus session through the SDK.
Identity
getIdentity() maps to client.request(readMe()).
That returns the current Directus user profile.
Check Authentication
check() maps to client.getToken().
| Token state | Result |
|---|---|
| Token exists | { authenticated: true } |
| No token | { authenticated: false } |
Check Error
checkError() inspects Directus client errors.
It returns { logout: true } only for verified auth-related Directus error codes.
| Directus error code | Behavior |
|---|---|
TOKEN_EXPIRED | Return { logout: true, error } |
INVALID_CREDENTIALS | Return { logout: true, error } |
INVALID_IP | Return { logout: true, error } |
INVALID_OTP | Return { logout: true, error } |
Other errors return an empty object, so non-auth failures do not force logout automatically.