mirror of
https://github.com/directus/directus.git
synced 2026-01-24 08:58:11 -05:00
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ lerna-debug.log
|
||||
dist
|
||||
*.sublime-settings
|
||||
*.db
|
||||
.nyc_output
|
||||
|
||||
@@ -24,7 +24,7 @@ router.get(
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/hash',
|
||||
'/hash/generate',
|
||||
asyncHandler(async (req, res) => {
|
||||
if (!req.body?.string) {
|
||||
throw new InvalidPayloadException(`"string" is required`);
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function login(credentials: LoginCredentials) {
|
||||
|
||||
// Refresh the token 10 seconds before the access token expires. This means the user will stay
|
||||
// logged in without any noticable hickups or delays
|
||||
setTimeout(() => refresh(), response.data.data.expires * 1000 + 10 * 1000);
|
||||
setTimeout(() => refresh(), response.data.data.expires - 10000);
|
||||
|
||||
appStore.state.authenticated = true;
|
||||
|
||||
|
||||
604
docs/reference/sdk-js.md
Normal file
604
docs/reference/sdk-js.md
Normal file
@@ -0,0 +1,604 @@
|
||||
# SDK JS
|
||||
|
||||
The JS SDK is a small wrapper around [Axios](https://npmjs.com/axios) that makes it a little easier to use the Directus API from a JavaScript powered project.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @directus/sdk-js
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import DirectusSDK from '@directus/sdk-js';
|
||||
|
||||
const directus = new DirectusSDK('https://api.example.com/');
|
||||
```
|
||||
|
||||
**NOTE** All methods return promises. Make sure to await methods, for example:
|
||||
|
||||
```js
|
||||
import DirectusSDK from '@directus/sdk-js';
|
||||
|
||||
const directus = new DirectusSDK('https://api.example.com/');
|
||||
|
||||
async function getData() {
|
||||
// Wait for login to be done...
|
||||
await directus.auth.login({ email: 'admin@example.com', password: 'password' });
|
||||
|
||||
// ... before fetching items
|
||||
return await directus.items('articles').read();
|
||||
}
|
||||
|
||||
getData();
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
### Global
|
||||
|
||||
#### Initialize
|
||||
|
||||
```js
|
||||
import DirectusSDK from '@directus/sdk-js';
|
||||
|
||||
const directus = new DirectusSDK('https://api.example.com/');
|
||||
```
|
||||
|
||||
The SDK accepts a second optional `options` parameter:
|
||||
|
||||
```js
|
||||
import DirectusSDK from '@directus/sdk-js';
|
||||
|
||||
const directus = new DirectusSDK('https://api.example.com/', {
|
||||
auth: {
|
||||
storage: new MemoryStore(), // Storage adapter where refresh tokens are stored in JSON mode
|
||||
mode: 'json', // What login mode to use. One of `json`, `cookie`
|
||||
autoRefresh: true, // Whether or not to automatically refresh the access token on login
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Get / set API URL
|
||||
|
||||
```js
|
||||
// Get the used API base URL
|
||||
console.log(directus.url);
|
||||
// => https://api.example.com/
|
||||
|
||||
// Set the API base URL
|
||||
directus.url = 'https://api2.example.com';
|
||||
```
|
||||
|
||||
#### Access to Axios
|
||||
|
||||
You can tap into the Axios instance used directly through `directus.axios`.
|
||||
|
||||
---
|
||||
|
||||
### Items
|
||||
|
||||
#### Create
|
||||
|
||||
##### Single Item
|
||||
|
||||
```js
|
||||
directus.items('articles').create({
|
||||
title: 'My New Article'
|
||||
});
|
||||
```
|
||||
|
||||
##### Multiple Items
|
||||
```js
|
||||
directus.items('articles').create([
|
||||
{
|
||||
title: 'My First Article'
|
||||
},
|
||||
{
|
||||
title: 'My Second Article'
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
#### Read
|
||||
|
||||
##### All
|
||||
|
||||
```js
|
||||
directus.items('articles').read();
|
||||
```
|
||||
|
||||
##### By Query
|
||||
|
||||
```js
|
||||
directus.items('articles').read({
|
||||
search: 'Directus',
|
||||
filter: {
|
||||
date_published: {
|
||||
_gte: '$NOW'
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
##### By Primary Key(s)
|
||||
|
||||
```js
|
||||
// One
|
||||
directus.items('articles').read(15);
|
||||
|
||||
// Multiple
|
||||
directus.items('articles').read([15, 42]);
|
||||
```
|
||||
|
||||
Supports optional query:
|
||||
|
||||
```js
|
||||
// One
|
||||
directus.items('articles').read(15, { fields: ['title'] });
|
||||
|
||||
// Multiple
|
||||
directus.items('articles').read([15, 42], { fields: ['title'] });
|
||||
```
|
||||
|
||||
#### Update
|
||||
|
||||
##### One or More Item(s), Single Value
|
||||
|
||||
```js
|
||||
// One
|
||||
directus.items('articles').update(15, {
|
||||
title: 'An Updated title'
|
||||
});
|
||||
|
||||
// Multiple
|
||||
directus.items('articles').update([15, 42], {
|
||||
title: 'An Updated title'
|
||||
});
|
||||
```
|
||||
|
||||
Supports optional query:
|
||||
|
||||
```js
|
||||
directus.items('articles').update(
|
||||
15,
|
||||
{ title: 'An Updated title' },
|
||||
{ fields: ['title'] }
|
||||
);
|
||||
|
||||
directus.items('articles').update(
|
||||
[15, 42],
|
||||
{ title: 'An Updated title' },
|
||||
{ fields: ['title'] }
|
||||
);
|
||||
```
|
||||
|
||||
##### Multiple Items, Multiple Values
|
||||
|
||||
```js
|
||||
directus.items('articles').update([
|
||||
{
|
||||
id: 15,
|
||||
title: 'Article 15',
|
||||
},
|
||||
{
|
||||
id: 42,
|
||||
title: 'Article 42',
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
Supports optional query:
|
||||
|
||||
```js
|
||||
directus.items('articles').update([
|
||||
{
|
||||
id: 15,
|
||||
title: 'Article 15',
|
||||
},
|
||||
{
|
||||
id: 42,
|
||||
title: 'Article 42',
|
||||
},
|
||||
], { fields: ['title'] });
|
||||
```
|
||||
|
||||
##### Multiple Items by Query, Single Value
|
||||
|
||||
```js
|
||||
directus.items('articles').update(
|
||||
{
|
||||
archived: true
|
||||
},
|
||||
{
|
||||
filter: {
|
||||
publish_date: {
|
||||
_gte: '$NOW'
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
#### Delete
|
||||
|
||||
```js
|
||||
// One
|
||||
directus.items('articles').delete(15);
|
||||
|
||||
// Multiple
|
||||
directus.items('articles').delete([15, 42]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Activity
|
||||
|
||||
#### Read Activity
|
||||
|
||||
##### All
|
||||
|
||||
```js
|
||||
directus.activity.read();
|
||||
```
|
||||
|
||||
##### By Query
|
||||
|
||||
```js
|
||||
directus.activity.read({
|
||||
filter: {
|
||||
action: {
|
||||
_eq: 'create'
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
##### By Primary Key(s)
|
||||
|
||||
```js
|
||||
// One
|
||||
directus.activity.read(15);
|
||||
|
||||
// Multiple
|
||||
directus.activity.read([15, 42]);
|
||||
```
|
||||
|
||||
Supports optional query:
|
||||
|
||||
```js
|
||||
// One
|
||||
directus.activity.read(15, { fields: ['action'] });
|
||||
|
||||
// Multiple
|
||||
directus.activity.read([15, 42], { fields: ['action'] });
|
||||
```
|
||||
|
||||
#### Create a Comment
|
||||
|
||||
```js
|
||||
directus.activity.comments.create({
|
||||
collection: 'articles',
|
||||
item: 15,
|
||||
comment: 'Hello, world!'
|
||||
});
|
||||
```
|
||||
|
||||
#### Update a comment
|
||||
|
||||
```js
|
||||
directus.activity.comments.update(31, { comment: 'Howdy, world!' });
|
||||
```
|
||||
|
||||
Note: The passed key is the primary key of the comment
|
||||
|
||||
#### Delete a comment
|
||||
|
||||
```js
|
||||
directus.activity.comments.delete(31);
|
||||
```
|
||||
|
||||
Note: The passed key is the primary key of the comment
|
||||
|
||||
---
|
||||
|
||||
### Auth
|
||||
|
||||
#### Configuration
|
||||
|
||||
Note: these configuration options are passed in the top level SDK constructor.
|
||||
|
||||
##### mode
|
||||
|
||||
`cookie` or `json`. When in cookie mode, the API will set the refresh token in a `httpOnly` secure cookie that can't be accessed from client side JS. This is the most secure way to connect to the API from a public front-end website.
|
||||
|
||||
When you can't rely on cookies, or need more control over handling the storage of the cookie, use `json` mode. This will return the refresh token like "regular" in the payload. You can use the `storage` option (see below) to control where the refresh token is stored / read from
|
||||
|
||||
##### storage
|
||||
|
||||
When using `json` for mode, the refresh token needs to be stored somewhere. The `storage` option allows you to plug in any object that has an async `setItem()` and `getItem()` method. This allows you to plugin things like [`localforage`](https://github.com/localForage/localForage) directly:
|
||||
|
||||
```js
|
||||
import localforage from 'localforage';
|
||||
import DirectusSDK from '@directus/sdk-js';
|
||||
|
||||
const directus = new DirectusSDK('https://api.example.com', { storage: localforage });
|
||||
```
|
||||
|
||||
##### autoRefresh
|
||||
|
||||
Whether or not to automatically call `refresh()` when the access token is about to expire. Defaults to `true`
|
||||
|
||||
#### Get / Set Token
|
||||
|
||||
```
|
||||
directus.auth.token = 'abc.def.ghi';
|
||||
```
|
||||
|
||||
#### Login
|
||||
|
||||
```js
|
||||
directus.auth.login({ email: 'admin@example.com', password: 'd1r3ctu5' });
|
||||
```
|
||||
|
||||
#### Refresh
|
||||
|
||||
Note: if you have autoRefresh enabled, you most likely won't need to use this manually.
|
||||
|
||||
```js
|
||||
directus.auth.refresh();
|
||||
```
|
||||
|
||||
#### Logout
|
||||
|
||||
```js
|
||||
directus.auth.logout();
|
||||
```
|
||||
|
||||
#### Request a Password Reset
|
||||
|
||||
```js
|
||||
directus.auth.password.request('admin@example.com');
|
||||
```
|
||||
|
||||
#### Reset a Password
|
||||
|
||||
```js
|
||||
directus.auth.password.reset('abc.def.ghi', 'n3w-p455w0rd');
|
||||
```
|
||||
|
||||
Note: the token passed in the first parameter is sent in an email to the user when using `request()`
|
||||
|
||||
---
|
||||
|
||||
### Collections
|
||||
|
||||
```js
|
||||
directus.collections;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Fields
|
||||
|
||||
```js
|
||||
directus.fields;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Files
|
||||
|
||||
```js
|
||||
directus.files;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Folders
|
||||
|
||||
```js
|
||||
directus.folders;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Permissions
|
||||
|
||||
```js
|
||||
directus.permissions;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Presets
|
||||
|
||||
```js
|
||||
directus.presets;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Relations
|
||||
|
||||
```js
|
||||
directus.relations;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Revisions
|
||||
|
||||
```js
|
||||
directus.revisions;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Roles
|
||||
|
||||
```js
|
||||
directus.roles;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Server
|
||||
|
||||
#### Get the API Spec in OAS Format
|
||||
|
||||
```js
|
||||
directus.server.specs.oas();
|
||||
```
|
||||
|
||||
#### Ping the Server
|
||||
|
||||
```js
|
||||
directus.server.ping()
|
||||
```
|
||||
|
||||
#### Get Server/Project Info
|
||||
|
||||
```js
|
||||
directus.server.info();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Settings
|
||||
|
||||
```js
|
||||
directus.settings;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`.
|
||||
|
||||
---
|
||||
|
||||
### Users
|
||||
|
||||
```js
|
||||
directus.users;
|
||||
```
|
||||
|
||||
Same methods as `directus.items(collection)`, and:
|
||||
|
||||
#### Invite a New User
|
||||
|
||||
```js
|
||||
directus.users.invite('admin@example.com', 'fe38136e-52f7-4622-8498-112b8a32a1e2');
|
||||
```
|
||||
|
||||
The second parameter is the role of the user
|
||||
|
||||
#### Accept a User Invite
|
||||
|
||||
```js
|
||||
directus.users.acceptInvite('abc.def.ghi', 'n3w-p455w0rd');
|
||||
```
|
||||
|
||||
The provided token is sent to the user's email
|
||||
|
||||
#### Enable Two-Factor Authentication
|
||||
|
||||
```js
|
||||
directus.users.tfa.enable('my-password');
|
||||
```
|
||||
|
||||
#### Disable Two-Factor Authentication
|
||||
|
||||
```js
|
||||
directus.users.tfa.disable('691402');
|
||||
```
|
||||
|
||||
#### Get the Current User
|
||||
|
||||
```js
|
||||
directus.users.me.read();
|
||||
```
|
||||
|
||||
Supports optional query:
|
||||
|
||||
```js
|
||||
directus.users.me.read({
|
||||
fields: ['last_access']
|
||||
});
|
||||
```
|
||||
|
||||
#### Update the Current Users
|
||||
|
||||
```js
|
||||
directus.users.me.update({ first_name: 'Admin' });
|
||||
```
|
||||
|
||||
Supports optional query:
|
||||
|
||||
```js
|
||||
directus.users.me.update(
|
||||
{ first_name: 'Admin' },
|
||||
{ fields: ['last_access'] }
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Utils
|
||||
|
||||
#### Get a Random String
|
||||
|
||||
```js
|
||||
directus.utils.random.string();
|
||||
```
|
||||
|
||||
Supports an optional `length`:
|
||||
|
||||
```js
|
||||
directus.utils.random.string(32);
|
||||
```
|
||||
|
||||
#### Generate a Hash for a Given Value
|
||||
|
||||
```js
|
||||
directus.utils.hash.generate('My String');
|
||||
```
|
||||
|
||||
#### Verify if a Hash is Valid
|
||||
|
||||
```js
|
||||
directus.utils.hash.verify('My String', '$argon2i$v=19$m=4096,t=3,p=1$A5uogJh');
|
||||
```
|
||||
|
||||
#### Sort Items in a Collection
|
||||
|
||||
```js
|
||||
directus.utils.sort('articles', 15, 42);
|
||||
```
|
||||
|
||||
This will move item 15 to the position of item 42, and move everything in between one "slot" up
|
||||
|
||||
#### Revert to a Previous Revision
|
||||
|
||||
```js
|
||||
directus.utils.revert(451);
|
||||
```
|
||||
|
||||
Note: the key passed is the primary key of the revision you'd like to apply
|
||||
34251
package-lock.json
generated
34251
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@@ -4,7 +4,7 @@
|
||||
"scripts": {
|
||||
"dev": "lerna run dev --stream --parallel",
|
||||
"build": "lerna run build",
|
||||
"release": "lerna publish --force-publish",
|
||||
"release": "lerna run test && lerna publish --force-publish",
|
||||
"cli": "cross-env NODE_ENV=development DOTENV_CONFIG_PATH=api/.env ts-node -r dotenv/config --script-mode --transpile-only api/src/cli/index.ts",
|
||||
"postinstall": "npm run build"
|
||||
},
|
||||
@@ -62,6 +62,8 @@
|
||||
"@types/qrcode": "^1.3.5",
|
||||
"@types/semver": "^7.3.1",
|
||||
"@types/sharp": "^0.25.1",
|
||||
"@types/sinon": "^9.0.8",
|
||||
"@types/sinon-chai": "^3.2.5",
|
||||
"@types/uuid": "^8.0.0",
|
||||
"@types/uuid-validate": "0.0.1",
|
||||
"@types/webpack-env": "^1.15.2",
|
||||
@@ -80,6 +82,7 @@
|
||||
"autoprefixer": "^9.8.5",
|
||||
"babel-loader": "^8.2.1",
|
||||
"babel-preset-vue": "^2.0.2",
|
||||
"chai": "^4.2.0",
|
||||
"colors": "^1.4.0",
|
||||
"concat-map": "0.0.1",
|
||||
"copyfiles": "^2.4.0",
|
||||
@@ -95,8 +98,10 @@
|
||||
"lerna": "^3.22.1",
|
||||
"lint-staged": "^10.3.0",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"mocha": "^8.2.1",
|
||||
"mockdate": "^3.0.2",
|
||||
"npm-watch": "^0.7.0",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.1.1",
|
||||
"raw-loader": "^4.0.1",
|
||||
"react": "^16.13.1",
|
||||
@@ -112,6 +117,9 @@
|
||||
"rollup-plugin-typescript2": "^0.27.2",
|
||||
"sass": "^1.26.10",
|
||||
"sass-loader": "^9.0.2",
|
||||
"sinon": "^9.2.0",
|
||||
"sinon-chai": "^3.5.0",
|
||||
"source-map-support": "^0.5.19",
|
||||
"storybook-addon-themes": "^5.4.1",
|
||||
"stylelint": "^13.6.1",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
@@ -137,6 +145,7 @@
|
||||
"@directus/app": "file:app",
|
||||
"@directus/docs": "file:docs",
|
||||
"@directus/format-title": "file:packages/format-title",
|
||||
"@directus/sdk-js": "file:packages/sdk-js",
|
||||
"@directus/specs": "file:packages/specs",
|
||||
"create-directus-project": "file:packages/create-directus-project",
|
||||
"directus": "file:api"
|
||||
|
||||
13
packages/sdk-js/.editorconfig
Normal file
13
packages/sdk-js/.editorconfig
Normal file
@@ -0,0 +1,13 @@
|
||||
root=true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{package.json,*.yml,*.yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
38
packages/sdk-js/package.json
Normal file
38
packages/sdk-js/package.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "@directus/sdk-js",
|
||||
"version": "9.0.0-rc.14",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "mocha -r ts-node/register/transpile-only -r source-map-support/register --recursive 'tests/**/*.ts'",
|
||||
"coverage": "nyc npm test"
|
||||
},
|
||||
"keywords": [
|
||||
"api",
|
||||
"client",
|
||||
"cms",
|
||||
"directus",
|
||||
"headless",
|
||||
"javascript",
|
||||
"node",
|
||||
"sdk"
|
||||
],
|
||||
"author": "Rijk van Zanten <rijkvanzanten@me.com>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^0.19.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.2.0",
|
||||
"mocha": "^8.2.0",
|
||||
"ts-node": "^9.0.0",
|
||||
"typescript": "^4.0.3"
|
||||
},
|
||||
"nyc": {
|
||||
"extension": [".ts"],
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["**/*.d.ts"],
|
||||
"all": true
|
||||
}
|
||||
}
|
||||
21
packages/sdk-js/readme.md
Normal file
21
packages/sdk-js/readme.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Directus JS SDK
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
npm install @directus/sdk-js
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import DirectusSDK from '@directus/sdk-js';
|
||||
|
||||
const directus = new DirectusSDK('https://api.example.com/');
|
||||
|
||||
directus.items('articles').read(15);
|
||||
```
|
||||
|
||||
## Docs
|
||||
|
||||
See [the docs](../../docs/reference/sdk-js.md)
|
||||
42
packages/sdk-js/src/handlers/activity.ts
Normal file
42
packages/sdk-js/src/handlers/activity.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
import { Query, PrimaryKey, Item, Response } from '../types';
|
||||
|
||||
export class ActivityHandler {
|
||||
private axios: AxiosInstance;
|
||||
private itemsHandler: ItemsHandler;
|
||||
|
||||
constructor(axios: AxiosInstance) {
|
||||
this.axios = axios;
|
||||
this.itemsHandler = new ItemsHandler('directus_activity', axios);
|
||||
}
|
||||
|
||||
async read(query?: Query): Promise<Response<Item | Item[]>>;
|
||||
async read(key: PrimaryKey, query?: Query): Promise<Response<Item>>;
|
||||
async read(keys: PrimaryKey[], query?: Query): Promise<Response<Item | Item[]>>;
|
||||
async read(
|
||||
keysOrQuery?: PrimaryKey | PrimaryKey[] | Query,
|
||||
query?: Query & { single: boolean }
|
||||
): Promise<Response<Item | Item[]>> {
|
||||
const result = await this.itemsHandler.read(keysOrQuery as any, query as any);
|
||||
return result;
|
||||
}
|
||||
|
||||
comments = {
|
||||
create: async (payload: {
|
||||
collection: string;
|
||||
item: string;
|
||||
comment: string;
|
||||
}): Promise<Response<Item>> => {
|
||||
const response = await this.axios.post('/activity/comments', payload);
|
||||
return response.data;
|
||||
},
|
||||
update: async (key: PrimaryKey, payload: { comment: string }) => {
|
||||
const response = await this.axios.patch(`/activity/comments/${key}`, payload);
|
||||
return response.data;
|
||||
},
|
||||
delete: async (key: PrimaryKey) => {
|
||||
await this.axios.delete(`/activity/comments/${key}`);
|
||||
},
|
||||
};
|
||||
}
|
||||
97
packages/sdk-js/src/handlers/auth.ts
Normal file
97
packages/sdk-js/src/handlers/auth.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { AuthStorage } from '../types';
|
||||
|
||||
export type LoginCredentials = {
|
||||
email: string;
|
||||
password: string;
|
||||
otp?: string;
|
||||
};
|
||||
|
||||
export type AuthOptions = {
|
||||
mode: 'cookie' | 'json';
|
||||
autoRefresh: boolean;
|
||||
storage: AuthStorage;
|
||||
};
|
||||
|
||||
export class AuthHandler {
|
||||
private axios: AxiosInstance;
|
||||
private storage: AuthStorage;
|
||||
private mode: 'cookie' | 'json';
|
||||
private autoRefresh: boolean;
|
||||
|
||||
constructor(axios: AxiosInstance, options: AuthOptions) {
|
||||
this.axios = axios;
|
||||
this.storage = options.storage;
|
||||
this.mode = options.mode;
|
||||
this.autoRefresh = options.autoRefresh;
|
||||
|
||||
if (this.autoRefresh) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
get token() {
|
||||
return this.axios.defaults.headers?.Authorization?.split(' ')[1] || null;
|
||||
}
|
||||
|
||||
set token(val: string | null) {
|
||||
this.axios.defaults.headers = {
|
||||
...(this.axios.defaults.headers || {}),
|
||||
Authorization: val ? `Bearer ${val}` : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
async login(credentials: LoginCredentials) {
|
||||
const response = await this.axios.post('/auth/login', { ...credentials, mode: this.mode });
|
||||
|
||||
this.token = response.data.data.access_token;
|
||||
|
||||
if (this.mode === 'json') {
|
||||
await this.storage.setItem('directus_refresh_token', response.data.data.refresh_token);
|
||||
}
|
||||
|
||||
if (this.autoRefresh) {
|
||||
setTimeout(() => this.refresh(), response.data.data.expires - 10000);
|
||||
}
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
const payload: Record<string, any> = { mode: this.mode };
|
||||
|
||||
if (this.mode === 'json') {
|
||||
const refreshToken = await this.storage.getItem('directus_refresh_token');
|
||||
payload['refresh_token'] = refreshToken;
|
||||
}
|
||||
|
||||
const response = await this.axios.post('/auth/refresh', payload);
|
||||
|
||||
this.token = response.data.data.access_token;
|
||||
|
||||
if (this.mode === 'json') {
|
||||
await this.storage.setItem('directus_refresh_token', response.data.data.refresh_token);
|
||||
}
|
||||
|
||||
if (this.autoRefresh) {
|
||||
setTimeout(() => this.refresh(), response.data.data.expires - 10000);
|
||||
}
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.axios.post('/auth/logout');
|
||||
this.token = null;
|
||||
}
|
||||
|
||||
password = {
|
||||
request: async (email: string) => {
|
||||
await this.axios.post('/auth/password/request', { email });
|
||||
},
|
||||
|
||||
reset: async (token: string, password: string) => {
|
||||
await this.axios.post('/auth/password/reset', { token, password });
|
||||
},
|
||||
};
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/collections.ts
Normal file
8
packages/sdk-js/src/handlers/collections.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class CollectionsHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_collections', axios);
|
||||
}
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/fields.ts
Normal file
8
packages/sdk-js/src/handlers/fields.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class FieldsHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_fields', axios);
|
||||
}
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/files.ts
Normal file
8
packages/sdk-js/src/handlers/files.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class FilesHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_files', axios);
|
||||
}
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/folders.ts
Normal file
8
packages/sdk-js/src/handlers/folders.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class FoldersHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_folders', axios);
|
||||
}
|
||||
}
|
||||
16
packages/sdk-js/src/handlers/index.ts
Normal file
16
packages/sdk-js/src/handlers/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export * from './items';
|
||||
export * from './server';
|
||||
export * from './utils';
|
||||
export * from './activity';
|
||||
export * from './folders';
|
||||
export * from './permissions';
|
||||
export * from './presets';
|
||||
export * from './relations';
|
||||
export * from './revisions';
|
||||
export * from './roles';
|
||||
export * from './users';
|
||||
export * from './settings';
|
||||
export * from './files';
|
||||
export * from './collections';
|
||||
export * from './fields';
|
||||
export * from './auth';
|
||||
102
packages/sdk-js/src/handlers/items.ts
Normal file
102
packages/sdk-js/src/handlers/items.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { Query, Item, Payload, Response, PrimaryKey } from '../types';
|
||||
import { AxiosInstance } from 'axios';
|
||||
|
||||
export class ItemsHandler {
|
||||
axios: AxiosInstance;
|
||||
private endpoint: string;
|
||||
|
||||
constructor(collection: string, axios: AxiosInstance) {
|
||||
this.axios = axios;
|
||||
this.endpoint = collection.startsWith('directus_')
|
||||
? `/${collection.substring(9)}/`
|
||||
: `/items/${collection}/`;
|
||||
}
|
||||
|
||||
async create(payload: Payload, query?: Query): Promise<Response<Item>>;
|
||||
async create(payloads: Payload[], query?: Query): Promise<Response<Item | Item[]>>;
|
||||
async create(payloads: Payload | Payload[], query?: Query): Promise<Response<Item | Item[]>> {
|
||||
const result = await this.axios.post(this.endpoint, payloads, {
|
||||
params: query,
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async read(query?: Query): Promise<Response<Item | Item[]>>;
|
||||
async read(key: PrimaryKey, query?: Query): Promise<Response<Item>>;
|
||||
async read(keys: PrimaryKey[], query?: Query): Promise<Response<Item | Item[]>>;
|
||||
async read(
|
||||
keysOrQuery?: PrimaryKey | PrimaryKey[] | Query,
|
||||
query?: Query & { single: boolean }
|
||||
): Promise<Response<Item | Item[]>> {
|
||||
let keys: PrimaryKey | PrimaryKey[] | null = null;
|
||||
|
||||
if (
|
||||
keysOrQuery &&
|
||||
(Array.isArray(keysOrQuery) ||
|
||||
typeof keysOrQuery === 'string' ||
|
||||
typeof keysOrQuery === 'number')
|
||||
) {
|
||||
keys = keysOrQuery;
|
||||
}
|
||||
|
||||
let params: Query = {};
|
||||
|
||||
if (query) {
|
||||
params = query;
|
||||
} else if (
|
||||
!query &&
|
||||
typeof keysOrQuery === 'object' &&
|
||||
Array.isArray(keysOrQuery) === false
|
||||
) {
|
||||
params = keysOrQuery as Query;
|
||||
}
|
||||
|
||||
let endpoint = this.endpoint;
|
||||
|
||||
if (keys) {
|
||||
endpoint += keys;
|
||||
}
|
||||
|
||||
const result = await this.axios.get(endpoint, { params });
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async update(key: PrimaryKey, payload: Payload, query?: Query): Promise<Response<Item>>;
|
||||
async update(keys: PrimaryKey[], payload: Payload, query?: Query): Promise<Response<Item[]>>;
|
||||
async update(payload: Payload[], query?: Query): Promise<Response<Item[]>>;
|
||||
async update(payload: Payload, query: Query): Promise<Response<Item[]>>;
|
||||
async update(
|
||||
keyOrPayload: PrimaryKey | PrimaryKey[] | Payload | Payload[],
|
||||
payloadOrQuery?: Payload | Query,
|
||||
query?: Query
|
||||
): Promise<Response<Item | Item[]>> {
|
||||
if (
|
||||
typeof keyOrPayload === 'string' ||
|
||||
typeof keyOrPayload === 'number' ||
|
||||
(Array.isArray(keyOrPayload) &&
|
||||
(keyOrPayload as any[]).every((key) => ['string', 'number'].includes(typeof key)))
|
||||
) {
|
||||
const key = keyOrPayload as PrimaryKey | PrimaryKey[];
|
||||
const payload = payloadOrQuery as Payload;
|
||||
|
||||
const result = await this.axios.patch(`${this.endpoint}${key}`, payload, {
|
||||
params: query,
|
||||
});
|
||||
return result.data;
|
||||
} else {
|
||||
const result = await this.axios.patch(`${this.endpoint}`, keyOrPayload, {
|
||||
params: payloadOrQuery,
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}
|
||||
}
|
||||
|
||||
async delete(key: PrimaryKey): Promise<void>;
|
||||
async delete(keys: PrimaryKey[]): Promise<void>;
|
||||
async delete(keys: PrimaryKey | PrimaryKey[]): Promise<void> {
|
||||
await this.axios.delete(`${this.endpoint}${keys}`);
|
||||
}
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/permissions.ts
Normal file
8
packages/sdk-js/src/handlers/permissions.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class PermissionsHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_permissions', axios);
|
||||
}
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/presets.ts
Normal file
8
packages/sdk-js/src/handlers/presets.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class PresetsHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_presets', axios);
|
||||
}
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/relations.ts
Normal file
8
packages/sdk-js/src/handlers/relations.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class RelationsHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_relations', axios);
|
||||
}
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/revisions.ts
Normal file
8
packages/sdk-js/src/handlers/revisions.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class RevisionsHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_revisions', axios);
|
||||
}
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/roles.ts
Normal file
8
packages/sdk-js/src/handlers/roles.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class RolesHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_roles', axios);
|
||||
}
|
||||
}
|
||||
26
packages/sdk-js/src/handlers/server.ts
Normal file
26
packages/sdk-js/src/handlers/server.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
|
||||
export class ServerHandler {
|
||||
private axios: AxiosInstance;
|
||||
|
||||
constructor(axios: AxiosInstance) {
|
||||
this.axios = axios;
|
||||
}
|
||||
|
||||
specs = {
|
||||
oas: async () => {
|
||||
const result = await this.axios.get('/server/specs/oas');
|
||||
return result.data;
|
||||
},
|
||||
};
|
||||
|
||||
async ping() {
|
||||
await this.axios.get('/server/ping');
|
||||
return 'pong';
|
||||
}
|
||||
|
||||
async info() {
|
||||
const result = await this.axios.get('/server/info');
|
||||
return result.data;
|
||||
}
|
||||
}
|
||||
8
packages/sdk-js/src/handlers/settings.ts
Normal file
8
packages/sdk-js/src/handlers/settings.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
|
||||
export class SettingsHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_settings', axios);
|
||||
}
|
||||
}
|
||||
37
packages/sdk-js/src/handlers/users.ts
Normal file
37
packages/sdk-js/src/handlers/users.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { ItemsHandler } from './items';
|
||||
import { Query, Payload } from '../types';
|
||||
|
||||
export class UsersHandler extends ItemsHandler {
|
||||
constructor(axios: AxiosInstance) {
|
||||
super('directus_users', axios);
|
||||
}
|
||||
|
||||
async invite(email: string | string[], role: string) {
|
||||
await this.axios.post('/users/invite', { email, role });
|
||||
}
|
||||
|
||||
async acceptInvite(token: string, password: string) {
|
||||
await this.axios.post('/users/invite/accept', { token, password });
|
||||
}
|
||||
|
||||
tfa = {
|
||||
enable: async (password: string) => {
|
||||
await this.axios.post('/users/tfa/enable', { password });
|
||||
},
|
||||
disable: async (otp: string) => {
|
||||
await this.axios.post('/users/tfa/disable', { otp });
|
||||
},
|
||||
};
|
||||
|
||||
me = {
|
||||
read: async (query?: Query) => {
|
||||
const response = await this.axios.get('/users/me', { params: query });
|
||||
return response.data;
|
||||
},
|
||||
update: async (payload: Payload, query?: Query) => {
|
||||
const response = await this.axios.patch('/users/me', payload, { params: query });
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
}
|
||||
36
packages/sdk-js/src/handlers/utils.ts
Normal file
36
packages/sdk-js/src/handlers/utils.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { AxiosInstance } from 'axios';
|
||||
import { PrimaryKey } from '../types';
|
||||
|
||||
export class UtilsHandler {
|
||||
private axios: AxiosInstance;
|
||||
|
||||
constructor(axios: AxiosInstance) {
|
||||
this.axios = axios;
|
||||
}
|
||||
|
||||
random = {
|
||||
string: async (length: number = 32) => {
|
||||
const result = await this.axios.get('/utils/random/string', { params: { length } });
|
||||
return result.data;
|
||||
},
|
||||
};
|
||||
|
||||
hash = {
|
||||
generate: async (string: string) => {
|
||||
const result = await this.axios.post('/utils/hash/generate', { string });
|
||||
return result.data;
|
||||
},
|
||||
verify: async (string: string, hash: string) => {
|
||||
const result = await this.axios.post('/utils/hash/verify', { string, hash });
|
||||
return result.data;
|
||||
},
|
||||
};
|
||||
|
||||
async sort(collection: string, item: PrimaryKey, to: PrimaryKey) {
|
||||
await this.axios.post(`/utils/sort/${collection}`, { item, to });
|
||||
}
|
||||
|
||||
async revert(revision: PrimaryKey) {
|
||||
await this.axios.post(`/utils/revert/${revision}`);
|
||||
}
|
||||
}
|
||||
121
packages/sdk-js/src/index.ts
Normal file
121
packages/sdk-js/src/index.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import {
|
||||
ItemsHandler,
|
||||
ServerHandler,
|
||||
UtilsHandler,
|
||||
ActivityHandler,
|
||||
FoldersHandler,
|
||||
PermissionsHandler,
|
||||
PresetsHandler,
|
||||
RolesHandler,
|
||||
UsersHandler,
|
||||
SettingsHandler,
|
||||
FilesHandler,
|
||||
CollectionsHandler,
|
||||
FieldsHandler,
|
||||
AuthHandler,
|
||||
RelationsHandler,
|
||||
AuthOptions,
|
||||
RevisionsHandler,
|
||||
} from './handlers';
|
||||
import { MemoryStore } from './utils';
|
||||
|
||||
export default class DirectusSDK {
|
||||
axios: AxiosInstance;
|
||||
private authOptions: AuthOptions;
|
||||
|
||||
constructor(url: string, options?: { auth: Partial<AuthOptions> }) {
|
||||
this.axios = axios.create({
|
||||
baseURL: url,
|
||||
});
|
||||
|
||||
this.authOptions = {
|
||||
storage:
|
||||
options?.auth?.storage !== undefined ? options.auth.storage : new MemoryStore(),
|
||||
mode: options?.auth?.mode !== undefined ? options.auth.mode : 'cookie',
|
||||
autoRefresh: options?.auth?.autoRefresh !== undefined ? options.auth.autoRefresh : true,
|
||||
};
|
||||
}
|
||||
|
||||
// Global helpers
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
get url() {
|
||||
return this.axios.defaults.baseURL!;
|
||||
}
|
||||
|
||||
set url(val: string) {
|
||||
this.axios.defaults.baseURL = val;
|
||||
}
|
||||
|
||||
// Handlers
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
items(collection: string) {
|
||||
if (collection.startsWith('directus_')) {
|
||||
throw new Error(`You can't read the "${collection}" collection directly.`);
|
||||
}
|
||||
|
||||
return new ItemsHandler(collection, this.axios);
|
||||
}
|
||||
|
||||
get activity() {
|
||||
return new ActivityHandler(this.axios);
|
||||
}
|
||||
|
||||
get auth() {
|
||||
return new AuthHandler(this.axios, this.authOptions);
|
||||
}
|
||||
|
||||
get collections() {
|
||||
return new CollectionsHandler(this.axios);
|
||||
}
|
||||
|
||||
get fields() {
|
||||
return new FieldsHandler(this.axios);
|
||||
}
|
||||
|
||||
get files() {
|
||||
return new FilesHandler(this.axios);
|
||||
}
|
||||
|
||||
get folders() {
|
||||
return new FoldersHandler(this.axios);
|
||||
}
|
||||
|
||||
get permissions() {
|
||||
return new PermissionsHandler(this.axios);
|
||||
}
|
||||
|
||||
get presets() {
|
||||
return new PresetsHandler(this.axios);
|
||||
}
|
||||
|
||||
get relations() {
|
||||
return new RelationsHandler(this.axios);
|
||||
}
|
||||
|
||||
get revisions() {
|
||||
return new RevisionsHandler(this.axios);
|
||||
}
|
||||
|
||||
get roles() {
|
||||
return new RolesHandler(this.axios);
|
||||
}
|
||||
|
||||
get server() {
|
||||
return new ServerHandler(this.axios);
|
||||
}
|
||||
|
||||
get settings() {
|
||||
return new SettingsHandler(this.axios);
|
||||
}
|
||||
|
||||
get users() {
|
||||
return new UsersHandler(this.axios);
|
||||
}
|
||||
|
||||
get utils() {
|
||||
return new UtilsHandler(this.axios);
|
||||
}
|
||||
}
|
||||
52
packages/sdk-js/src/types.ts
Normal file
52
packages/sdk-js/src/types.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
export type Item = Record<string, any>;
|
||||
export type Payload = Record<string, any>;
|
||||
export type PrimaryKey = string | number;
|
||||
|
||||
export enum Meta {
|
||||
TOTAL_COUNT = 'total_count',
|
||||
FILTER_COUNT = 'filter_count',
|
||||
}
|
||||
|
||||
export type Response<T> = {
|
||||
data: T | null;
|
||||
meta?: Record<Meta, number>;
|
||||
};
|
||||
|
||||
export type Query = {
|
||||
fields?: string | string[];
|
||||
sort?: string;
|
||||
filter?: Filter;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
page?: number;
|
||||
single?: boolean;
|
||||
meta?: Meta[];
|
||||
search?: string;
|
||||
export?: 'json' | 'csv';
|
||||
deep?: Record<string, Query>;
|
||||
};
|
||||
|
||||
export type Filter = {
|
||||
[keyOrOperator: string]: Filter | string | boolean | number | string[];
|
||||
};
|
||||
|
||||
export type FilterOperator =
|
||||
| '_eq'
|
||||
| '_neq'
|
||||
| '_contains'
|
||||
| '_ncontains'
|
||||
| '_in'
|
||||
| '_nin'
|
||||
| '_gt'
|
||||
| '_gte'
|
||||
| '_lt'
|
||||
| '_lte'
|
||||
| '_null'
|
||||
| '_nnull'
|
||||
| '_empty'
|
||||
| '_nempty';
|
||||
|
||||
export type AuthStorage = {
|
||||
getItem: (key: string) => Promise<any>;
|
||||
setItem: (key: string, value: any) => Promise<any>;
|
||||
};
|
||||
1
packages/sdk-js/src/utils/index.ts
Normal file
1
packages/sdk-js/src/utils/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './memory-store';
|
||||
13
packages/sdk-js/src/utils/memory-store.ts
Normal file
13
packages/sdk-js/src/utils/memory-store.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { AuthStorage } from '../types';
|
||||
|
||||
export class MemoryStore implements AuthStorage {
|
||||
private values: Record<string, any> = {};
|
||||
|
||||
async getItem(key: string) {
|
||||
return this.values[key];
|
||||
}
|
||||
|
||||
async setItem(key: string, value: any) {
|
||||
this.values[key] = value;
|
||||
}
|
||||
}
|
||||
94
packages/sdk-js/tests/handlers/activity.ts
Normal file
94
packages/sdk-js/tests/handlers/activity.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { ActivityHandler } from '../../src/handlers/activity';
|
||||
import { ItemsHandler } from '../../src/handlers/items';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('ActivityHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: ActivityHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new ActivityHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('Initializes ItemHandler instance', () => {
|
||||
expect(handler['itemsHandler']).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
|
||||
describe('read', () => {
|
||||
it('Calls ItemsHandler#read with the provided params', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['itemsHandler'], 'read')
|
||||
.returns(Promise.resolve({ data: {} }));
|
||||
|
||||
await handler.read();
|
||||
expect(stub).to.have.been.calledWith();
|
||||
|
||||
await handler.read(15);
|
||||
expect(stub).to.have.been.calledWith(15);
|
||||
|
||||
await handler.read([15, 41]);
|
||||
expect(stub).to.have.been.calledWith([15, 41]);
|
||||
|
||||
await handler.read([15, 41], { fields: ['title'] });
|
||||
expect(stub).to.have.been.calledWith([15, 41], { fields: ['title'] });
|
||||
});
|
||||
});
|
||||
|
||||
describe('comments.create', () => {
|
||||
it('Calls the /activity/comments endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'post')
|
||||
.returns(Promise.resolve({ data: {} }));
|
||||
|
||||
await handler.comments.create({
|
||||
collection: 'articles',
|
||||
item: '15',
|
||||
comment: 'Hello World',
|
||||
});
|
||||
|
||||
expect(stub).to.have.been.calledWith('/activity/comments', {
|
||||
collection: 'articles',
|
||||
item: '15',
|
||||
comment: 'Hello World',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('comments.update', () => {
|
||||
it('Calls the /activity/comments/:id endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'patch')
|
||||
.returns(Promise.resolve({ data: {} }));
|
||||
|
||||
await handler.comments.update(15, { comment: 'Hello Update' });
|
||||
|
||||
expect(stub).to.have.been.calledWith('/activity/comments/15', {
|
||||
comment: 'Hello Update',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('comments.delete', () => {
|
||||
it('Calls the /activity/comments/:id endpoint', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'delete').returns(Promise.resolve());
|
||||
|
||||
await handler.comments.delete(15);
|
||||
|
||||
expect(stub).to.have.been.calledWith('/activity/comments/15');
|
||||
});
|
||||
});
|
||||
});
|
||||
235
packages/sdk-js/tests/handlers/auth.ts
Normal file
235
packages/sdk-js/tests/handlers/auth.ts
Normal file
@@ -0,0 +1,235 @@
|
||||
import { AuthHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox, SinonFakeTimers } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
import { MemoryStore } from '../../src/utils/memory-store';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
const mockResponse = {
|
||||
data: {
|
||||
access_token: 'abc.def.ghi',
|
||||
refresh_token: 'jkl.mno.pqr',
|
||||
expires: 900000,
|
||||
},
|
||||
};
|
||||
|
||||
Object.freeze(mockResponse);
|
||||
|
||||
describe('AuthHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: AuthHandler;
|
||||
let clock: SinonFakeTimers;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new AuthHandler(axiosInstance, {
|
||||
mode: 'json',
|
||||
autoRefresh: false,
|
||||
storage: new MemoryStore(),
|
||||
});
|
||||
clock = sinon.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
clock.restore();
|
||||
});
|
||||
|
||||
describe('token', () => {
|
||||
it('Sets token as auth header in Axios', () => {
|
||||
handler.token = 'test';
|
||||
expect(handler['axios'].defaults.headers.Authorization).to.equal('Bearer test');
|
||||
});
|
||||
|
||||
it('Deletes the defaults auth header to undefined when token is set to a falsey value', () => {
|
||||
handler['axios'].defaults.headers.Authorization = 'Bearer test';
|
||||
handler.token = null;
|
||||
expect(handler['axios'].defaults.headers.Authorization).to.be.undefined;
|
||||
});
|
||||
|
||||
it('Gets the token from Axios default header', () => {
|
||||
handler['axios'].defaults.headers.Authorization = 'Bearer test';
|
||||
expect(handler.token).to.equal('test');
|
||||
});
|
||||
|
||||
it('Returns null if headers do not exist, or if token is not set', () => {
|
||||
handler['axios'].defaults.headers = null;
|
||||
expect(handler.token).to.be.null;
|
||||
|
||||
handler['axios'].defaults.headers = { Authorization: null };
|
||||
expect(handler.token).to.be.null;
|
||||
|
||||
handler['axios'].defaults.headers.Authorization = 'Invalid';
|
||||
expect(handler.token).to.be.null;
|
||||
});
|
||||
|
||||
it('Preserves the other existing default headers', () => {
|
||||
handler['axios'].defaults.headers = {
|
||||
Test: 'example',
|
||||
};
|
||||
|
||||
handler.token = 'Rijk';
|
||||
|
||||
expect(handler['axios'].defaults.headers.Test).to.exist;
|
||||
});
|
||||
|
||||
it('Defaults to {} if no default headers exist yet', () => {
|
||||
handler['axios'].defaults.headers = null;
|
||||
handler.token = 'Rijk';
|
||||
expect(handler['axios'].defaults.headers.Authorization).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
describe('login', () => {
|
||||
it('Calls the /auth/login endpoint', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
await handler.login({ email: 'test@example.com', password: 'test' });
|
||||
expect(stub).to.have.been.calledWith('/auth/login', {
|
||||
email: 'test@example.com',
|
||||
password: 'test',
|
||||
mode: 'json',
|
||||
});
|
||||
});
|
||||
|
||||
it('Sets the token after retrieval', async () => {
|
||||
sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
await handler.login({ email: 'test@example.com', password: 'test' });
|
||||
expect(handler['token']).to.equal('abc.def.ghi');
|
||||
});
|
||||
|
||||
it('Adds the refresh token to the passed store in JSON mode', async () => {
|
||||
sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
const testStore = new MemoryStore();
|
||||
const stub = sandbox.stub(testStore, 'setItem');
|
||||
|
||||
handler['storage'] = testStore;
|
||||
|
||||
handler['mode'] = 'json';
|
||||
await handler.login({ email: 'test@example.com', password: 'test' });
|
||||
expect(stub).to.have.been.calledWith('directus_refresh_token', 'jkl.mno.pqr');
|
||||
});
|
||||
|
||||
it('Does not attempt to set the refresh token in cookie mode', async () => {
|
||||
sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
const testStore = new MemoryStore();
|
||||
const stub = sandbox.stub(testStore, 'setItem');
|
||||
|
||||
handler['mode'] = 'cookie';
|
||||
await handler.login({ email: 'test@example.com', password: 'test' });
|
||||
expect(stub).to.not.have.been.called;
|
||||
});
|
||||
|
||||
it('Calls refresh 10 seconds before expiry time when in autoRefresh mode', async () => {
|
||||
sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
handler['autoRefresh'] = true;
|
||||
const stub = sandbox.stub(handler, 'refresh').resolves();
|
||||
await handler.login({ email: 'test@example.com', password: 'test' });
|
||||
|
||||
clock.tick(885000); // 15 seconds before expiry time
|
||||
expect(stub).to.not.have.been.called;
|
||||
clock.tick(6000); // add +6s
|
||||
expect(stub).to.have.been.called;
|
||||
});
|
||||
|
||||
it('Does not call refresh when not in auto refresh mode', async () => {
|
||||
sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
handler['autoRefresh'] = false;
|
||||
const stub = sandbox.stub(handler, 'refresh').resolves();
|
||||
await handler.login({ email: 'test@example.com', password: 'test' });
|
||||
|
||||
clock.tick(910000);
|
||||
expect(stub).to.not.have.been.called;
|
||||
});
|
||||
});
|
||||
|
||||
describe('refresh', () => {
|
||||
it('Calls the /auth/refresh endpoint without refresh token when in cookie mode', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
handler['mode'] = 'cookie';
|
||||
await handler.refresh();
|
||||
expect(stub).to.have.been.calledWith('/auth/refresh', { mode: 'cookie' });
|
||||
});
|
||||
|
||||
it('Passes the refresh token from the store when using JSON mode', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
handler['mode'] = 'json';
|
||||
const testStore = new MemoryStore();
|
||||
testStore['values'].directus_refresh_token = 'test-token';
|
||||
handler['storage'] = testStore;
|
||||
await handler.refresh();
|
||||
expect(stub).to.have.been.calledWith('/auth/refresh', {
|
||||
mode: 'json',
|
||||
refresh_token: 'test-token',
|
||||
});
|
||||
});
|
||||
|
||||
it('Sets the token on refresh', async () => {
|
||||
sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
handler.token = 'before';
|
||||
await handler.refresh();
|
||||
expect(handler.token).to.equal('abc.def.ghi');
|
||||
});
|
||||
|
||||
it('Adds the refresh token to the passed store in JSON mode', async () => {
|
||||
sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
const testStore = new MemoryStore();
|
||||
const stub = sandbox.stub(testStore, 'setItem');
|
||||
|
||||
handler['storage'] = testStore;
|
||||
|
||||
handler['mode'] = 'json';
|
||||
await handler.refresh();
|
||||
expect(stub).to.have.been.calledWith('directus_refresh_token', 'jkl.mno.pqr');
|
||||
});
|
||||
|
||||
it('Calls itself 10 seconds before expiry when autoRefresh is enabled', async () => {
|
||||
sandbox.stub(handler['axios'], 'post').resolves({ data: mockResponse });
|
||||
handler['autoRefresh'] = true;
|
||||
const spy = sandbox.spy(handler, 'refresh');
|
||||
await handler.refresh();
|
||||
clock.tick(910000);
|
||||
|
||||
expect(spy).to.have.been.calledTwice;
|
||||
});
|
||||
});
|
||||
|
||||
describe('logout', () => {
|
||||
it('Calls the /auth/logout endpoint', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'post').resolves();
|
||||
await handler.logout();
|
||||
expect(stub).to.have.been.calledWith('/auth/logout');
|
||||
});
|
||||
|
||||
it('Nullifies the token', async () => {
|
||||
sandbox.stub(handler['axios'], 'post').resolves();
|
||||
handler.token = 'test-token';
|
||||
await handler.logout();
|
||||
expect(handler.token).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('password.request', () => {
|
||||
it('Calls the /auth/password/request endpoint', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'post').resolves();
|
||||
await handler.password.request('admin@example.com');
|
||||
expect(stub).to.have.been.calledWith('/auth/password/request', {
|
||||
email: 'admin@example.com',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('password.reset', () => {
|
||||
it('Calls the /auth/password/reset endpoint', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'post').resolves();
|
||||
await handler.password.reset('abc.def.ghi', 'p455w0rd');
|
||||
expect(stub).to.have.been.calledWith('/auth/password/reset', {
|
||||
token: 'abc.def.ghi',
|
||||
password: 'p455w0rd',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/collections.ts
Normal file
27
packages/sdk-js/tests/handlers/collections.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { CollectionsHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('CollectionsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: CollectionsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new CollectionsHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/fields.ts
Normal file
27
packages/sdk-js/tests/handlers/fields.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { FieldsHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('FieldsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: FieldsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new FieldsHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/files.ts
Normal file
27
packages/sdk-js/tests/handlers/files.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { FilesHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('FilesHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: FilesHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new FilesHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/folders.ts
Normal file
27
packages/sdk-js/tests/handlers/folders.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { FoldersHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('FoldersHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: FoldersHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new FoldersHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
164
packages/sdk-js/tests/handlers/items.ts
Normal file
164
packages/sdk-js/tests/handlers/items.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import { ItemsHandler } from '../../src/handlers/items';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('ItemsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: ItemsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new ItemsHandler('test', axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('constructor', () => {
|
||||
it('Sets the correct endpoint', () => {
|
||||
const handler = new ItemsHandler('test', axiosInstance);
|
||||
expect(handler['endpoint']).to.equal('/items/test/');
|
||||
|
||||
const handler2 = new ItemsHandler('directus_activity', axiosInstance);
|
||||
expect(handler2['endpoint']).to.equal('/activity/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('Calls the /items/:collection endpoint when creating a single item', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'post').resolves({ data: '' });
|
||||
await handler.create({ title: 'test' });
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/items/test/',
|
||||
{ title: 'test' },
|
||||
{ params: undefined }
|
||||
);
|
||||
});
|
||||
|
||||
it('Calls the /items/:collection endpoint when creating multiple items', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'post').resolves({ data: '' });
|
||||
await handler.create([{ title: 'test' }, { title: 'another test' }]);
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/items/test/',
|
||||
[{ title: 'test' }, { title: 'another test' }],
|
||||
{ params: undefined }
|
||||
);
|
||||
});
|
||||
|
||||
it('Passes the query params', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'post').resolves({ data: '' });
|
||||
await handler.create({ title: 'test' }, { fields: ['test'] });
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/items/test/',
|
||||
{ title: 'test' },
|
||||
{ params: { fields: ['test'] } }
|
||||
);
|
||||
|
||||
await handler.create([{ title: 'test' }, { title: 'another test' }], {
|
||||
fields: ['test'],
|
||||
});
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/items/test/',
|
||||
[{ title: 'test' }, { title: 'another test' }],
|
||||
{ params: { fields: ['test'] } }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('read', () => {
|
||||
it('Reads all with no params', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'get').resolves({ data: '' });
|
||||
await handler.read();
|
||||
expect(stub).to.have.been.calledWith('/items/test/', { params: {} });
|
||||
});
|
||||
|
||||
it('Does not set the PK when only using query', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'get').resolves({ data: '' });
|
||||
await handler.read({ fields: ['test'] });
|
||||
expect(stub).to.have.been.calledWith('/items/test/', { params: { fields: ['test'] } });
|
||||
});
|
||||
|
||||
it('Adds the PK when set', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'get').resolves({ data: '' });
|
||||
await handler.read(15);
|
||||
expect(stub).to.have.been.calledWith('/items/test/15');
|
||||
});
|
||||
|
||||
it('Sets both pk and query', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'get').resolves({ data: '' });
|
||||
await handler.read(15, { fields: ['test'] });
|
||||
expect(stub).to.have.been.calledWith('/items/test/15', {
|
||||
params: { fields: ['test'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
it('Updates a single item to a new value', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'patch').resolves({ data: '' });
|
||||
await handler.update(15, { test: 'new value' });
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/items/test/15',
|
||||
{ test: 'new value' },
|
||||
{ params: undefined }
|
||||
);
|
||||
|
||||
await handler.update(15, { test: 'new value' }, { fields: ['test'] });
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/items/test/15',
|
||||
{ test: 'new value' },
|
||||
{ params: { fields: ['test'] } }
|
||||
);
|
||||
});
|
||||
|
||||
it('Updates multiple items to a new value', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'patch').resolves({ data: '' });
|
||||
await handler.update([15, 42], { test: 'new value' });
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/items/test/15,42',
|
||||
{ test: 'new value' },
|
||||
{ params: undefined }
|
||||
);
|
||||
|
||||
await handler.update([15, 42], { test: 'new value' }, { fields: ['test'] });
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/items/test/15,42',
|
||||
{ test: 'new value' },
|
||||
{ params: { fields: ['test'] } }
|
||||
);
|
||||
});
|
||||
|
||||
it('Allows updating by query', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'patch').resolves({ data: '' });
|
||||
|
||||
await handler.update({ archived: true }, { filter: {} });
|
||||
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/items/test/',
|
||||
{ archived: true },
|
||||
{ params: { filter: {} } }
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
it('Deletes a single item', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'delete').resolves();
|
||||
await handler.delete(15);
|
||||
expect(stub).to.have.been.calledWith('/items/test/15');
|
||||
});
|
||||
|
||||
it('Deletes multiple items', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'delete').resolves();
|
||||
await handler.delete([15, 42]);
|
||||
expect(stub).to.have.been.calledWith('/items/test/15,42');
|
||||
});
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/permissions.ts
Normal file
27
packages/sdk-js/tests/handlers/permissions.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { PermissionsHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('PermissionsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: PermissionsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new PermissionsHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/presets.ts
Normal file
27
packages/sdk-js/tests/handlers/presets.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { PresetsHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('PresetsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: PresetsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new PresetsHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/relations.ts
Normal file
27
packages/sdk-js/tests/handlers/relations.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { RelationsHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('RelationsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: RelationsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new RelationsHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/revisions.ts
Normal file
27
packages/sdk-js/tests/handlers/revisions.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { RevisionsHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('RevisionsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: RevisionsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new RevisionsHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/roles.ts
Normal file
27
packages/sdk-js/tests/handlers/roles.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { PresetsHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('PresetsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: PresetsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new PresetsHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
51
packages/sdk-js/tests/handlers/server.ts
Normal file
51
packages/sdk-js/tests/handlers/server.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { ServerHandler } from '../../src/handlers/server';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('ServerHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: ServerHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new ServerHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('specs.oas', () => {
|
||||
it('Calls the /server/specs/oas endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'get')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.specs.oas();
|
||||
expect(stub).to.have.been.calledWith('/server/specs/oas');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ping', () => {
|
||||
it('Calls the /server/ping endpoint', async () => {
|
||||
const stub = sandbox.stub(handler['axios'], 'get').returns(Promise.resolve('pong'));
|
||||
await handler.ping();
|
||||
expect(stub).to.have.been.calledWith('/server/ping');
|
||||
});
|
||||
});
|
||||
|
||||
describe('info', () => {
|
||||
it('Calls the /server/info endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'get')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.info();
|
||||
expect(stub).to.have.been.calledWith('/server/info');
|
||||
});
|
||||
});
|
||||
});
|
||||
27
packages/sdk-js/tests/handlers/settings.ts
Normal file
27
packages/sdk-js/tests/handlers/settings.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { SettingsHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('SettingsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: SettingsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new SettingsHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
});
|
||||
118
packages/sdk-js/tests/handlers/users.ts
Normal file
118
packages/sdk-js/tests/handlers/users.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { UsersHandler, ItemsHandler } from '../../src/handlers';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('UsersHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: UsersHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new UsersHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('Extends ItemsHandler', () => {
|
||||
expect(handler).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
|
||||
describe('invite', () => {
|
||||
it('Calls the /users/invite endpoint', async () => {
|
||||
const stub = sandbox.stub(handler.axios, 'post').resolves(Promise.resolve());
|
||||
|
||||
await handler.invite('admin@example.com', 'abc');
|
||||
expect(stub).to.have.been.calledWith('/users/invite', {
|
||||
email: 'admin@example.com',
|
||||
role: 'abc',
|
||||
});
|
||||
|
||||
await handler.invite(['admin@example.com', 'user@example.com'], 'abc');
|
||||
expect(stub).to.have.been.calledWith('/users/invite', {
|
||||
email: ['admin@example.com', 'user@example.com'],
|
||||
role: 'abc',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('acceptInvite', () => {
|
||||
it('Calls the /users/invite/accept endpoint', async () => {
|
||||
const stub = sandbox.stub(handler.axios, 'post').resolves(Promise.resolve());
|
||||
|
||||
await handler.acceptInvite('abc.def.ghi', 'p455w0rd');
|
||||
|
||||
expect(stub).to.have.been.calledWith('/users/invite/accept', {
|
||||
token: 'abc.def.ghi',
|
||||
password: 'p455w0rd',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tfa.enable', () => {
|
||||
it('Calls the /users/tfa/enable endpoint', async () => {
|
||||
const stub = sandbox.stub(handler.axios, 'post').resolves(Promise.resolve());
|
||||
|
||||
await handler.tfa.enable('p455w0rd');
|
||||
|
||||
expect(stub).to.have.been.calledWith('/users/tfa/enable', {
|
||||
password: 'p455w0rd',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('tfa.disable', () => {
|
||||
it('Calls the /users/tfa/disable endpoint', async () => {
|
||||
const stub = sandbox.stub(handler.axios, 'post').resolves(Promise.resolve());
|
||||
|
||||
await handler.tfa.disable('351851');
|
||||
|
||||
expect(stub).to.have.been.calledWith('/users/tfa/disable', {
|
||||
otp: '351851',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('me.read', () => {
|
||||
it('Calls the /users/me endpoint', async () => {
|
||||
const stub = sandbox.stub(handler.axios, 'get').resolves(Promise.resolve({ data: {} }));
|
||||
|
||||
await handler.me.read();
|
||||
expect(stub).to.have.been.calledWith('/users/me');
|
||||
|
||||
await handler.me.read({ fields: ['first_name'] });
|
||||
expect(stub).to.have.been.calledWith('/users/me', {
|
||||
params: { fields: ['first_name'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('me.update', () => {
|
||||
it('Calls the /users/me endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler.axios, 'patch')
|
||||
.resolves(Promise.resolve({ data: {} }));
|
||||
|
||||
await handler.me.update({ first_name: 'Rijk' });
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/users/me',
|
||||
{ first_name: 'Rijk' },
|
||||
{ params: undefined }
|
||||
);
|
||||
|
||||
await handler.me.update({ first_name: 'Rijk' }, { fields: ['first_name'] });
|
||||
expect(stub).to.have.been.calledWith(
|
||||
'/users/me',
|
||||
{ first_name: 'Rijk' },
|
||||
{ params: { fields: ['first_name'] } }
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
104
packages/sdk-js/tests/handlers/utils.ts
Normal file
104
packages/sdk-js/tests/handlers/utils.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { UtilsHandler } from '../../src/handlers/utils';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import sinon, { SinonSandbox } from 'sinon';
|
||||
import chai, { expect } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('UtilsHandler', () => {
|
||||
let sandbox: SinonSandbox;
|
||||
let axiosInstance: AxiosInstance;
|
||||
let handler: UtilsHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
axiosInstance = axios.create();
|
||||
handler = new UtilsHandler(axiosInstance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('random.string', () => {
|
||||
it('Calls the /utils/random/string endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'get')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.random.string();
|
||||
expect(stub).to.have.been.calledWith('/utils/random/string', {
|
||||
params: { length: 32 },
|
||||
});
|
||||
});
|
||||
|
||||
it('Passes the parameter to the length query param', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'get')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.random.string(15);
|
||||
expect(stub).to.have.been.calledWith('/utils/random/string', {
|
||||
params: { length: 15 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hash.generate', () => {
|
||||
it('Calls the /utils/hash/generate endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'post')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.hash.generate('test');
|
||||
expect(stub).to.have.been.calledWith('/utils/hash/generate');
|
||||
});
|
||||
|
||||
it('Passes the parameter as string in body', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'post')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.hash.generate('test');
|
||||
expect(stub).to.have.been.calledWith('/utils/hash/generate', { string: 'test' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('hash.verify', () => {
|
||||
it('Calls the /utils/hash/verify endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'post')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.hash.verify('test', '$argonHash');
|
||||
expect(stub).to.have.been.calledWith('/utils/hash/verify');
|
||||
});
|
||||
|
||||
it('Passes the parameters as string, hash in body', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'post')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.hash.verify('test', '$argonHash');
|
||||
expect(stub).to.have.been.calledWith('/utils/hash/verify', {
|
||||
string: 'test',
|
||||
hash: '$argonHash',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('sort', () => {
|
||||
it('Calls the /utils/sort/:collection endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'post')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.sort('articles', 10, 15);
|
||||
expect(stub).to.have.been.calledWith('/utils/sort/articles', { item: 10, to: 15 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('revert', () => {
|
||||
it('Calls the /utils/revert/:revision endpoint', async () => {
|
||||
const stub = sandbox
|
||||
.stub(handler['axios'], 'post')
|
||||
.returns(Promise.resolve({ data: '' }));
|
||||
await handler.revert(25);
|
||||
expect(stub).to.have.been.calledWith('/utils/revert/25');
|
||||
});
|
||||
});
|
||||
});
|
||||
135
packages/sdk-js/tests/index.ts
Normal file
135
packages/sdk-js/tests/index.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import DirectusSDK from '../src/index';
|
||||
import {
|
||||
ItemsHandler,
|
||||
UtilsHandler,
|
||||
ActivityHandler,
|
||||
FoldersHandler,
|
||||
PermissionsHandler,
|
||||
PresetsHandler,
|
||||
RolesHandler,
|
||||
UsersHandler,
|
||||
SettingsHandler,
|
||||
FilesHandler,
|
||||
AuthHandler,
|
||||
CollectionsHandler,
|
||||
FieldsHandler,
|
||||
RelationsHandler,
|
||||
RevisionsHandler,
|
||||
ServerHandler,
|
||||
} from '../src/handlers/';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import { MemoryStore } from '../src/utils';
|
||||
|
||||
describe('DirectusSDK', () => {
|
||||
let directus: DirectusSDK;
|
||||
|
||||
beforeEach(() => (directus = new DirectusSDK('http://example.com')));
|
||||
|
||||
it('Initializes', () => {
|
||||
expect(directus).to.be.instanceOf(DirectusSDK);
|
||||
});
|
||||
|
||||
it('Sets the passed authOptions', () => {
|
||||
const fakeStore = { async getItem() {}, async setItem() {} };
|
||||
const directusWithOptions = new DirectusSDK('http://example.com', {
|
||||
auth: {
|
||||
autoRefresh: false,
|
||||
storage: fakeStore,
|
||||
mode: 'json',
|
||||
},
|
||||
});
|
||||
|
||||
expect(directusWithOptions['authOptions'].autoRefresh).to.be.false;
|
||||
expect(directusWithOptions['authOptions'].mode).to.equal('json');
|
||||
expect(directusWithOptions['authOptions'].storage).to.equal(fakeStore);
|
||||
});
|
||||
|
||||
it('Defaults to the correct auth options', () => {
|
||||
expect(directus['authOptions'].autoRefresh).to.be.true;
|
||||
expect(directus['authOptions'].mode).to.equal('cookie');
|
||||
expect(directus['authOptions'].storage).to.be.instanceOf(MemoryStore);
|
||||
});
|
||||
|
||||
it('Gets / Sets URL', () => {
|
||||
expect(directus.url).to.equal('http://example.com');
|
||||
|
||||
directus.url = 'http://different.example.com';
|
||||
expect(directus.url).to.equal('http://different.example.com');
|
||||
});
|
||||
|
||||
it('Syncs URL with Axios base instance', () => {
|
||||
expect(directus.axios.defaults.baseURL).to.equal('http://example.com');
|
||||
|
||||
directus.url = 'http://different.example.com';
|
||||
expect(directus.axios.defaults.baseURL).to.equal('http://different.example.com');
|
||||
});
|
||||
|
||||
it('Returns ItemsHandler instance for #items', () => {
|
||||
expect(directus.items('articles')).to.be.instanceOf(ItemsHandler);
|
||||
});
|
||||
|
||||
it('Errors when trying to read a system collection directly', () => {
|
||||
expect(() => directus.items('directus_files')).to.throw();
|
||||
});
|
||||
|
||||
it('Returns ActivityHandler instance for #activity', () => {
|
||||
expect(directus.activity).to.be.instanceOf(ActivityHandler);
|
||||
});
|
||||
|
||||
it('Returns AuthHandler for #auth', () => {
|
||||
expect(directus.auth).to.be.instanceOf(AuthHandler);
|
||||
});
|
||||
|
||||
it('Returns CollectionsHandler for #collections', () => {
|
||||
expect(directus.collections).to.be.instanceOf(CollectionsHandler);
|
||||
});
|
||||
|
||||
it('Returns FieldsHandler for #fields', () => {
|
||||
expect(directus.fields).to.be.instanceOf(FieldsHandler);
|
||||
});
|
||||
|
||||
it('Returns FilesHandler for #users', () => {
|
||||
expect(directus.files).to.be.instanceOf(FilesHandler);
|
||||
});
|
||||
|
||||
it('Returns FoldersHandler for #folders', () => {
|
||||
expect(directus.folders).to.be.instanceOf(FoldersHandler);
|
||||
});
|
||||
|
||||
it('Returns PermissionsHandler for #permissions', () => {
|
||||
expect(directus.permissions).to.be.instanceOf(PermissionsHandler);
|
||||
});
|
||||
|
||||
it('Returns PresetsHandler for #presets', () => {
|
||||
expect(directus.presets).to.be.instanceOf(PresetsHandler);
|
||||
});
|
||||
|
||||
it('Returns RelationsHandler for #roles', () => {
|
||||
expect(directus.relations).to.be.instanceOf(RelationsHandler);
|
||||
});
|
||||
|
||||
it('Returns RevisionsHandler for #revisions', () => {
|
||||
expect(directus.revisions).to.be.instanceOf(RevisionsHandler);
|
||||
});
|
||||
|
||||
it('Returns RolesHandler for #roles', () => {
|
||||
expect(directus.roles).to.be.instanceOf(RolesHandler);
|
||||
});
|
||||
|
||||
it('Returns ServerHandler for #server', () => {
|
||||
expect(directus.server).to.be.instanceOf(ServerHandler);
|
||||
});
|
||||
|
||||
it('Returns SettingsHandler for #settings', () => {
|
||||
expect(directus.settings).to.be.instanceOf(SettingsHandler);
|
||||
});
|
||||
|
||||
it('Returns UsersHandler for #users', () => {
|
||||
expect(directus.users).to.be.instanceOf(UsersHandler);
|
||||
});
|
||||
|
||||
it('Returns UtilsHandler for #utils', () => {
|
||||
expect(directus.utils).to.be.instanceOf(UtilsHandler);
|
||||
});
|
||||
});
|
||||
19
packages/sdk-js/tests/utils.ts
Normal file
19
packages/sdk-js/tests/utils.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { MemoryStore } from '../src/utils/';
|
||||
import { expect } from 'chai';
|
||||
|
||||
describe('Utils', () => {
|
||||
describe('MemoryStore', () => {
|
||||
it('Gets values based on key', async () => {
|
||||
const store = new MemoryStore();
|
||||
store['values'].test = 'test';
|
||||
const result = await store.getItem('test');
|
||||
expect(result).to.equal('test');
|
||||
});
|
||||
|
||||
it('Sets value based on key', async () => {
|
||||
const store = new MemoryStore();
|
||||
await store.setItem('test', 'test');
|
||||
expect(store['values'].test).to.equal('test');
|
||||
});
|
||||
});
|
||||
});
|
||||
13
packages/sdk-js/tsconfig.json
Normal file
13
packages/sdk-js/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "tests", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user