diff --git a/.eslintignore b/.eslintignore
index d849ec6cc..91cef1057 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -3,12 +3,26 @@ src/**/*.d.ts
src/**/*.js.map
src/Kuzzle.js
+src/KuzzleError.js
src/controllers/Auth.js
src/controllers/Document.js
+src/controllers/Realtime.js
+src/controllers/Index.js
+src/controllers/Collection.js
src/controllers/Base.js
src/core/security/User.js
src/core/security/Profile.js
src/core/security/Role.js
+src/protocols/abstract/Base.js
+src/protocols/abstract/Realtime.js
+src/protocols/Http.js
+src/protocols/WebSocket.js
+src/protocols/index.js
src/utils/interfaces.js
+src/core/KuzzleEventEmitter.js
src/core/searchResult/SearchResultBase.js
src/core/searchResult/Document.js
+src/core/searchResult/Profile.js
+src/core/searchResult/Role.js
+src/core/searchResult/Specifications.js
+src/core/searchResult/User.js
diff --git a/.eslintc-ts.json b/.eslintrc-ts.json
similarity index 100%
rename from .eslintc-ts.json
rename to .eslintrc-ts.json
diff --git a/.gitignore b/.gitignore
index 1a1af6994..1f5aa706a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,12 +31,26 @@ test-*.js
*.js.map
index.js
src/Kuzzle.js
+src/KuzzleError.js
src/controllers/Auth.js
src/controllers/Document.js
+src/controllers/Index.js
+src/controllers/Collection.js
src/controllers/Base.js
+src/controllers/Realtime.js
src/core/security/User.js
src/core/security/Profile.js
src/core/security/Role.js
+src/protocols/abstract/Base.js
+src/protocols/abstract/Realtime.js
+src/protocols/Http.js
+src/protocols/WebSocket.js
+src/protocols/index.js
src/utils/interfaces.js
+src/core/KuzzleEventEmitter.js
src/core/searchResult/SearchResultBase.js
src/core/searchResult/Document.js
+src/core/searchResult/Profile.js
+src/core/searchResult/Role.js
+src/core/searchResult/Specifications.js
+src/core/searchResult/User.js
diff --git a/.travis.yml b/.travis.yml
index aa2ac4cef..e932f0495 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,6 +32,7 @@ jobs:
install:
- npm install
+ - npm run build
script:
- npm run test:lint
@@ -78,7 +79,7 @@ jobs:
- npm install
- npm run build
script:
- - npm run doc-testing
+ - travis_retry npm run doc-testing
- stage: Tests
name: Dead link check
@@ -93,7 +94,7 @@ jobs:
- $(npm bin)/kuzdoc framework:link -d /sdk/js/7/ -v 7
script:
- gem install typhoeus
- - cd doc/framework/ && HYDRA_MAX_CONCURRENCY=20 ruby .ci/dead-links.rb -p src/sdk/js/7/
+ - cd doc/framework/ && HYDRA_MAX_CONCURRENCY=20 travis_retry ruby .ci/dead-links.rb -p src/sdk/js/7/
- stage: Deployment Doc Dev
name: Deploy next-docs.kuzzle.io
diff --git a/doc/7/controllers/auth/create-api-key/index.md b/doc/7/controllers/auth/create-api-key/index.md
index d7a2ca918..f0f301b9f 100644
--- a/doc/7/controllers/auth/create-api-key/index.md
+++ b/doc/7/controllers/auth/create-api-key/index.md
@@ -56,7 +56,7 @@ The API key content has the following properties:
| Name | Type | Description |
| --------- | ----------------- | ---------------- |
| `userId` |
string | User kuid |
-| `expiresAt` | number | Expiration date in UNIX micro-timestamp format (`-1` if the token never expires) |
+| `expiresAt` | number | Expiration date in Epoch-millis format (`-1` if the token never expires) |
| `ttl` | number | Original TTL |
| `description` | string | API key description |
| `token` | string | Authentication token associated with this API key |
diff --git a/doc/7/controllers/collection/create/index.md b/doc/7/controllers/collection/create/index.md
index 68ada4bda..4346f2a6d 100644
--- a/doc/7/controllers/collection/create/index.md
+++ b/doc/7/controllers/collection/create/index.md
@@ -7,17 +7,22 @@ description: Create a new collection
# create
-Creates a new [collection](/core/2/guides/essentials/store-access-data) in Kuzzle via the persistence engine, in the provided index.
+Creates a new [collection](/core/2/guides/essentials/store-access-data) in the provided index.
You can also provide an optional data mapping that allow you to exploit the full capabilities of our
-persistent data storage layer, [ElasticSearch](https://www.elastic.co/elastic-stack) (check here the [mapping capabilities of ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/reference/7.3/mapping.html)).
+persistent data storage layer, [ElasticSearch](https://www.elastic.co/elastic-stack) (check here the [mapping capabilities of ElasticSearch](/core/2/guides/essentials/database-mappings/)).
This method will only update the mapping if the collection already exists.
+
+
+
+You can also provide Elasticsearch [index settings](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/index-modules.html#index-modules-settings) when creating a new collection.
+
```js
-create(index, collection, [mapping], [options]);
+create(index, collection, [definition], [options]);
```
@@ -26,17 +31,48 @@ create(index, collection, [mapping], [options]);
| ------------ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `index` | string | Index name |
| `collection` | string | Collection name |
-| `mapping` | object | Describes the data mapping to associate to the new collection, using Elasticsearch [mapping format](https://www.elastic.co/guide/en/elasticsearch/reference/7.3/mapping.html) |
+| `definition` | object | Describes the collection mappings and the ES index settings |
| `options` | object | Query options |
+
-### mapping
-
-An object representing the data mapping of the collection.
+### definition
+An object containings:
+ - [collection mappings](/core/2/guides/essentials/database-mappings).
+ - Elasticsearch [index settings](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/index-modules.html#index-modules-settings)
The mapping must have a root field `properties` that contain the mapping definition:
```js
-const mapping = {
+const definition = {
+ mappings: {
+ properties: {
+ field1: { type: 'text' },
+ field2: {
+ properties: {
+ nestedField: { type: 'keyword' }
+ }
+ }
+ }
+ },
+ settings: {
+
+ }
+};
+```
+
+
+
+
+
+
+### definition
+
+An object representing the data mappings of the collection.
+
+The mappings must have a root field `properties` that contain the mappings properties definition:
+
+```js
+const mappings = {
properties: {
field1: { type: 'text' },
field2: {
@@ -50,6 +86,8 @@ const mapping = {
More informations about database mappings [here](/core/2/guides/essentials/database-mappings).
+
+
### options
Additional query options
diff --git a/doc/7/controllers/collection/create/snippets/create.js b/doc/7/controllers/collection/create/snippets/create.js
index 4c10502d6..89cc8a348 100644
--- a/doc/7/controllers/collection/create/snippets/create.js
+++ b/doc/7/controllers/collection/create/snippets/create.js
@@ -1,4 +1,4 @@
-const mapping = {
+const mappings = {
properties: {
license: { type: 'keyword' },
driver: {
@@ -11,7 +11,7 @@ const mapping = {
};
try {
- await kuzzle.collection.create('nyc-open-data', 'yellow-taxi', mapping);
+ await kuzzle.collection.create('nyc-open-data', 'yellow-taxi', { mappings });
console.log('Success');
} catch (error) {
diff --git a/doc/7/controllers/collection/delete/index.md b/doc/7/controllers/collection/delete/index.md
new file mode 100644
index 000000000..3cfa16394
--- /dev/null
+++ b/doc/7/controllers/collection/delete/index.md
@@ -0,0 +1,32 @@
+---
+code: true
+type: page
+title: delete
+description: Deletes a collection
+---
+
+# delete
+
+Deletes a collection.
+
+
+
+```js
+delete(index, collection);
+```
+
+
+
+| Arguments | Type | Description |
+| ------------ | ----------------- | --------------- |
+| `index` | string | Index name |
+| `collection` | string | Collection name |
+
+
+## Resolves
+
+Resolves if the collection is successfully deleted.
+
+## Usage
+
+<<< ./snippets/delete-specifications.js
diff --git a/doc/7/controllers/collection/delete/snippets/delete-specifications.js b/doc/7/controllers/collection/delete/snippets/delete-specifications.js
new file mode 100644
index 000000000..5dc6b5fd9
--- /dev/null
+++ b/doc/7/controllers/collection/delete/snippets/delete-specifications.js
@@ -0,0 +1,7 @@
+try {
+ await kuzzle.collection.delete('nyc-open-data', 'yellow-taxi');
+
+ console.log('Success');
+} catch (error) {
+ console.error(error.message);
+}
diff --git a/doc/7/controllers/collection/delete/snippets/delete-specifications.test.yml b/doc/7/controllers/collection/delete/snippets/delete-specifications.test.yml
new file mode 100644
index 000000000..69c1d5c18
--- /dev/null
+++ b/doc/7/controllers/collection/delete/snippets/delete-specifications.test.yml
@@ -0,0 +1,7 @@
+name: collection#delete
+description: Delete a collection
+hooks:
+ before: curl -X POST kuzzle:7512/nyc-open-data/_create && curl -X PUT kuzzle:7512/nyc-open-data/yellow-taxi
+ after:
+template: default
+expected: Success
diff --git a/doc/7/controllers/collection/exists/index.md b/doc/7/controllers/collection/exists/index.md
index 8a8000677..012fc4300 100644
--- a/doc/7/controllers/collection/exists/index.md
+++ b/doc/7/controllers/collection/exists/index.md
@@ -7,7 +7,7 @@ description: Check if collection exists
# exists
-Check if a collection exists in Kuzzle.
+Checks if a collection exists in Kuzzle.
diff --git a/doc/7/controllers/collection/get-mapping/index.md b/doc/7/controllers/collection/get-mapping/index.md
index 0f0fdcade..c01a9177e 100644
--- a/doc/7/controllers/collection/get-mapping/index.md
+++ b/doc/7/controllers/collection/get-mapping/index.md
@@ -30,6 +30,7 @@ Additional query options
| Property | Type (default) | Description |
| ---------- | ------------------------------- | ---------------------------------------------------------------------------- |
| `queuable` | boolean (`true`) | If true, queues the request during downtime, until connected to Kuzzle again |
+| `includeKuzzleMeta` | boolean (`true`) | If true, the returned mappings will contain [Kuzzle metadata](/core/2/guides/essentials/document-metadata/) |
## Resolves
diff --git a/doc/7/controllers/collection/refresh/index.md b/doc/7/controllers/collection/refresh/index.md
index b79d97a7d..407f0e6b5 100644
--- a/doc/7/controllers/collection/refresh/index.md
+++ b/doc/7/controllers/collection/refresh/index.md
@@ -7,7 +7,7 @@ description: Forces an Elasticsearch search index update
# refresh
-When writing or deleting documents in Kuzzle, the update needs to be indexed before being available in search results.
+Refreshes a collection to reindex the written and deleted documents so they are available in search results.
:::info
A refresh operation comes with some performance costs.
diff --git a/doc/7/controllers/collection/update-specifications/index.md b/doc/7/controllers/collection/update-specifications/index.md
index af9b1981d..b7947f2d7 100644
--- a/doc/7/controllers/collection/update-specifications/index.md
+++ b/doc/7/controllers/collection/update-specifications/index.md
@@ -7,7 +7,7 @@ description: Update the validation specifications
# updateSpecifications
-The updateSpecifications method allows you to create or update the validation specifications for a collection.
+Creates or updates the validation specifications for a collection.
When the validation specification is not formatted correctly, a detailed error message is returned to help you to debug.
diff --git a/doc/7/controllers/collection/update/index.md b/doc/7/controllers/collection/update/index.md
index f7edd238a..c39bc0e6b 100644
--- a/doc/7/controllers/collection/update/index.md
+++ b/doc/7/controllers/collection/update/index.md
@@ -13,28 +13,66 @@ You can define the collection [dynamic mapping policy](/core/2/guides/essentials
You can define [collection additional metadata](/core/2/guides/essentials/database-mappings#collection-metadata) within the `_meta` root field.
+
+
+
+You can also provide Elasticsearch [index settings](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/index-modules.html#index-modules-settings) when creating a new collection.
+
```js
-update(index, collection, mapping);
+update(index, collection, definition);
```
-| Arguments | Type | Description |
-| ------------ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `index` | string | Index name |
-| `collection` | string | Collection name |
-| `mapping` | object | Describes the collection mapping |
+| Arguments | Type | Description |
+|--------------|-------------------|-------------------------------------------------------------|
+| `index` | string | Index name |
+| `collection` | string | Collection name |
+| `definition` | object | Describes the collection mappings and the ES index settings |
+| `options` | object | Query options |
+
+
-### mapping
+### definition
-An object representing the collection data mapping.
+An object containing:
+ - [collection mappings](/core/2/guides/essentials/database-mappings).
+ - Elasticsearch [index settings](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/index-modules.html#index-modules-settings)
-This object must have a root field `properties` that contain the mapping definition:
```js
-const mapping = {
+const definition = {
+ mappings: {
+ properties: {
+ field1: { type: 'text' },
+ field2: {
+ properties: {
+ nestedField: { type: 'keyword' }
+ }
+ }
+ }
+ },
+ settings: {
+ // index settings (e.g. analyzers)
+ }
+};
+```
+
+
+
+
+
+
+### definition
+
+An object representing the data mappings of the collection.
+
+The mappings must have a root field `properties` that contain the mappings properties definition:
+
+```js
+const mappings = {
properties: {
field1: { type: 'text' },
field2: {
@@ -48,6 +86,9 @@ const mapping = {
More informations about database mappings [here](/core/2/guides/essentials/database-mappings).
+
+
+
## Resolves
Resolve if the collection is successfully updated.
diff --git a/doc/7/controllers/collection/validate-specifications/index.md b/doc/7/controllers/collection/validate-specifications/index.md
index cd5cf676b..f10474abe 100644
--- a/doc/7/controllers/collection/validate-specifications/index.md
+++ b/doc/7/controllers/collection/validate-specifications/index.md
@@ -7,7 +7,7 @@ description: Validate specifications format
# validateSpecifications
-The validateSpecifications method checks if a validation specification is well formatted. It does not store or modify the existing specification.
+Checks if a validation specification is well formatted. It does not store nor modify the existing specification.
When the validation specification is not formatted correctly, a detailed error message is returned to help you to debug.
diff --git a/doc/7/controllers/realtime/count/index.md b/doc/7/controllers/realtime/count/index.md
index d8beddf88..dd5c460ed 100644
--- a/doc/7/controllers/realtime/count/index.md
+++ b/doc/7/controllers/realtime/count/index.md
@@ -32,7 +32,7 @@ Additional query options
## Resolves
-Resolves to a number represensting active connections using the same provided subscription room.
+Resolves to a number representing active connections using the same provided subscription room.
## Usage
diff --git a/doc/7/controllers/security/create-api-key/index.md b/doc/7/controllers/security/create-api-key/index.md
index 35202ecb1..ae4722cb0 100644
--- a/doc/7/controllers/security/create-api-key/index.md
+++ b/doc/7/controllers/security/create-api-key/index.md
@@ -57,7 +57,7 @@ The API key content has the following properties:
| Name | Type | Description |
| --------- | ----------------- | ---------------- |
| `userId` | string | User kuid |
-| `expiresAt` | number | Aexpiration date in UNIX micro-timestamp format (`-1` if the token never expires) |
+| `expiresAt` | number | Aexpiration date in Epoch-millis format (`-1` if the token never expires) |
| `ttl` | number | Original TTL |
| `description` | string | API key description |
| `token` | string | Authentication token associated with this API key |
diff --git a/doc/7/controllers/security/m-delete-profiles/snippets/m-delete-profiles.test.yml b/doc/7/controllers/security/m-delete-profiles/snippets/m-delete-profiles.test.yml
index 6fbf0d363..0c7f7e2de 100644
--- a/doc/7/controllers/security/m-delete-profiles/snippets/m-delete-profiles.test.yml
+++ b/doc/7/controllers/security/m-delete-profiles/snippets/m-delete-profiles.test.yml
@@ -8,4 +8,4 @@ hooks:
}' kuzzle:7512/profiles/profile${i}/_create
done
template: default
-expected: '^\[ ''profile\d'', ''profile\d'', ''profile\d'', ''profile\d', ''profile\d'' \]$'
+expected: '^\[ ''profile\d'', ''profile\d'', ''profile\d'', ''profile\d'', ''profile\d'' \]$'
diff --git a/doc/7/controllers/security/m-delete-roles/snippets/m-delete-roles.test.yml b/doc/7/controllers/security/m-delete-roles/snippets/m-delete-roles.test.yml
index 5578d3834..1fb4967fa 100644
--- a/doc/7/controllers/security/m-delete-roles/snippets/m-delete-roles.test.yml
+++ b/doc/7/controllers/security/m-delete-roles/snippets/m-delete-roles.test.yml
@@ -14,4 +14,4 @@ hooks:
}' kuzzle:7512/roles/role${i}/_create
done
template: default
-expected: '^\[ ''role1'', ''role2'', ''role3'', ''role4'', ''role5'' \]$'
+expected: '^\[ ''role\d'', ''role\d'', ''role\d'', ''role\d'', ''role\d'' \]$'
diff --git a/doc/7/controllers/security/m-delete-users/snippets/m-delete-users.test.yml b/doc/7/controllers/security/m-delete-users/snippets/m-delete-users.test.yml
index be9ebea3d..ef0acb81b 100644
--- a/doc/7/controllers/security/m-delete-users/snippets/m-delete-users.test.yml
+++ b/doc/7/controllers/security/m-delete-users/snippets/m-delete-users.test.yml
@@ -16,4 +16,4 @@ hooks:
}' kuzzle:7512/users/user${i}/_create
done
template: default
-expected: '^\[ ''user1'', ''user2'', ''user3'' \]$'
+expected: '^\[ ''user\d'', ''user\d'', ''user\d'' \]$'
diff --git a/doc/7/core-classes/kuzzle-error/properties/index.md b/doc/7/core-classes/kuzzle-error/properties/index.md
index 1b5655e92..63b07a4f9 100644
--- a/doc/7/core-classes/kuzzle-error/properties/index.md
+++ b/doc/7/core-classes/kuzzle-error/properties/index.md
@@ -14,3 +14,6 @@ order: 10
| `message` | string | Error message |
| `status` | number | Error status code |
| `stack` | string | Error stacktrace (only in development mode) |
+| `id` | string | Error unique identifier |
+| `code` | string | Error unique code |
+
diff --git a/doc/7/core-classes/kuzzle/constructor/index.md b/doc/7/core-classes/kuzzle/constructor/index.md
index 2203444bc..6f076596f 100644
--- a/doc/7/core-classes/kuzzle/constructor/index.md
+++ b/doc/7/core-classes/kuzzle/constructor/index.md
@@ -46,6 +46,7 @@ Kuzzle SDK instance options.
| `queueTTL` | number (`120000`) | Time a queued request is kept during offline mode, in milliseconds |
| `queueMaxSize` | number (`500`) | Number of maximum requests kept during offline mode |
| `replayInterval` | number (`10`) | Delay between each replayed requests, in milliseconds |
+| `tokenExpiredInterval` | number (`1000`) | Time (in ms) during which a TokenExpired event is ignored |
| `volatile` | object (`{}`) | Common volatile data, will be sent to all future requests |
## Return
diff --git a/doc/7/essentials/error-handling/index.md b/doc/7/essentials/error-handling/index.md
index f19e943a8..fa56caac4 100644
--- a/doc/7/essentials/error-handling/index.md
+++ b/doc/7/essentials/error-handling/index.md
@@ -15,7 +15,9 @@ All SDK methods return a promise, that can be rejected with a `KuzzleError` valu
| Property | Type | Description |
| -------- | ----------------- | ------------------------------------------------------------------------------------------ |
| `status` | number | Status following [HTTP Standards](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) |
-| `stack` | string | Error stacktrace (Only in development mode) |
+| `stack` | string | Error stacktrace (Only in development mode) | `id` | string | Error unique identifier |
+| `code` | string | Error unique code |
+
You can find a detailed list of possible errors messages and statuses in the [documentation API](/core/2/api/essentials/error-handling).
diff --git a/doc/7/essentials/realtime-notifications/index.md b/doc/7/essentials/realtime-notifications/index.md
index cdc976ce7..86583db0d 100644
--- a/doc/7/essentials/realtime-notifications/index.md
+++ b/doc/7/essentials/realtime-notifications/index.md
@@ -23,7 +23,7 @@ These notifications represent [documents changes & messages](/core/2/api/essenti
| `protocol` | string | Network protocol used to modify the document |
| `result` | object | Notification content |
| `room` | string | Subscription channel identifier. Can be used to link a notification to its corresponding subscription |
-| `scope` | string | `in`: document enters (or stays) in the scope string | `in`: document enters (or stays) in the scope `out`: document leaves the scope |
| `timestamp` | number | Timestamp of the event, in Epoch-millis format |
| `type` | string | `document`: Notification type |
| `volatile` | object | Request [volatile data](/core/2/api/essentials/volatile-data) |
@@ -50,7 +50,7 @@ These notifications represent [user events](/core/2/api/essentials/notifications
| `room` | string | Subscription channel identifier. Can be used to link a notification to its corresponding subscription |
| `timestamp` | number | Timestamp of the event, in Epoch-millis format |
| `type` | string | `user`: Notification type |
-| `user` | string | `in`: a new user has subscribed to the same filters string | `in`: a new user has subscribed to the same filters `out`: a user cancelled a shared subscription |
| `volatile` | object | Request [volatile data](/core/2/api/essentials/volatile-data) |
The `result` object is the notification content, and it has the following structure:
diff --git a/doc/7/protocols/http/constructor/index.md b/doc/7/protocols/http/constructor/index.md
index d5ff3892f..a1aaddae1 100644
--- a/doc/7/protocols/http/constructor/index.md
+++ b/doc/7/protocols/http/constructor/index.md
@@ -30,7 +30,8 @@ Http protocol connection options.
| Property | Type (default) | Description |
| --------------- | -------------------------------- | ----------------------------------- |
| `port` | number (`7512`) | Kuzzle server port |
-| `sslConnection` | boolean (`false`) | Use SSL to connect to Kuzzle server |
+| `sslConnection` | boolean (`false`) | Use SSL to connect to Kuzzle server |
+| `ssl` | boolean (`false`) | Use SSL to connect to Kuzzle server. Defaults to `true` for ports 443 and 7443. |
| `customRoutes` | object (`{}`) | Add custom routes |
| `timeout` | number (`0`) | Connection timeout in milliseconds (`0` means no timeout) |
diff --git a/doc/7/protocols/websocket/constructor/index.md b/doc/7/protocols/websocket/constructor/index.md
index 736df3deb..7f770d046 100644
--- a/doc/7/protocols/websocket/constructor/index.md
+++ b/doc/7/protocols/websocket/constructor/index.md
@@ -31,9 +31,10 @@ WebSocket protocol connection options.
| ------------------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
| `autoReconnect` | boolean (`true`) | Automatically reconnect to kuzzle after a `disconnected` event |
| `port` | number (`7512`) | Kuzzle server port |
-| `headers` | object (`{}`) | Connection HTTP headers (e.g. origin, subprotocols, ...) **(Not supported by browsers)** |
+| `headers` | object (`{}`) | Connection custom HTTP headers (e.g. origin, subprotocols, ...) **(Not supported by browsers)** |
| `reconnectionDelay` | number (`1000`) | Number of milliseconds between reconnection attempts |
-| `sslConnection` | boolean (`false`) | Use SSL to connect to Kuzzle server |
+| `sslConnection` | boolean (`false`) | Use SSL to connect to Kuzzle server |
+| `ssl` | boolean (`false`) | Use SSL to connect to Kuzzle server. Defaults to `true` for ports 443 and 7443. |
## Return
diff --git a/index.ts b/index.ts
index b88efa680..dc87dfb68 100644
--- a/index.ts
+++ b/index.ts
@@ -8,34 +8,15 @@ if (typeof window !== 'undefined' && typeof BUILT === 'undefined') {
'Learn more at https://github.com/kuzzleio/sdk-javascript/tree/master#browser');
}
-import { Kuzzle } from './src/Kuzzle';
-import { Http, WebSocket } from './src/protocols';
-import { BaseController } from './src/controllers/Base';
-import { KuzzleAbstractProtocol } from './src/protocols/abstract/Base';
-import { KuzzleEventEmitter } from './src/core/KuzzleEventEmitter';
+export * from './src/Kuzzle';
+export * from './src/protocols';
+export * from './src/controllers/Base';
+export * from './src/protocols/abstract/Base';
+export * from './src/core/KuzzleEventEmitter';
-import { SearchResultBase } from './src/core/searchResult/SearchResultBase';
-import { DocumentSearchResult } from './src/core/searchResult/Document';
-import { ProfileSearchResult } from './src/core/searchResult/Profile';
-import { RoleSearchResult } from './src/core/searchResult/Role';
-import { SpecificationSearchResult } from './src/core/searchResult/Specifications';
-import { UserSearchResult } from './src/core/searchResult/User';
-
-const exported = {
- Kuzzle,
- Http,
- WebSocket,
- BaseController,
- KuzzleAbstractProtocol,
- KuzzleEventEmitter,
- SearchResultBase,
- DocumentSearchResult,
- ProfileSearchResult,
- RoleSearchResult,
- SpecificationSearchResult,
- UserSearchResult
-}
-
-export default exported;
-
-module.exports = exported;
+export * from './src/core/searchResult/SearchResultBase';
+export * from './src/core/searchResult/Document';
+export * from './src/core/searchResult/Profile';
+export * from './src/core/searchResult/Role';
+export * from './src/core/searchResult/Specifications';
+export * from './src/core/searchResult/User';
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 87472d4ad..1328d1680 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "kuzzle-sdk",
- "version": "7.3.1",
+ "version": "7.4.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 9e6a88c71..cdf7366c0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "kuzzle-sdk",
- "version": "7.3.1",
+ "version": "7.4.0",
"description": "Official Javascript SDK for Kuzzle",
"author": "The Kuzzle Team ",
"repository": {
@@ -24,7 +24,9 @@
"test:functional": "cucumber-js --exit --fail-fast",
"test:lint": "npm run test:lint:js && npm run test:lint:ts",
"test:lint:js": "eslint --max-warnings=0 ./src ./test ./features",
- "test:lint:ts": "eslint ./src --ext .ts --config .eslintc-ts.json",
+ "test:lint:js:fix": "eslint --max-warnings=0 ./src ./test ./features --fix",
+ "test:lint:ts": "eslint ./src --ext .ts --config .eslintrc-ts.json",
+ "test:lint:ts:fix": "eslint ./src --ext .ts --config .eslintrc-ts.json --fix",
"build": "npm run build-ts && node build.js",
"build-ts": "tsc --build tsconfig.json",
"doc": "docker-compose -f doc/docker-compose.yml up",
diff --git a/src/Kuzzle.ts b/src/Kuzzle.ts
index 98a27138e..b19d4ed90 100644
--- a/src/Kuzzle.ts
+++ b/src/Kuzzle.ts
@@ -1,4 +1,5 @@
import { KuzzleEventEmitter } from './core/KuzzleEventEmitter';
+import { KuzzleAbstractProtocol } from './protocols/abstract/Base';
import { AuthController } from './controllers/Auth';
import { BulkController } from './controllers/Bulk';
@@ -12,7 +13,7 @@ import { MemoryStorageController } from './controllers/MemoryStorage';
import { uuidv4 } from './utils/uuidv4';
import { proxify } from './utils/proxify';
-import { JSONObject, KuzzleRequest } from './utils/interfaces';
+import { JSONObject, KuzzleRequest, KuzzleResponse } from './utils/interfaces';
// Defined by webpack plugin
declare const SDKVERSION: any;
@@ -31,6 +32,9 @@ const events = [
];
export class Kuzzle extends KuzzleEventEmitter {
+ // We need to define any string key because users can register new controllers
+ [key: string]: any;
+
/**
* Protocol used by the SDK to communicate with Kuzzle.
*/
@@ -48,7 +52,7 @@ export class Kuzzle extends KuzzleEventEmitter {
*/
public sdkVersion: string;
/**
- * SDK name (e.g: js@7.4.2).
+ * SDK name (e.g: `js@7.4.2`).
*/
public sdkName: string;
/**
@@ -58,11 +62,11 @@ export class Kuzzle extends KuzzleEventEmitter {
public auth: AuthController;
public bulk: any;
- public collection: any;
+ public collection: CollectionController;
public document: DocumentController;
- public index: any;
+ public index: IndexController;
public ms: any;
- public realtime: any;
+ public realtime: RealtimeController;
public security: any;
public server: any;
@@ -82,10 +86,84 @@ export class Kuzzle extends KuzzleEventEmitter {
private __proxy__: any;
/**
- * @param protocol - the protocol to use
- * @param [options] - Kuzzle options
+ * Instantiate a new SDK
+ *
+ * @example
+ *
+ * import { Kuzzle, WebSocket } from 'kuzzle-sdk';
+ *
+ * const kuzzle = new Kuzzle(
+ * new WebSocket('localhost')
+ * );
*/
- constructor(protocol: any, options: any = {}) {
+ constructor(
+ /**
+ * Network protocol to connect to Kuzzle. (e.g. `Http` or `WebSocket`)
+ */
+ protocol: KuzzleAbstractProtocol,
+ options: {
+ /**
+ * Automatically renew all subscriptions on a `reconnected` event
+ * Default: `true`
+ */
+ autoResubscribe?: boolean;
+ /**
+ * Time (in ms) during which a similar event is ignored
+ * Default: `200`
+ */
+ eventTimeout?: number;
+ /**
+ * Common volatile data, will be sent to all future requests
+ * Default: `{}`
+ */
+ volatile?: JSONObject;
+ /**
+ * If `true`, automatically queues all requests during offline mode
+ * Default: `false`
+ */
+ autoQueue?: boolean;
+ /**
+ * If `true`, automatically replays queued requests
+ * on a `reconnected` event
+ * Default: `false`
+ */
+ autoReplay?: boolean;
+ /**
+ * Custom function called during offline mode to filter
+ * queued requests on-the-fly
+ */
+ queueFilter?: (request: KuzzleRequest) => boolean;
+ /**
+ * Called before dequeuing requests after exiting offline mode,
+ * to add items at the beginning of the offline queue
+ */
+ offlineQueueLoader?: (...any) => any;
+ /**
+ * Number of maximum requests kept during offline mode
+ * Default: `500`
+ */
+ queueMaxSize?: number;
+ /**
+ * Time a queued request is kept during offline mode, in milliseconds
+ * Default: `120000`
+ */
+ queueTTL?: number;
+ /**
+ * Delay between each replayed requests, in milliseconds
+ * Default: `10`
+ */
+ replayInterval?: number;
+ /**
+ * Time (in ms) during which a TokenExpired event is ignored
+ * Default: `1000`
+ */
+ tokenExpiredInterval?: number;
+ /**
+ * If set to `auto`, the `autoQueue` and `autoReplay` are also set to `true`
+ */
+ offlineMode?: 'auto';
+ } = {}
+ ) {
super();
if (protocol === undefined || protocol === null) {
@@ -324,13 +402,12 @@ export class Kuzzle extends KuzzleEventEmitter {
return this._superEmit(eventName, ...payload);
}
- _superEmit (eventName, ...payload) {
+ private _superEmit (eventName, ...payload) {
return super.emit(eventName, ...payload);
}
/**
- * Connects to a Kuzzle instance using the provided host name
- * @returns {Promise}
+ * Connects to a Kuzzle instance
*/
connect (): Promise {
if (this.protocol.isReady()) {
@@ -361,15 +438,10 @@ export class Kuzzle extends KuzzleEventEmitter {
if (this.autoQueue) {
this.startQueuing();
}
-
- this.realtime.disconnected();
-
this.emit('networkError', error);
});
this.protocol.addListener('disconnect', () => {
- this.realtime.disconnected();
-
this.emit('disconnected');
});
@@ -382,8 +454,6 @@ export class Kuzzle extends KuzzleEventEmitter {
this.playQueue();
}
- this.realtime.reconnected();
-
if (this.auth.authenticationToken) {
return this.auth.checkToken()
.then(res => {
@@ -421,7 +491,7 @@ export class Kuzzle extends KuzzleEventEmitter {
return this._superAddListener(event, listener);
}
- _superAddListener (event, listener) {
+ private _superAddListener (event, listener) {
return super.addListener(event, listener);
}
@@ -451,11 +521,10 @@ export class Kuzzle extends KuzzleEventEmitter {
* - volatile (object, default: null):
* Additional information passed to notifications to other users
*
- * @param {object} request
- * @param {object} [options] - Optional arguments
- * @returns {Promise}
+ * @param request
+ * @param options - Optional arguments
*/
- query (request: KuzzleRequest = {}, options: JSONObject = {}): Promise {
+ query (request: KuzzleRequest = {}, options: JSONObject = {}): Promise {
if (typeof request !== 'object' || Array.isArray(request)) {
throw new Error(`Kuzzle.query: Invalid request: ${JSON.stringify(request)}`);
}
@@ -570,11 +639,10 @@ Discarded request: ${JSON.stringify(request)}`));
/**
* Adds a new controller and make it available in the SDK.
*
- * @param {BaseController} ControllerClass
- * @param {string} accessor
- * @returns {Kuzzle}
+ * @param ControllerClass
+ * @param accessor
*/
- useController (ControllerClass, accessor) {
+ useController (ControllerClass: any, accessor: string) {
if (!(accessor && accessor.length > 0)) {
throw new Error('You must provide a valid accessor.');
}
@@ -601,7 +669,7 @@ Discarded request: ${JSON.stringify(request)}`));
return this;
}
- _checkPropertyType (prop, typestr, value) {
+ private _checkPropertyType (prop, typestr, value) {
const wrongType = typestr === 'array' ? !Array.isArray(value) : typeof value !== typestr;
if (wrongType) {
@@ -612,7 +680,7 @@ Discarded request: ${JSON.stringify(request)}`));
/**
* Clean up the queue, ensuring the queryTTL and queryMaxSize properties are respected
*/
- _cleanQueue () {
+ private _cleanQueue () {
const now = Date.now();
let lastDocumentIndex = -1;
@@ -644,7 +712,7 @@ Discarded request: ${JSON.stringify(request)}`));
/**
* Play all queued requests, in order.
*/
- _dequeue() {
+ private _dequeue() {
const
uniqueQueue = {},
dequeuingProcess = () => {
@@ -693,7 +761,4 @@ Discarded request: ${JSON.stringify(request)}`));
dequeuingProcess();
}
-
}
-
-module.exports = { Kuzzle };
diff --git a/src/KuzzleError.js b/src/KuzzleError.js
deleted file mode 100644
index fd9ee4ce3..000000000
--- a/src/KuzzleError.js
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict';
-
-class KuzzleError extends Error {
- constructor (apiError) {
- super(apiError.message);
-
- this.status = apiError.status;
- this.stack = apiError.stack;
- this.id = apiError.id;
- this.code = apiError.code;
-
- // PartialError
- if (this.status === 206) {
- this.errors = apiError.errors;
- this.count = apiError.count;
- }
- }
-}
-
-module.exports = KuzzleError;
diff --git a/src/KuzzleError.ts b/src/KuzzleError.ts
new file mode 100644
index 000000000..505227ac4
--- /dev/null
+++ b/src/KuzzleError.ts
@@ -0,0 +1,67 @@
+'use strict';
+
+/**
+ * Standard Kuzzle error.
+ *
+ * @see https://docs.kuzzle.io/core/2/api/essentials/error-handling/
+ */
+export class KuzzleError extends Error {
+ /**
+ * Http status code
+ */
+ public status: number;
+ /**
+ * Stacktrace
+ */
+ public stack: string;
+ /**
+ * Kuzzle stacktrace (development mode only)
+ */
+ public kuzzleStack?: string;
+ /**
+ * Unique ID
+ */
+ public id: string;
+ /**
+ * Code
+ */
+ public code: number;
+
+ /**
+ * Associated errors
+ * (PartialError only)
+ */
+ public errors?: Array;
+ /**
+ * Number of associated errors
+ * (PartialError only)
+ */
+ public count?: number;
+
+ constructor (apiError, stack = null) {
+ super(apiError.message);
+
+ this.status = apiError.status;
+ if (apiError.stack) {
+ Reflect.defineProperty(this, 'kuzzleStack', {
+ value: apiError.stack
+ });
+ }
+
+ if (stack) {
+ const lines = stack.split('\n');
+ lines[0] += apiError.message;
+ lines[3] = ' 🡆 ' + lines[3].trimStart();
+ this.stack = lines.join('\n');
+ }
+
+ this.id = apiError.id;
+ this.code = apiError.code;
+
+ // PartialError
+ if (this.status === 206) {
+ this.errors = apiError.errors;
+ this.count = apiError.count;
+ }
+ }
+}
diff --git a/src/controllers/Auth.ts b/src/controllers/Auth.ts
index 2d8ef3ce6..9ed867c18 100644
--- a/src/controllers/Auth.ts
+++ b/src/controllers/Auth.ts
@@ -495,7 +495,7 @@ export class AuthController extends BaseController {
*/
_id: string;
/**
- * Expiration date in UNIX micro-timestamp format (-1 if the token never expires)
+ * Expiration date in Epoch-millis format (-1 if the token never expires)
*/
expiresAt: number;
/**
@@ -520,5 +520,3 @@ export class AuthController extends BaseController {
});
}
}
-
-module.exports = { AuthController };
diff --git a/src/controllers/Base.ts b/src/controllers/Base.ts
index b67d63f58..8115fc82a 100644
--- a/src/controllers/Base.ts
+++ b/src/controllers/Base.ts
@@ -40,5 +40,3 @@ export class BaseController {
return this._kuzzle.query(request, options);
}
}
-
-module.exports = { BaseController };
diff --git a/src/controllers/Collection.js b/src/controllers/Collection.js
deleted file mode 100644
index 97727ab6b..000000000
--- a/src/controllers/Collection.js
+++ /dev/null
@@ -1,151 +0,0 @@
-const { BaseController } = require('./Base');
-const { SpecificationsSearchResult } = require('../core/searchResult/Specifications');
-
-class CollectionController extends BaseController {
-
- /**
- * @param {Kuzzle} kuzzle
- */
- constructor (kuzzle) {
- super(kuzzle, 'collection');
- }
-
- create (index, collection, mappings = {}, options = {}) {
- const request = {
- index,
- collection,
- body: mappings,
- action: 'create'
- };
- return this.query(request, options)
- .then(response => response.result);
- }
-
- deleteSpecifications (index, collection, options = {}) {
- const request = {
- index,
- collection,
- action: 'deleteSpecifications'
- };
- return this.query(request, options)
- .then(response => response.result);
- }
-
- exists (index, collection, options = {}) {
- return this.query({
- index,
- collection,
- action: 'exists'
- }, options)
- .then(response => response.result);
- }
-
- refresh (index, collection, options = {}) {
- return this.query({
- index,
- collection,
- action: 'refresh'
- }, options)
- .then(response => response.result);
- }
-
- getMapping (index, collection, options = {}) {
- const request = {
- index,
- collection,
- action: 'getMapping',
- includeKuzzleMeta: options.includeKuzzleMeta || false
- };
-
- return this.query(request, options)
- .then(response => response.result);
- }
-
- getSpecifications (index, collection, options = {}) {
- return this.query({
- index,
- collection,
- action: 'getSpecifications'
- }, options)
- .then(response => response.result);
- }
-
- list (index, options = {}) {
- const request = {
- index,
- action: 'list',
- size: options.size || 0,
- from: options.from
- };
-
- return this.query(request, options)
- .then(response => response.result);
- }
-
- searchSpecifications (body = {}, options = {}) {
- const request = {
- body,
- action: 'searchSpecifications'
- };
-
- for (const opt of ['from', 'size', 'scroll']) {
- request[opt] = options[opt];
- }
-
- return this.query(request, options)
- .then(response => new SpecificationsSearchResult(this.kuzzle, request, options, response.result));
- }
-
- truncate (index, collection, options = {}) {
- const request = {
- index,
- collection,
- action: 'truncate'
- };
- return this.query(request, options)
- .then(response => response.result);
- }
-
- update(index, collection, body) {
- return this.query({
- index,
- collection,
- body,
- action: 'update'
- })
- .then(response => response.result);
- }
-
- // @deprecated
- updateMapping (index, collection, body, options = {}) {
- return this.query({
- index,
- collection,
- body,
- action: 'updateMapping'
- }, options)
- .then(response => response.result);
- }
-
- updateSpecifications (index, collection, specifications, options = {}) {
- return this.query({
- index,
- collection,
- body: specifications,
- action: 'updateSpecifications'
- }, options)
- .then(response => response.result);
- }
-
- validateSpecifications (index, collection, specifications, options = {}) {
- return this.query({
- index,
- collection,
- body: specifications,
- action: 'validateSpecifications'
- }, options)
- .then(response => response.result);
- }
-}
-
-module.exports = { CollectionController };
diff --git a/src/controllers/Collection.ts b/src/controllers/Collection.ts
new file mode 100644
index 000000000..6f1374b22
--- /dev/null
+++ b/src/controllers/Collection.ts
@@ -0,0 +1,428 @@
+import { BaseController } from './Base';
+import { SpecificationsSearchResult } from '../core/searchResult/Specifications';
+import { CollectionMappings, JSONObject } from '../utils/interfaces';
+
+export class CollectionController extends BaseController {
+ constructor (kuzzle) {
+ super(kuzzle, 'collection');
+ }
+
+ /**
+ * Creates a new collection in the provided index.
+ * You can also provide optional mappings and settings that allow you to exploit
+ * the full capabilities of our persistent data storage layer.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/create/
+ * @see https://docs.kuzzle.io/core/2/guides/essentials/database-mappings/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param definition Collection mappings and settings
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ create (
+ index: string,
+ collection: string,
+ definition:
+ {
+ /**
+ * Mappings definition
+ */
+ mappings?: CollectionMappings;
+ /**
+ * Elasticsearch index settings
+ */
+ settings?: JSONObject
+ } | CollectionMappings,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ const request = {
+ index,
+ collection,
+ body: definition,
+ action: 'create'
+ };
+
+ return this.query(request, options)
+ .then(() => undefined);
+ }
+
+ /**
+ * Deletes validation specifications for a collection.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/delete-specifications/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ deleteSpecifications (
+ index: string,
+ collection: string,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ const request = {
+ index,
+ collection,
+ action: 'deleteSpecifications'
+ };
+ return this.query(request, options)
+ .then(() => undefined);
+ }
+
+ /**
+ * Checks if a collection exists in Kuzzle.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/exists/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ exists (
+ index: string,
+ collection: string,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ return this.query({
+ index,
+ collection,
+ action: 'exists'
+ }, options)
+ .then(response => response.result);
+ }
+
+ /**
+ * Refreshes a collection to reindex the writed and deleted documents
+ * so they are available in search results.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/refresh/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ refresh (
+ index: string,
+ collection: string,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ return this.query({
+ index,
+ collection,
+ action: 'refresh'
+ }, options)
+ .then(() => undefined);
+ }
+
+ /**
+ * Returns the collection mapping.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/get-mapping/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param options Additional options
+ * - `includeKuzzleMeta` If true, the returned mappings will contain Kuzzle metadata
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ getMapping (
+ index: string,
+ collection: string,
+ options: { includeKuzzleMeta?: boolean, queuable?: boolean } = {}
+ ): Promise {
+ const request = {
+ index,
+ collection,
+ action: 'getMapping',
+ includeKuzzleMeta: options.includeKuzzleMeta || false
+ };
+
+ return this.query(request, options)
+ .then(response => response.result);
+ }
+
+ /**
+ * Returns the validation specifications associated to the given index and collection.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/get-specifications/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ *
+ * @returns The specifications
+ */
+ getSpecifications (
+ index: string,
+ collection: string,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ return this.query({
+ index,
+ collection,
+ action: 'getSpecifications'
+ }, options)
+ .then(response => response.result);
+ }
+
+ /**
+ * Returns the list of collections associated to a provided index.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/list/
+ *
+ * @param index Index name
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ *
+ * @returns An object containing the collection list
+ */
+ list (
+ index: string,
+ options: {
+ queuable?: boolean;
+ /**
+ * @deprecated
+ */
+ from?: number;
+ /**
+ * @deprecated
+ */
+ size?: number;
+ } = {}
+ ): Promise<{
+ /**
+ * Types of returned collections.
+ */
+ type: string;
+ /**
+ * List of collections
+ */
+ collections: Array<{
+ /**
+ * Collection name
+ */
+ name: string;
+ /**
+ * Collection type
+ */
+ type: 'realtime' | 'stored'
+ }>;
+ }> {
+ const request = {
+ index,
+ action: 'list',
+ size: options.size || 0,
+ from: options.from
+ };
+
+ return this.query(request, options)
+ .then(response => response.result);
+ }
+
+ /**
+ * Searches collection specifications.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/search-specifications/
+ *
+ * @param query Search query
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ * - `from` Offset of the first document to fetch
+ * - `size` Maximum number of documents to retrieve per page
+ * - `scroll` When set, gets a forward-only cursor having its ttl set to the given value (e.g. `30s`)
+ */
+ searchSpecifications (
+ query: JSONObject = {},
+ options: {
+ queuable?: boolean;
+ from?: number;
+ size?: number;
+ scroll?: string;
+ } = {}
+ ): Promise {
+ const request = {
+ body: query,
+ action: 'searchSpecifications'
+ };
+
+ for (const opt of ['from', 'size', 'scroll']) {
+ request[opt] = options[opt];
+ }
+
+ return this.query(request, options)
+ .then(response => (
+ new SpecificationsSearchResult(this.kuzzle, request, options, response.result)
+ ));
+ }
+
+
+ /**
+ * Removes all documents from a collection, while keeping the associated mappings.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/truncate/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ truncate (
+ index: string,
+ collection: string,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ const request = {
+ index,
+ collection,
+ action: 'truncate'
+ };
+ return this.query(request, options)
+ .then(() => undefined);
+ }
+
+ /**
+ * Updates a collection informations
+ * You can also provide optional mappings and settings that allow you to exploit
+ * the full capabilities of our persistent data storage layer.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/update/
+ * @see https://docs.kuzzle.io/core/2/guides/essentials/database-mappings/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param definition Collection mappings and settings
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ update (
+ index: string,
+ collection: string,
+ definition:
+ {
+ /**
+ * Mappings definition
+ */
+ mappings?: CollectionMappings;
+ /**
+ * Elasticsearch index settings
+ */
+ settings?: JSONObject
+ } | CollectionMappings,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ return this.query({
+ index,
+ collection,
+ body: definition,
+ action: 'update'
+ }, options)
+ .then(() => undefined);
+ }
+
+ /**
+ * @deprecated Use collection.update instead
+ */
+ updateMapping (
+ index: string,
+ collection: string,
+ mappings: CollectionMappings,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ return this.query({
+ index,
+ collection,
+ body: mappings,
+ action: 'updateMapping'
+ }, options)
+ .then(response => response.result);
+ }
+
+ /**
+ * Create or updates the validation specifications for a collection.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/update-specifications/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param specifications Specifications to update
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ *
+ * @returns The updated specifications
+ */
+ updateSpecifications (
+ index: string,
+ collection: string,
+ specifications: JSONObject,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ return this.query({
+ index,
+ collection,
+ body: specifications,
+ action: 'updateSpecifications'
+ }, options)
+ .then(response => response.result);
+ }
+
+ /**
+ * Checks if a validation specification is well formatted.
+ * It does not store or modify the existing specification.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/validate-specifications/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param specifications Specifications to validate
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ *
+ * @returns An object which contain information about the specifications validity.
+ */
+ validateSpecifications (
+ index: string,
+ collection: string,
+ specifications: JSONObject,
+ options: { queuable?: boolean } = {}
+ ): Promise<{
+ valid: boolean;
+ details: Array;
+ description: string;
+ }> {
+ return this.query({
+ index,
+ collection,
+ body: specifications,
+ action: 'validateSpecifications'
+ }, options)
+ .then(response => response.result);
+ }
+
+ /**
+ * Deletes a collection.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/collection/delete/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ */
+ delete (
+ index: string,
+ collection: string
+ ): Promise {
+ const request = {
+ index,
+ collection,
+ action: 'delete'
+ };
+
+ return this.query(request)
+ .then(() => undefined);
+ }
+}
diff --git a/src/controllers/Document.ts b/src/controllers/Document.ts
index 34141a911..60a3c77fc 100644
--- a/src/controllers/Document.ts
+++ b/src/controllers/Document.ts
@@ -27,7 +27,7 @@ export class DocumentController extends BaseController {
count (
index: string,
collection: string,
- body: JSONObject = null,
+ body?: JSONObject,
options: { queuable?: boolean } = {}
): Promise {
const request = {
@@ -801,5 +801,3 @@ export class DocumentController extends BaseController {
.then(response => response.result);
}
}
-
-module.exports = { DocumentController };
diff --git a/src/controllers/Index.js b/src/controllers/Index.js
deleted file mode 100644
index 626d8c949..000000000
--- a/src/controllers/Index.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const { BaseController } = require('./Base');
-
-class IndexController extends BaseController {
-
- /**
- * @param {Kuzzle} kuzzle
- */
- constructor (kuzzle) {
- super(kuzzle, 'index');
- }
-
- create (index, options = {}) {
- const request = {
- index,
- action: 'create'
- };
- return this.query(request, options)
- .then(response => response.result);
- }
-
- delete (index, options = {}) {
- const request = {
- index,
- action: 'delete'
- };
- return this.query(request, options)
- .then(response => response.result.acknowledged);
- }
-
- exists (index, options = {}) {
- return this.query({
- index,
- action : 'exists'
- }, options)
- .then(response => response.result);
- }
-
- list (options) {
- return this.query({
- action: 'list'
- }, options)
- .then(response => response.result.indexes);
- }
-
- mDelete (indexes, options = {}) {
- const request = {
- action: 'mDelete',
- body: {
- indexes
- }
- };
-
- return this.query(request, options)
- .then(response => response.result.deleted);
- }
-}
-
-module.exports = { IndexController };
diff --git a/src/controllers/Index.ts b/src/controllers/Index.ts
new file mode 100644
index 000000000..61fc13c10
--- /dev/null
+++ b/src/controllers/Index.ts
@@ -0,0 +1,102 @@
+import { BaseController } from './Base';
+
+export class IndexController extends BaseController {
+
+ constructor (kuzzle) {
+ super(kuzzle, 'index');
+ }
+
+ /**
+ * Creates a new index
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/index/create/
+ *
+ * @param index Index name
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ create (index: string, options: { queuable?: boolean } = {}): Promise {
+ const request = {
+ index,
+ action: 'create'
+ };
+ return this.query(request, options)
+ .then(() => undefined);
+ }
+
+ /**
+ * Deletes an index
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/index/delete/
+ *
+ * @param index Index name
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ delete (index: string, options: { queuable?: boolean } = {}): Promise {
+ const request = {
+ index,
+ action: 'delete'
+ };
+ return this.query(request, options)
+ .then(() => undefined);
+ }
+
+ /**
+ * Checks if the given index exists.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/index/exists/
+ *
+ * @param index Index name
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ exists (index: string, options: { queuable?: boolean } = {}): Promise {
+ return this.query({
+ index,
+ action : 'exists'
+ }, options)
+ .then(response => response.result);
+ }
+
+ /**
+ * Returns the complete list of indexes.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/index/list/
+ *
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ list (options: { queuable?: boolean } = {}): Promise> {
+ return this.query({
+ action: 'list'
+ }, options)
+ .then(response => response.result.indexes);
+ }
+
+ /**
+ * Deletes multiple indexes
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/index/m-delete/
+ *
+ * @param indexes List of index names to delete
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ *
+ * @returns Names of successfully deleted indexes
+ */
+ mDelete (
+ indexes: Array,
+ options: { queuable?: boolean } = {}
+ ): Promise> {
+ const request = {
+ action: 'mDelete',
+ body: {
+ indexes
+ }
+ };
+
+ return this.query(request, options)
+ .then(response => response.result.deleted);
+ }
+}
diff --git a/src/controllers/Realtime.js b/src/controllers/Realtime.js
deleted file mode 100644
index e68478ba2..000000000
--- a/src/controllers/Realtime.js
+++ /dev/null
@@ -1,128 +0,0 @@
-const { BaseController } = require('./Base');
-const Room = require('../core/Room');
-
-
-class RealtimeController extends BaseController {
- /**
- * @param {Kuzzle} kuzzle
- */
- constructor (kuzzle) {
- super(kuzzle, 'realtime');
-
- this.subscriptions = new Map();
- this.subscriptionsOff = new Map();
-
- this.kuzzle.on('tokenExpired', () => this.tokenExpired());
- }
-
- count (roomId, options = {}) {
- return this.query({
- action: 'count',
- body: {roomId}
- }, options)
- .then(response => response.result.count);
- }
-
- publish (index, collection, message, options = {}) {
- const request = {
- index,
- collection,
- body: message,
- action: 'publish',
- _id: options._id
- };
-
- return this.query(request, options)
- .then(response => response.result.published);
- }
-
- subscribe (index, collection, filters, callback, options = {}) {
- const room = new Room(this, index, collection, filters, callback, options);
-
- return room.subscribe()
- .then(() => {
- if (!this.subscriptions.has(room.id)) {
- this.subscriptions.set(room.id, []);
- }
- this.subscriptions.get(room.id).push(room);
- return room.id;
- });
- }
-
- unsubscribe (roomId, options = {}) {
- const request = {
- action: 'unsubscribe',
- body: { roomId }
- };
-
- return this.query(request, options)
- .then(response => {
- const rooms = this.subscriptions.get(roomId);
-
- if (rooms) {
- for (const room of rooms) {
- room.removeListeners();
- }
-
- this.subscriptions.delete(roomId);
- }
-
- return response.result;
- });
- }
-
- // called on network error or disconnection
- disconnected () {
- for (const roomId of this.subscriptions.keys()) {
- for (const room of this.subscriptions.get(roomId)) {
- room.removeListeners();
-
- if (room.autoResubscribe) {
- if (!this.subscriptionsOff.has(roomId)) {
- this.subscriptionsOff.set(roomId, []);
- }
- this.subscriptionsOff.get(roomId).push(room);
- }
- }
-
- this.subscriptions.delete(roomId);
- }
- }
-
- /**
- * Called on kuzzle reconnection.
- * Resubscribe to eligible disabled rooms.
- */
- reconnected () {
- for (const roomId of this.subscriptionsOff.keys()) {
- for (const room of this.subscriptionsOff.get(roomId)) {
- if (!this.subscriptions.has(roomId)) {
- this.subscriptions.set(roomId, []);
- }
- this.subscriptions.get(roomId).push(room);
-
- room.subscribe()
- .catch(() => this.kuzzle.emit('discarded', {request: room.request}));
- }
-
- this.subscriptionsOff.delete(roomId);
- }
- }
-
- /**
- * Removes all subscriptions.
- */
- tokenExpired() {
- for (const roomId of this.subscriptions.keys()) {
- for (const room of this.subscriptions.get(roomId)) {
- room.removeListeners();
- }
- }
-
- this.subscriptions = new Map();
- this.subscriptionsOff = new Map();
- }
-
-}
-
-module.exports = { RealtimeController };
diff --git a/src/controllers/Realtime.ts b/src/controllers/Realtime.ts
new file mode 100644
index 000000000..1d1b391c2
--- /dev/null
+++ b/src/controllers/Realtime.ts
@@ -0,0 +1,259 @@
+import { BaseController } from './Base';
+import Room from '../core/Room';
+import { JSONObject } from '../utils/interfaces';
+
+/**
+ * Enum for `scope` option of realtime.subscribe method
+ */
+export enum ScopeOption {
+ /**
+ * Receive all document notifications
+ */
+ all = 'all',
+ /**
+ * Receive notifications when document enter or stay in the scope
+ */
+ in = 'in',
+ /**
+ * Receive notification when document exit the scope
+ */
+ out = 'out',
+ /**
+ * Do not receive document notifications
+ */
+ none = 'none'
+}
+
+/**
+ * Enum for `user` option of realtime.subscribe method
+ */
+export enum UserOption {
+ /**
+ * Receive all user notifications
+ */
+ all = 'all',
+ /**
+ * Receive notification when users join the room
+ */
+ in = 'in',
+ /**
+ * Receive notifications when users leave the room
+ */
+ out = 'out',
+ /**
+ * Do not receive user notifications
+ */
+ none = 'none'
+}
+
+export class RealtimeController extends BaseController {
+ private _subscriptions: Map>;
+ private _subscriptionsOff: Map>;
+
+ constructor (kuzzle) {
+ super(kuzzle, 'realtime');
+
+ this._subscriptions = new Map();
+ this._subscriptionsOff = new Map();
+
+ this.kuzzle.on('tokenExpired', () => this.removeSubscriptions());
+ this.kuzzle.on('disconnected', () => this.saveSubscriptions());
+ this.kuzzle.on('networkError', () => this.saveSubscriptions());
+ this.kuzzle.on('reconnected', () => this.resubscribe());
+ }
+
+ /**
+ * Returns the number of other connections sharing the same subscription.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/realtime/count/
+ *
+ * @param roomId Subscription room ID
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ *
+ * @returns A number represensting active connections using the same provided subscription room.
+ */
+ count (roomId: string, options: { queuable?: boolean } = {}): Promise {
+ return this.query({
+ action: 'count',
+ body: { roomId }
+ }, options)
+ .then(response => response.result.count);
+ }
+
+ /**
+ * Sends a real-time message to Kuzzle.
+ *
+ * The message will be dispatched to all clients with subscriptions
+ * matching the index, the collection and the message content.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/realtime/count/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param message Message to send (will be put in `_source` property of the notification)
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ * - `_id` Additional unique ID (will be put in the `_id` property of the notification)
+ */
+ publish (
+ index: string,
+ collection: string,
+ message: JSONObject,
+ options: { queuable?: boolean, _id?: string } = {}
+ ): Promise {
+ const request = {
+ index,
+ collection,
+ body: message,
+ action: 'publish',
+ _id: options._id
+ };
+
+ return this.query(request, options)
+ .then(response => response.result.published);
+ }
+
+ /**
+ * Subscribes by providing a set of filters: messages, document changes
+ * and, optionally, user events matching the provided filters will generate
+ * real-time notifications.
+ *
+ * @see https://docs.kuzzle.io/sdk/js/7/controllers/realtime/subscribe/
+ * @see https://docs.kuzzle.io/sdk/js/7/essentials/realtime-notifications/
+ *
+ * @param index Index name
+ * @param collection Collection name
+ * @param filters Optional subscription filters (@see https://docs.kuzzle.io/core/2/guides/cookbooks/realtime-api)
+ * @param callback Callback function to handle notifications
+ * @param options Additional options
+ * - `scope` Subscribe to document entering or leaving the scope. (default: 'all')
+ * - `users` Subscribe to users entering or leaving the room. (default: 'none')
+ * - `subscribeToSelf` Subscribe to notifications fired by our own queries. (default: true)
+ * - `volatile` Subscription information sent alongside notifications
+ *
+ * @returns A string containing the room ID
+ */
+ subscribe (
+ index: string,
+ collection: string,
+ filters: JSONObject,
+ callback: (notification: Notification) => void | Promise,
+ options: {
+ /**
+ * Subscribe to document entering or leaving the scope. (default: 'all')
+ */
+ scope?: ScopeOption;
+ /**
+ * Subscribe to users entering or leaving the room. (default: 'none')
+ */
+ users?: UserOption;
+ /**
+ * Subscribe to notifications fired by our own queries. (default: true)
+ */
+ subscribeToSelf?: boolean;
+ /**
+ * Subscription information sent alongside notifications
+ */
+ volatile?: JSONObject;
+ } = {}
+ ): Promise {
+ const room = new Room(this, index, collection, filters, callback, options);
+
+ return room.subscribe()
+ .then(() => {
+ if (!this._subscriptions.has(room.id)) {
+ this._subscriptions.set(room.id, []);
+ }
+ this._subscriptions.get(room.id).push(room);
+ return room.id;
+ });
+ }
+
+ /**
+ * Removes a subscription
+ *
+ * @param roomId Subscription room ID
+ * @param options Additional options
+ * - `queuable` If true, queues the request during downtime, until connected to Kuzzle again
+ */
+ unsubscribe (
+ roomId: string,
+ options: { queuable?: boolean } = {}
+ ): Promise {
+ const request = {
+ action: 'unsubscribe',
+ body: { roomId }
+ };
+
+ return this.query(request, options)
+ .then(response => {
+ const rooms = this._subscriptions.get(roomId);
+
+ if (rooms) {
+ for (const room of rooms) {
+ room.removeListeners();
+ }
+
+ this._subscriptions.delete(roomId);
+ }
+
+ return response.result;
+ });
+ }
+
+ /**
+ * Called when kuzzle is disconnected
+ */
+ private saveSubscriptions () {
+ for (const roomId of this._subscriptions.keys()) {
+ for (const room of this._subscriptions.get(roomId)) {
+ room.removeListeners();
+
+ if (room.autoResubscribe) {
+ if (!this._subscriptionsOff.has(roomId)) {
+ this._subscriptionsOff.set(roomId, []);
+ }
+ this._subscriptionsOff.get(roomId).push(room);
+ }
+ }
+
+ this._subscriptions.delete(roomId);
+ }
+ }
+
+ /**
+ * Called on kuzzle reconnection
+ */
+ private resubscribe () {
+ for (const roomId of this._subscriptionsOff.keys()) {
+ for (const room of this._subscriptionsOff.get(roomId)) {
+ if (!this._subscriptions.has(roomId)) {
+ this._subscriptions.set(roomId, []);
+ }
+ this._subscriptions.get(roomId).push(room);
+
+ room.subscribe()
+ .catch(() => this.kuzzle.emit('discarded', { request: room.request }));
+ }
+
+ this._subscriptionsOff.delete(roomId);
+ }
+ }
+
+ /**
+ * Called when a token expire
+ */
+ private removeSubscriptions() {
+ for (const roomId of this._subscriptions.keys()) {
+ for (const room of this._subscriptions.get(roomId)) {
+ room.removeListeners();
+ }
+ }
+
+ this._subscriptions = new Map();
+ this._subscriptionsOff = new Map();
+ }
+}
+
+module.exports = { RealtimeController };
diff --git a/src/core/KuzzleEventEmitter.js b/src/core/KuzzleEventEmitter.ts
similarity index 91%
rename from src/core/KuzzleEventEmitter.js
rename to src/core/KuzzleEventEmitter.ts
index e88ee825c..c10f03b23 100644
--- a/src/core/KuzzleEventEmitter.js
+++ b/src/core/KuzzleEventEmitter.ts
@@ -1,16 +1,24 @@
class Listener {
+ public fn: (...any) => any;
+ public once: boolean;
+
constructor(fn, once = false) {
this.fn = fn;
this.once = once;
}
}
-class KuzzleEventEmitter {
- constructor() {
+/**
+ * @todo proper TS conversion
+ */
+export class KuzzleEventEmitter {
+ private _events: Map>;
+
+ constructor () {
this._events = new Map();
}
- _exists (listeners, fn) {
+ private _exists (listeners, fn) {
return Boolean(listeners.find(listener => listener.fn === fn));
}
@@ -98,7 +106,7 @@ class KuzzleEventEmitter {
return this;
}
- removeAllListeners (eventName) {
+ removeAllListeners (eventName?: string) {
if (eventName) {
this._events.delete(eventName);
}
diff --git a/src/core/Room.js b/src/core/Room.js
index ddf0c4af4..25fd7a6ed 100644
--- a/src/core/Room.js
+++ b/src/core/Room.js
@@ -1,3 +1,5 @@
+'use strict';
+
class Room {
/**
diff --git a/src/core/searchResult/Profile.js b/src/core/searchResult/Profile.js
deleted file mode 100644
index ac7de860b..000000000
--- a/src/core/searchResult/Profile.js
+++ /dev/null
@@ -1,29 +0,0 @@
-const { Profile } = require('../security/Profile');
-const { SearchResultBase } = require('./SearchResultBase');
-
-class ProfileSearchResult extends SearchResultBase {
- constructor (kuzzle, request, options, response) {
- super(kuzzle, request, options, response);
-
- this._searchAction = 'searchProfiles';
- this._scrollAction = 'scrollProfiles';
- this.hits = response.hits.map(
- hit => new Profile(this._kuzzle, hit._id, hit._source));
- }
-
- next () {
- return super.next()
- .then(nextSearchResult => {
- if (! nextSearchResult) {
- return null;
- }
-
- nextSearchResult.hits = nextSearchResult._response.hits.map(
- hit => new Profile(nextSearchResult._kuzzle, hit._id, hit._source));
-
- return nextSearchResult;
- });
- }
-}
-
-module.exports = { ProfileSearchResult };
diff --git a/src/core/searchResult/Profile.ts b/src/core/searchResult/Profile.ts
new file mode 100644
index 000000000..08d9e131c
--- /dev/null
+++ b/src/core/searchResult/Profile.ts
@@ -0,0 +1,29 @@
+import { Profile } from '../security/Profile';
+import { SearchResultBase } from './SearchResultBase';
+
+export class ProfileSearchResult extends SearchResultBase {
+ constructor (kuzzle, request, options, response) {
+ super(kuzzle, request, options, response);
+
+ this._searchAction = 'searchProfiles';
+ this._scrollAction = 'scrollProfiles';
+ this.hits = response.hits.map(hit => (
+ new Profile(this._kuzzle, hit._id, hit._source)
+ ));
+ }
+
+ next () {
+ return super.next()
+ .then((nextSearchResult: ProfileSearchResult) => {
+ if (! nextSearchResult) {
+ return null;
+ }
+
+ nextSearchResult.hits = nextSearchResult._response.hits.map(hit => (
+ new Profile(nextSearchResult._kuzzle, hit._id, hit._source)
+ ));
+
+ return nextSearchResult;
+ });
+ }
+}
diff --git a/src/core/searchResult/Role.js b/src/core/searchResult/Role.ts
similarity index 63%
rename from src/core/searchResult/Role.js
rename to src/core/searchResult/Role.ts
index 241e310da..4cbbb48aa 100644
--- a/src/core/searchResult/Role.js
+++ b/src/core/searchResult/Role.ts
@@ -1,7 +1,7 @@
-const { Role } = require('../security/Role');
-const { SearchResultBase } = require('./SearchResultBase');
+import { Role } from '../security/Role';
+import { SearchResultBase } from './SearchResultBase';
-class RoleSearchResult extends SearchResultBase {
+export class RoleSearchResult extends SearchResultBase {
constructor (kuzzle, query, options, response) {
super(kuzzle, query, options, response);
@@ -9,7 +9,9 @@ class RoleSearchResult extends SearchResultBase {
this._searchAction = 'searchRoles';
this._scrollAction = null; // scrollRoles action does not exists in Kuzzle API.
- this.hits = this._response.hits.map(hit => new Role(this._kuzzle, hit._id, hit._source.controllers));
+ this.hits = this._response.hits.map(hit => (
+ new Role(this._kuzzle, hit._id, hit._source.controllers)
+ ));
}
next () {
@@ -20,16 +22,16 @@ class RoleSearchResult extends SearchResultBase {
}
return super.next()
- .then(nextSearchResult => {
+ .then((nextSearchResult: RoleSearchResult) => {
if (! nextSearchResult) {
return null;
}
- nextSearchResult.hits = nextSearchResult._response.hits.map(hit => new Role(nextSearchResult._kuzzle, hit._id, hit._source.controllers));
+ nextSearchResult.hits = nextSearchResult._response.hits.map(hit => (
+ new Role(nextSearchResult._kuzzle, hit._id, hit._source.controllers)
+ ));
return nextSearchResult;
});
}
}
-
-module.exports = { RoleSearchResult };
diff --git a/src/core/searchResult/SearchResultBase.ts b/src/core/searchResult/SearchResultBase.ts
index a6c2da445..c48ea9c71 100644
--- a/src/core/searchResult/SearchResultBase.ts
+++ b/src/core/searchResult/SearchResultBase.ts
@@ -55,17 +55,10 @@ export class SearchResultBase implements SearchResult {
public fetched: number;
- /**
- *
- * @param {Kuzzle} kuzzle
- * @param {object} request
- * @param {object} options
- * @param {object} response
- */
constructor (
kuzzle: Kuzzle,
request: KuzzleRequest = {},
- options: any = {},
+ options: JSONObject = {},
response: any = {}
) {
Reflect.defineProperty(this, '_kuzzle', {
@@ -80,10 +73,18 @@ export class SearchResultBase implements SearchResult {
Reflect.defineProperty(this, '_response', {
value: response
});
-
- this._controller = request.controller;
- this._searchAction = 'search';
- this._scrollAction = 'scroll';
+ Reflect.defineProperty(this, '_controller', {
+ value: request.controller,
+ writable: true
+ });
+ Reflect.defineProperty(this, '_searchAction', {
+ value: 'search',
+ writable: true
+ });
+ Reflect.defineProperty(this, '_scrollAction', {
+ value: 'scroll',
+ writable: true
+ });
this.aggregations = response.aggregations;
this.hits = response.hits || [];
@@ -166,7 +167,7 @@ export class SearchResultBase implements SearchResult {
return Promise.reject(new Error('Unable to retrieve next results from search: missing scrollId, from/sort, or from/size params'));
}
- _get (object, path) {
+ protected _get (object, path) {
if (!object) {
return object;
}
@@ -179,7 +180,7 @@ export class SearchResultBase implements SearchResult {
return this._get(object[key], path);
}
- _buildNextSearchResult (response) {
+ protected _buildNextSearchResult (response) {
const Constructor: any = this.constructor;
const nextSearchResult = new Constructor(this._kuzzle, this._request, this._options, response.result);
@@ -187,8 +188,4 @@ export class SearchResultBase implements SearchResult {
return nextSearchResult;
}
-
}
-
-
-module.exports = { SearchResultBase };
diff --git a/src/core/searchResult/Specifications.js b/src/core/searchResult/Specifications.ts
similarity index 56%
rename from src/core/searchResult/Specifications.js
rename to src/core/searchResult/Specifications.ts
index 15d2d2410..54b21df0f 100644
--- a/src/core/searchResult/Specifications.js
+++ b/src/core/searchResult/Specifications.ts
@@ -1,6 +1,7 @@
-const { SearchResultBase } = require('./SearchResultBase');
+import { SearchResultBase } from './SearchResultBase';
+import { JSONObject } from '../../utils/interfaces';
-class SpecificationsSearchResult extends SearchResultBase {
+export class SpecificationsSearchResult extends SearchResultBase {
constructor (kuzzle, query, options, response) {
super(kuzzle, query, options, response);
@@ -10,5 +11,3 @@ class SpecificationsSearchResult extends SearchResultBase {
this._scrollAction = 'scrollSpecifications';
}
}
-
-module.exports = { SpecificationsSearchResult };
diff --git a/src/core/searchResult/User.js b/src/core/searchResult/User.js
deleted file mode 100644
index 20ec93dcb..000000000
--- a/src/core/searchResult/User.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const { SearchResultBase } = require('./SearchResultBase');
-const { User } = require('../security/User');
-
-class UserSearchResult extends SearchResultBase {
-
- constructor (kuzzle, query, options, response) {
- super(kuzzle, query, options, response);
-
- this._searchAction = 'searchUsers';
- this._scrollAction = 'scrollUsers';
- this.hits = this._response.hits.map(hit => new User(this._kuzzle, hit._id, hit._source));
- }
-
- next () {
- return super.next()
- .then(nextSearchResult => {
- if (! nextSearchResult) {
- return null;
- }
-
- nextSearchResult.hits = nextSearchResult._response.hits.map(hit => new User(nextSearchResult._kuzzle, hit._id, hit._source));
- return nextSearchResult;
- });
- }
-}
-
-module.exports = { UserSearchResult };
diff --git a/src/core/searchResult/User.ts b/src/core/searchResult/User.ts
new file mode 100644
index 000000000..501b88b71
--- /dev/null
+++ b/src/core/searchResult/User.ts
@@ -0,0 +1,30 @@
+import { SearchResultBase } from './SearchResultBase';
+import { User } from '../security/User';
+
+export class UserSearchResult extends SearchResultBase {
+
+ constructor (kuzzle, query, options, response) {
+ super(kuzzle, query, options, response);
+
+ this._searchAction = 'searchUsers';
+ this._scrollAction = 'scrollUsers';
+ this.hits = this._response.hits.map(hit => (
+ new User(this._kuzzle, hit._id, hit._source)
+ ));
+ }
+
+ next () {
+ return super.next()
+ .then((nextSearchResult: UserSearchResult) => {
+ if (! nextSearchResult) {
+ return null;
+ }
+
+ nextSearchResult.hits = nextSearchResult._response.hits.map(hit => (
+ new User(nextSearchResult._kuzzle, hit._id, hit._source)
+ ));
+
+ return nextSearchResult;
+ });
+ }
+}
diff --git a/src/core/security/Profile.ts b/src/core/security/Profile.ts
index 12e18010a..044844635 100644
--- a/src/core/security/Profile.ts
+++ b/src/core/security/Profile.ts
@@ -52,6 +52,3 @@ export class Profile {
options);
}
}
-
-module.exports = { Profile };
-
diff --git a/src/protocols/Http.js b/src/protocols/Http.ts
similarity index 77%
rename from src/protocols/Http.js
rename to src/protocols/Http.ts
index e7f1d86fe..8525c9bfa 100644
--- a/src/protocols/Http.js
+++ b/src/protocols/Http.ts
@@ -1,10 +1,40 @@
'use strict';
-const staticHttpRoutes = require('./routes.json');
-const { KuzzleAbstractProtocol } = require('./abstract/Base');
+import staticHttpRoutes from './routes.json';
+import { KuzzleAbstractProtocol } from './abstract/Base';
+import { HttpRoutes, JSONObject, KuzzleRequest } from '../utils/interfaces';
+
+/**
+ * Http protocol used to connect to a Kuzzle server.
+ *
+ * The Http protocol cannot use the realtime capabilities of Kuzzle.
+ */
+export default class HttpProtocol extends KuzzleAbstractProtocol {
+ private _routes: HttpRoutes;
+ private _timeout: number;
+ private _customRoutes: HttpRoutes;
-class HttpProtocol extends KuzzleAbstractProtocol {
- constructor(host, options = {}) {
+ /**
+ * @param host Kuzzle server hostname or IP
+ * @param options Http connection options
+ * - `customRoutes` Add custom routes
+ * - `port` Kuzzle server port (default: `7512`)
+ * - `ssl` Use SSL to connect to Kuzzle server. Default `false` unless port is 443 or 7443.
+ * - `timeout` Connection timeout in milliseconds (default: `0`)
+ */
+ constructor(
+ host: string,
+ options: {
+ port?: number;
+ /**
+ * @deprecated Use `ssl` instead
+ */
+ sslConnection?: boolean;
+ ssl?: boolean;
+ customRoutes?: HttpRoutes;
+ timeout?: number
+ } = {}
+ ) {
super(host, options, 'http');
if (typeof host !== 'string' || host === '') {
@@ -15,10 +45,10 @@ class HttpProtocol extends KuzzleAbstractProtocol {
this._timeout = options.timeout || 0;
- this.customRoutes = options.customRoutes || {};
+ this._customRoutes = options.customRoutes || {};
- for (const controller of Object.keys(this.customRoutes)) {
- const definition = this.customRoutes[controller];
+ for (const controller of Object.keys(this._customRoutes)) {
+ const definition = this._customRoutes[controller];
for (const action of Object.keys(definition)) {
const route = definition[action];
@@ -35,35 +65,49 @@ class HttpProtocol extends KuzzleAbstractProtocol {
}
}
- // @deprecated
+ /**
+ * @deprecated Use `routes` instead
+ */
get http () {
return this.routes;
}
- get routes () {
+ /**
+ * Returns a list of available routes
+ */
+ get routes (): HttpRoutes {
return this._routes;
}
- get protocol () {
+ /**
+ * `http` or `https`
+ */
+ get protocol (): string {
return this.ssl ? 'https' : 'http';
}
- get connected () {
+ /**
+ * Always returns `true`
+ */
+ get connected (): true {
return true;
}
- get timeout () {
+ /**
+ * Connection timeout in milliseconds
+ */
+ get timeout (): number {
return this._timeout;
}
- set timeout (timeout) {
+ set timeout (timeout: number) {
this._timeout = timeout;
}
/**
* Connect to the server
*/
- connect () {
+ connect (): Promise {
if (this.state === 'ready') {
return Promise.resolve();
}
@@ -92,7 +136,6 @@ class HttpProtocol extends KuzzleAbstractProtocol {
.then(({ result: res, error: err }) => {
if (! err) {
this._routes = this._constructRoutes(res.serverInfo.kuzzle.api.routes);
- this._staticRoutes = false;
return;
}
@@ -114,13 +157,13 @@ class HttpProtocol extends KuzzleAbstractProtocol {
throw error;
})
.then(() => {
- this._routes = Object.assign(this._routes, this.customRoutes);
+ this._routes = Object.assign(this._routes, this._customRoutes);
// Client is ready
this.clientConnected();
})
.catch(err => {
- const connectionError = new Error(`Unable to connect to kuzzle server at ${this.host}:${this.port}`);
+ const connectionError: any = new Error(`Unable to connect to kuzzle server at ${this.host}:${this.port}`);
connectionError.internal = err;
this.emit('networkError', connectionError);
@@ -134,19 +177,19 @@ class HttpProtocol extends KuzzleAbstractProtocol {
* @param {Object} data
* @returns {Promise}
*/
- send (data, options = {}) {
- const route = this.routes[data.controller]
- && this.routes[data.controller][data.action];
+ send (request: KuzzleRequest, options: JSONObject = {}) {
+ const route = this.routes[request.controller]
+ && this.routes[request.controller][request.action];
if (! route) {
- const error = new Error(`No URL found for "${data.controller}:${data.action}".`);
- this.emit(data.requestId, { status: 400, error });
+ const error = new Error(`No URL found for "${request.controller}:${request.action}".`);
+ this.emit(request.requestId, { status: 400, error });
return;
}
const method = options.verb || route.verb;
- const payload = {
+ const payload: any = {
action: undefined,
body: undefined,
collection: undefined,
@@ -160,8 +203,8 @@ class HttpProtocol extends KuzzleAbstractProtocol {
};
const queryArgs = {};
- for (const key of Object.keys(data)) {
- const value = data[key];
+ for (const key of Object.keys(request)) {
+ const value = request[key];
if (key === 'body') {
if (method === 'GET') {
@@ -191,7 +234,7 @@ class HttpProtocol extends KuzzleAbstractProtocol {
let matches = regex.exec(url);
while (matches) {
- const urlParam = data[ matches[1] ];
+ const urlParam = request[ matches[1] ];
// check if an url param is missing (eg: "/:index/_create)
if (!urlParam) {
@@ -201,9 +244,9 @@ class HttpProtocol extends KuzzleAbstractProtocol {
return;
}
- url = url.replace(regex, `/${encodeURIComponent(data[matches[1]])}`);
+ url = url.replace(regex, `/${encodeURIComponent(request[matches[1]])}`);
- delete(queryArgs[ matches[1] ]);
+ delete queryArgs[matches[1]];
matches = regex.exec(url);
}
@@ -242,10 +285,11 @@ class HttpProtocol extends KuzzleAbstractProtocol {
.catch(error => this.emit(payload.requestId, {error}));
}
- _sendHttpRequest (method, path, payload = {}) {
+ _sendHttpRequest (method, path, payload: any = {}) {
if (typeof XMLHttpRequest === 'undefined') {
// NodeJS implementation, using http.request:
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
const httpClient = require('min-req-promise');
if (path[0] !== '/') {
@@ -328,8 +372,8 @@ class HttpProtocol extends KuzzleAbstractProtocol {
return routes;
}, {});
- for (const controller of Object.keys(this.customRoutes)) {
- apiRoutes[controller] = this.customRoutes[controller];
+ for (const controller of Object.keys(this._customRoutes)) {
+ apiRoutes[controller] = this._customRoutes[controller];
}
return apiRoutes;
@@ -371,5 +415,3 @@ function getCorrectRoute (routes) {
// will be in the query string
return sameLength ? getRoute : shortestRoute;
}
-
-module.exports = HttpProtocol;
diff --git a/src/protocols/WebSocket.js b/src/protocols/WebSocket.ts
similarity index 66%
rename from src/protocols/WebSocket.js
rename to src/protocols/WebSocket.ts
index f2d05e1fb..d1438cda3 100644
--- a/src/protocols/WebSocket.js
+++ b/src/protocols/WebSocket.ts
@@ -1,11 +1,62 @@
'use strict';
-const KuzzleError = require('../KuzzleError');
-const BaseProtocolRealtime = require('./abstract/Realtime');
+import { KuzzleError } from '../KuzzleError';
+import { BaseProtocolRealtime } from './abstract/Realtime';
+import { JSONObject, KuzzleRequest } from '../utils/interfaces';
+
+/**
+ * WebSocket protocol used to connect to a Kuzzle server.
+ */
+export default class WebSocketProtocol extends BaseProtocolRealtime {
+ private WebSocketClient: any;
+ private options: any;
+ private client: any;
+ private lasturl: any;
-class WebSocketProtocol extends BaseProtocolRealtime {
+ /**
+ * Automatically reconnect after a connection loss
+ */
+ public autoReconnect: boolean;
+ /**
+ * `true` if the socket is open
+ */
+ public connected: boolean;
+ /**
+ * Kuzzle server host or IP
+ */
+ public host: string;
+ /**
+ * Kuzzle server port
+ */
+ public port: number;
+ /**
+ * `true` if ssl is active
+ */
+ public ssl: boolean;
- constructor(host, options = {}) {
+ /**
+ * @param host Kuzzle server hostname or IP
+ * @param options WebSocket connection options
+ * - `autoReconnect` Automatically reconnect to kuzzle after a `disconnected` event. (default: `true`)
+ * - `port` Kuzzle server port (default: `7512`)
+ * - `headers` Connection custom HTTP headers (Not supported by browsers)
+ * - `reconnectionDelay` Number of milliseconds between reconnection attempts (default: `1000`)
+ * - `ssl` Use SSL to connect to Kuzzle server. Default `false` unless port is 443 or 7443.
+ */
+ constructor(
+ host: string,
+ options: {
+ autoReconnect?: boolean;
+ port?: number;
+ headers?: JSONObject;
+ reconnectionDelay?: number;
+ /**
+ * @deprecated Use `ssl` instead
+ */
+ sslConnection?: boolean;
+ ssl?: boolean;
+ } = {}
+ ) {
super(host, options, 'ws');
if (typeof host !== 'string' || host === '') {
@@ -39,7 +90,7 @@ class WebSocketProtocol extends BaseProtocolRealtime {
/**
* Connect to the websocket server
*/
- connect () {
+ connect (): Promise {
return new Promise((resolve, reject) => {
const url = `${this.ssl ? 'wss' : 'ws'}://${this.host}:${this.port}`;
@@ -79,7 +130,7 @@ class WebSocketProtocol extends BaseProtocolRealtime {
// do not forward a connection close error if no
// connection has been previously established
else if (this.wasConnected) {
- const error = new Error(reason);
+ const error: any = new Error(reason);
error.status = status;
this.clientNetworkError(error);
@@ -127,9 +178,9 @@ class WebSocketProtocol extends BaseProtocolRealtime {
*
* @param {Object} payload
*/
- send (payload) {
+ send (request: KuzzleRequest) {
if (this.client && this.client.readyState === this.client.OPEN) {
- this.client.send(JSON.stringify(payload));
+ this.client.send(JSON.stringify(request));
}
}
@@ -148,5 +199,3 @@ class WebSocketProtocol extends BaseProtocolRealtime {
super.close();
}
}
-
-module.exports = WebSocketProtocol;
diff --git a/src/protocols/abstract/Base.js b/src/protocols/abstract/Base.ts
similarity index 63%
rename from src/protocols/abstract/Base.js
rename to src/protocols/abstract/Base.ts
index 258c6082e..ec60e6cc1 100644
--- a/src/protocols/abstract/Base.js
+++ b/src/protocols/abstract/Base.ts
@@ -1,12 +1,26 @@
'use strict';
-const KuzzleError = require('../../KuzzleError');
-const { uuidv4 } = require('../../utils/uuidv4');
-const { KuzzleEventEmitter } = require('../../core/KuzzleEventEmitter');
-const PendingRequest = require('./PendingRequest');
-
-class KuzzleAbstractProtocol extends KuzzleEventEmitter {
- constructor (host, options = {}, name = undefined) {
+import { KuzzleError } from '../../KuzzleError';
+import { uuidv4 } from '../../utils/uuidv4';
+import { KuzzleEventEmitter } from '../../core/KuzzleEventEmitter';
+import { PendingRequest } from './PendingRequest';
+import { KuzzleRequest, JSONObject } from '../../utils/interfaces';
+
+/**
+ * @todo proper TS conversion
+ */
+export abstract class KuzzleAbstractProtocol extends KuzzleEventEmitter {
+ private _pendingRequests: Map;
+ private _host: string;
+ private _name: string;
+ private _port: number;
+ private _ssl: boolean;
+
+ public id: string;
+
+ public state: string;
+
+ constructor (host: string, options: JSONObject = {}, name: string = undefined) {
super();
this._pendingRequests = new Map();
@@ -14,7 +28,23 @@ class KuzzleAbstractProtocol extends KuzzleEventEmitter {
this._name = name;
const port = parseInt(options.port, 10);
this._port = isNaN(port) ? 7512 : port;
- this._ssl = typeof options.sslConnection === 'boolean' ? options.sslConnection : false;
+
+ if (options.ssl !== undefined && options.sslConnection !== undefined) {
+ throw new Error('Both "ssl" and "sslConnection" options are set. Use only "ssl".');
+ }
+
+ if (typeof options.ssl === 'boolean') {
+ this._ssl = options.ssl;
+ }
+ else if (typeof options.sslConnection === 'boolean') {
+ this._ssl = options.sslConnection;
+ }
+ else if (port === 443 || port === 7443) {
+ this._ssl = true;
+ }
+ else {
+ this._ssl = false;
+ }
this.id = uuidv4();
this.state = 'offline';
@@ -52,27 +82,14 @@ class KuzzleAbstractProtocol extends KuzzleEventEmitter {
return this._pendingRequests;
}
- /**
- * @abstract
- * @returns {Promise}
- */
- connect () {
- throw new Error('Method "connect" is not implemented');
- }
+ abstract connect (): Promise
- /**
- * @abstract
- * @param request
- * @returns {Promise}
- */
- send () {
- throw new Error('Method "send" is not implemented');
- }
+ abstract send (request: KuzzleRequest, options: JSONObject): void
/**
* Called when the client's connection is established
*/
- clientConnected (state, wasConnected) {
+ clientConnected (state?: string, wasConnected?: boolean) {
this.state = state || 'ready';
this.emit(wasConnected && 'reconnect' || 'connect');
}
@@ -92,6 +109,8 @@ class KuzzleAbstractProtocol extends KuzzleEventEmitter {
Discarded request: ${JSON.stringify(request)}`));
}
+ const stack = Error().stack;
+
const pending = new PendingRequest(request);
this._pendingRequests.set(request.requestId, pending);
@@ -99,7 +118,7 @@ Discarded request: ${JSON.stringify(request)}`));
this._pendingRequests.delete(request.requestId);
if (response.error) {
- const error = new KuzzleError(response.error);
+ const error = new KuzzleError(response.error, stack);
this.emit('queryError', error, request);
@@ -136,7 +155,4 @@ Discarded request: ${JSON.stringify(request)}`));
this._pendingRequests.clear();
}
-
}
-
-module.exports = { KuzzleAbstractProtocol };
diff --git a/src/protocols/abstract/PendingRequest.js b/src/protocols/abstract/PendingRequest.js
index 852ea9a0b..73aa5dfbd 100644
--- a/src/protocols/abstract/PendingRequest.js
+++ b/src/protocols/abstract/PendingRequest.js
@@ -20,4 +20,4 @@ class PendingRequest {
}
}
-module.exports = PendingRequest;
+module.exports = { PendingRequest };
diff --git a/src/protocols/abstract/Realtime.js b/src/protocols/abstract/Realtime.ts
similarity index 72%
rename from src/protocols/abstract/Realtime.js
rename to src/protocols/abstract/Realtime.ts
index 0dab94019..74bb34cc0 100644
--- a/src/protocols/abstract/Realtime.js
+++ b/src/protocols/abstract/Realtime.ts
@@ -1,10 +1,16 @@
'use strict';
-const { KuzzleAbstractProtocol } = require('./Base');
+import { KuzzleAbstractProtocol } from './Base';
-class BaseProtocolRealtime extends KuzzleAbstractProtocol {
- constructor (host, options = {}) {
- super(host, options);
+export abstract class BaseProtocolRealtime extends KuzzleAbstractProtocol {
+ protected _autoReconnect: boolean;
+ protected _reconnectionDelay: number;
+ protected wasConnected: boolean;
+ protected stopRetryingToConnect: boolean;
+ protected retrying: boolean;
+
+ constructor (host, options: any = {}, name: string) {
+ super(host, options, name);
this._autoReconnect = typeof options.autoReconnect === 'boolean' ? options.autoReconnect : true;
this._reconnectionDelay = typeof options.reconnectionDelay === 'number' ? options.reconnectionDelay : 1000;
@@ -18,18 +24,23 @@ class BaseProtocolRealtime extends KuzzleAbstractProtocol {
return this._autoReconnect;
}
- get reconnectionDelay () {
+ /**
+ * Number of milliseconds between reconnection attempts
+ */
+ get reconnectionDelay (): number {
return this._reconnectionDelay;
}
- connect() {
+ connect (): Promise {
this.state = 'connecting';
+
+ return Promise.resolve();
}
/**
* Called when the client's connection is established
*/
- clientConnected() {
+ clientConnected () {
super.clientConnected('connected', this.wasConnected);
this.state = 'connected';
@@ -40,7 +51,7 @@ class BaseProtocolRealtime extends KuzzleAbstractProtocol {
/**
* Called when the client's connection is closed
*/
- clientDisconnected() {
+ clientDisconnected () {
this.clear();
this.emit('disconnect');
}
@@ -54,8 +65,7 @@ class BaseProtocolRealtime extends KuzzleAbstractProtocol {
this.state = 'offline';
this.clear();
- const connectionError = new Error(`Unable to connect to kuzzle server at ${this.host}:${this.port}`);
- connectionError.internal = error;
+ const connectionError = new Error(`Unable to connect to kuzzle server at ${this.host}:${this.port}: ${error.message} (ws status=${error.status})`);
this.emit('networkError', connectionError);
@@ -90,5 +100,3 @@ class BaseProtocolRealtime extends KuzzleAbstractProtocol {
return this.state === 'connected';
}
}
-
-module.exports = BaseProtocolRealtime;
diff --git a/src/protocols/index.js b/src/protocols/index.js
deleted file mode 100644
index 1e39ea546..000000000
--- a/src/protocols/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict';
-
-const Http = require('./Http');
-const WebSocket = require('./WebSocket');
-
-module.exports = {
- Http,
- WebSocket
-};
diff --git a/src/protocols/index.ts b/src/protocols/index.ts
new file mode 100644
index 000000000..51c13cd4a
--- /dev/null
+++ b/src/protocols/index.ts
@@ -0,0 +1,2 @@
+export { default as WebSocket } from './WebSocket';
+export { default as Http } from './Http';
diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts
index 6062231a3..cfb3d9ae3 100644
--- a/src/utils/interfaces.ts
+++ b/src/utils/interfaces.ts
@@ -21,6 +21,31 @@ export interface KuzzleRequest extends JSONObject {
jwt?: string;
volatile?: JSONObject;
body?: JSONObject;
+ [key: string]: any;
+}
+
+/**
+ * Kuzzle API response
+ *
+ * @see https://docs.kuzzle.io/core/2/api/essentials/kuzzle-response/
+ */
+export interface KuzzleResponse extends JSONObject {
+ controller: string;
+ action: string;
+ index?: string;
+ collection?: string;
+ error?: {
+ id: string;
+ code: number;
+ message: string;
+ status: number;
+ stack?: string;
+ };
+ requestId: string;
+ result: JSONObject | null;
+ status: number;
+ volatile?: JSONObject;
+ room?: string;
}
/**
@@ -88,8 +113,14 @@ export interface ProfilePolicy {
* @see https://docs.kuzzle.io/core/2/guides/essentials/security#defining-roles
*/
export interface RoleRightsDefinition {
+ /**
+ * API controller name
+ */
[key: string]: {
actions: {
+ /**
+ * API action name
+ */
[key: string]: boolean
}
}
@@ -112,7 +143,7 @@ export interface ApiKey {
*/
userId: string;
/**
- * Expiration date in UNIX micro-timestamp format (-1 if the token never expires)
+ * Expiration date in Epoch-millis format (-1 if the token never expires)
*/
expiresAt: number;
/**
@@ -178,6 +209,11 @@ export interface Document {
/**
* Document retrieved from a search
+ *
+ * @property _id
+ * @property _version
+ * @property _source
+ * @property _score
*/
export interface DocumentHit extends Document {
/**
@@ -185,3 +221,214 @@ export interface DocumentHit extends Document {
*/
_score: number;
}
+
+export interface MappingsProperties {
+ /**
+ * Properties types definition
+ *
+ * @see https://docs.kuzzle.io/core/2/guides/essentials/database-mappings/#properties-types-definition
+ */
+ properties?: MappingsProperties,
+ /**
+ * Dynamic mapping policy
+ *
+ * @see https://docs.kuzzle.io/core/2/guides/essentials/database-mappings/#dynamic-mapping-policy
+ */
+ dynamic?: 'true' | 'false' | 'strict' | boolean
+}
+
+/**
+ * Collection mappings definition
+ *
+ * @see https://docs.kuzzle.io/core/2/guides/essentials/database-mappings/
+ */
+export interface CollectionMappings {
+ /**
+ * Collection metadata
+ *
+ * @see https://docs.kuzzle.io/core/2/guides/essentials/database-mappings/#collection-metadata
+ */
+ _meta?: JSONObject;
+ /**
+ * Properties types definition
+ *
+ * @see https://docs.kuzzle.io/core/2/guides/essentials/database-mappings/#properties-types-definition
+ */
+ properties?: MappingsProperties,
+ /**
+ * Dynamic mapping policy
+ *
+ * @see https://docs.kuzzle.io/core/2/guides/essentials/database-mappings/#dynamic-mapping-policy
+ */
+ dynamic?: 'true' | 'false' | 'strict' | boolean,
+}
+
+/**
+ * Enum for notification types
+ */
+export enum ENotificationType {
+ document = 'document',
+ user = 'user',
+ TokenExpired = 'TokenExpired'
+}
+
+/**
+ * Real-time notifications sent by Kuzzle.
+ *
+ */
+export interface Notification {
+ /**
+ * Notification type
+ */
+ type: ENotificationType;
+}
+
+export interface BaseNotification extends Notification {
+ /**
+ * Controller that triggered the notification
+ */
+ controller: string;
+ /**
+ * Action that triggered the notification
+ */
+ action: string;
+ /**
+ * Index name
+ */
+ index: string;
+ /**
+ * Collection name
+ */
+ collection: string;
+ /**
+ * Network protocol used to trigger the notification
+ */
+ protocol: string;
+ /**
+ * Subscription channel identifier.
+ * Can be used to link a notification to its corresponding subscription
+ */
+ room: string;
+ /**
+ * Timestamp of the event, in Epoch-millis format
+ */
+ timestamp: number;
+ /**
+ * Request volatile data
+ * @see https://docs.kuzzle.io/core/2/guides/essentials/volatile-data/
+ */
+ volatile: JSONObject;
+}
+
+/**
+ * State of the document regarding the scope
+ */
+export enum EDocumentScope {
+ /**
+ * Document enters or stays in the scope
+ */
+ in = 'in',
+ /**
+ * Document exit the scope
+ */
+ out = 'out'
+}
+
+/**
+ * Notification triggered by a document change.
+ * (create, update, delete)
+ */
+export interface DocumentNotification extends BaseNotification {
+ /**
+ * Updated document that triggered the notification
+ */
+ result: Document;
+ /**
+ * State of the document regarding the scope (`in` or `out`)
+ */
+ scope: EDocumentScope;
+
+ type: ENotificationType.document;
+}
+
+/**
+ * Tells wether an user leave or join the subscription room
+ */
+export enum EUserScope {
+ /**
+ * User enters the subscription room
+ */
+ in = 'in',
+ /**
+ * User leaves the subscription room
+ */
+ out = 'out'
+}
+
+/**
+ * Notification triggered by an user joining or leaving a subscription room
+ */
+export interface UserNotification extends BaseNotification {
+ /**
+ * Tell wether an user leave or join the subscription room (`in` or `out`)
+ */
+ user: EUserScope;
+
+ /**
+ * Contains the actual number of users in the subscription room
+ */
+ result: {
+ /**
+ * Updated users count sharing the same subscription room
+ */
+ count: number;
+ }
+
+ type: ENotificationType.user;
+}
+
+export interface ServerNotification extends BaseNotification {
+ /**
+ * Server message explaining why this notifications has been triggered
+ */
+ message: string;
+
+ type: ENotificationType.TokenExpired;
+}
+
+/**
+ * HTTP routes definition format
+ * @example
+ * {
+ * : {
+ * : { verb: , url: }
+ * }
+ * }
+ *
+ * {
+ * 'my-plugin/my-controller': {
+ * action: { verb: 'GET', url: '/some/url' },
+ * action2: { verb: 'GET', url: '/some/url/with/:parameter' }
+ * }
+ * }
+ */
+export interface HttpRoutes {
+ /**
+ * Controller name
+ */
+ [key: string]: {
+ /**
+ * Action name
+ */
+ [key: string]: {
+ /**
+ * HTTP verb
+ */
+ verb: string,
+ /**
+ * URL
+ */
+ url: string
+ }
+ }
+}
diff --git a/test/controllers/collection.test.js b/test/controllers/collection.test.js
index 03e83489f..ae9ba248a 100644
--- a/test/controllers/collection.test.js
+++ b/test/controllers/collection.test.js
@@ -16,7 +16,7 @@ describe('Collection Controller', () => {
});
describe('create', () => {
- it('should call collection/create query and return a Promise which resolves an acknowledgement', () => {
+ it('should call collection/create query and return a Promise which resolves', () => {
kuzzle.query.resolves({result: {acknowledged: true}});
return kuzzle.collection.create('index', 'collection', null, options)
@@ -31,7 +31,7 @@ describe('Collection Controller', () => {
collection: 'collection'
}, options);
- should(res.acknowledged).be.a.Boolean().and.be.true();
+ should(res).be.undefined();
});
});
@@ -50,13 +50,13 @@ describe('Collection Controller', () => {
collection: 'collection'
}, options);
- should(res.acknowledged).be.a.Boolean().and.be.true();
+ should(res).be.undefined();
});
});
});
describe('deleteSpecifications', () => {
- it('should call collection/deleteSpecifications query and return a Promise which resolves an acknowledgement', () => {
+ it('should call collection/deleteSpecifications query and return a Promise which resolves', () => {
kuzzle.query.resolves({result: {acknowledged: true}});
return kuzzle.collection.deleteSpecifications('index', 'collection', options)
@@ -70,7 +70,7 @@ describe('Collection Controller', () => {
collection: 'collection'
}, options);
- should(res.acknowledged).be.a.Boolean().and.be.true();
+ should(res).be.undefined();
});
});
});
@@ -110,7 +110,7 @@ describe('Collection Controller', () => {
collection: 'collection'
}, options);
- should(res).be.Null();
+ should(res).be.undefined();
});
});
});
@@ -301,7 +301,7 @@ describe('Collection Controller', () => {
collection: 'collection'
}, options);
- should(res.acknowledged).be.a.Boolean().and.be.true();
+ should(res).be.undefined();
});
});
});
@@ -345,7 +345,7 @@ describe('Collection Controller', () => {
collection: 'collection'
});
- should(res).match({ foo: 'bar' });
+ should(res).be.undefined();
});
});
});
@@ -403,4 +403,22 @@ describe('Collection Controller', () => {
});
});
});
+
+ describe('delete', () => {
+ it('should call collection/delete query and return a promise which resolves an acknowledgement', () => {
+ kuzzle.query.resolves({result: {acknowledged: true}});
+ return kuzzle.collection.delete('index', 'collection')
+ .then(res => {
+ should(kuzzle.query)
+ .be.calledOnce()
+ .be.calledWith({
+ controller: 'collection',
+ action: 'delete',
+ index: 'index',
+ collection: 'collection',
+ });
+ should(res).be.undefined();
+ });
+ });
+ });
});
diff --git a/test/controllers/index.test.js b/test/controllers/index.test.js
index 409a9ed13..8bd2e901a 100644
--- a/test/controllers/index.test.js
+++ b/test/controllers/index.test.js
@@ -33,8 +33,7 @@ describe('Index Controller', () => {
index: 'index'
}, options);
- should(res.acknowledged).be.a.Boolean().and.be.true();
- should(res.shards_acknowledged).be.a.Boolean().and.be.true();
+ should(res).be.undefined();
});
});
});
@@ -55,7 +54,7 @@ describe('Index Controller', () => {
index: 'index'
}, options);
- should(res).be.a.Boolean().and.be.true();
+ should(res).be.undefined();
});
});
});
diff --git a/test/controllers/realtime.test.js b/test/controllers/realtime.test.js
index c264a24cb..698ecd767 100644
--- a/test/controllers/realtime.test.js
+++ b/test/controllers/realtime.test.js
@@ -26,17 +26,52 @@ describe('Realtime Controller', () => {
});
describe('on: tokenExpired', () => {
- it('should call tokenExpired() method', () => {
- kuzzle.realtime.tokenExpired = sinon.stub();
+ it('should call removeSubscriptions() method', () => {
+ kuzzle.realtime.removeSubscriptions = sinon.stub();
kuzzle.emit('tokenExpired');
process.nextTick(() => {
- should(kuzzle.realtime.tokenExpired).be.called();
+ should(kuzzle.realtime.removeSubscriptions).be.called();
});
});
});
+ describe('on: disconnected', () => {
+ it('should call saveSubscriptions() method', () => {
+ kuzzle.realtime.saveSubscriptions = sinon.stub();
+
+ kuzzle.emit('disconnected');
+
+ process.nextTick(() => {
+ should(kuzzle.realtime.saveSubscriptions).be.called();
+ });
+ });
+ });
+
+ describe('on: networkError', () => {
+ it('should call saveSubscriptions() method', () => {
+ kuzzle.realtime.saveSubscriptions = sinon.stub();
+
+ kuzzle.emit('networkError');
+
+ process.nextTick(() => {
+ should(kuzzle.realtime.saveSubscriptions).be.called();
+ });
+ });
+ });
+
+ describe('on: reconnected', () => {
+ it('should call resubscribe() method', () => {
+ kuzzle.realtime.resubscribe = sinon.stub();
+
+ kuzzle.emit('reconnected');
+
+ process.nextTick(() => {
+ should(kuzzle.realtime.resubscribe).be.called();
+ });
+ });
+ });
describe('#count', () => {
it('should call realtime/count query with the roomId and return a Promise which resolves a number', () => {
@@ -139,17 +174,17 @@ describe('Realtime Controller', () => {
body = {foo: 'bar'},
cb = sinon.stub();
- kuzzle.realtime.subscriptions = new Map();
+ kuzzle.realtime._subscriptions = new Map();
return kuzzle.realtime.subscribe('index', 'collection', body, cb, options)
.then(() => {
- const subscriptions = kuzzle.realtime.subscriptions.get(roomId);
+ const subscriptions = kuzzle.realtime._subscriptions.get(roomId);
should(subscriptions).be.an.Array();
should(subscriptions.length).be.exactly(1);
should(subscriptions[0]).be.exactly(room);
return kuzzle.realtime.subscribe('index', 'collection', body, cb, options);
}).then(() => {
- const subscriptions = kuzzle.realtime.subscriptions.get(roomId);
+ const subscriptions = kuzzle.realtime._subscriptions.get(roomId);
should(subscriptions).be.an.Array();
should(subscriptions.length).be.exactly(2);
@@ -175,8 +210,8 @@ describe('Realtime Controller', () => {
room1.removeListeners.reset();
room2.removeListeners.reset();
- kuzzle.realtime.subscriptions.set(roomId, [room1, room2]);
- kuzzle.realtime.subscriptions.set('foo', [room3]);
+ kuzzle.realtime._subscriptions.set(roomId, [room1, room2]);
+ kuzzle.realtime._subscriptions.set('foo', [room3]);
kuzzle.query.resolves({result: roomId});
});
@@ -193,12 +228,12 @@ describe('Realtime Controller', () => {
it('should delete rooms from local storage', () => {
return kuzzle.realtime.unsubscribe(roomId)
.then(() => {
- should(kuzzle.realtime.subscriptions.get(roomId)).be.undefined();
+ should(kuzzle.realtime._subscriptions.get(roomId)).be.undefined();
// Check we do not remove other registered rooms:
- should(kuzzle.realtime.subscriptions.get('foo')).be.an.Array();
- should(kuzzle.realtime.subscriptions.get('foo').length).be.equal(1);
- should(kuzzle.realtime.subscriptions.get('foo')[0]).be.equal(room3);
+ should(kuzzle.realtime._subscriptions.get('foo')).be.an.Array();
+ should(kuzzle.realtime._subscriptions.get('foo').length).be.equal(1);
+ should(kuzzle.realtime._subscriptions.get('foo')[0]).be.equal(room3);
});
});
@@ -218,7 +253,7 @@ describe('Realtime Controller', () => {
});
});
- describe('#disconnected', () => {
+ describe('#saveSubscriptions', () => {
it('should disable current subscriptions', () => {
const roomA = {
autoResubscribe: true,
@@ -233,15 +268,15 @@ describe('Realtime Controller', () => {
removeListeners: sinon.stub()
};
- kuzzle.realtime.subscriptions = new Map([
+ kuzzle.realtime._subscriptions = new Map([
['foo', [roomA, roomB]],
['bar', [roomC]]
]);
- kuzzle.realtime.disconnected();
+ kuzzle.realtime.saveSubscriptions();
- should(kuzzle.realtime.subscriptions).be.empty();
- should(kuzzle.realtime.subscriptionsOff).eql(new Map([
+ should(kuzzle.realtime._subscriptions).be.empty();
+ should(kuzzle.realtime._subscriptionsOff).eql(new Map([
['foo', [roomA]]
]));
for (const room of [roomA, roomB, roomC]) {
@@ -250,21 +285,21 @@ describe('Realtime Controller', () => {
});
});
- describe('#reconnected', () => {
+ describe('#resubscribe', () => {
it('should resubmit pending subcriptions', () => {
const roomA = { subscribe: sinon.stub().resolves() };
const roomB = { subscribe: sinon.stub().resolves() };
const roomC = { subscribe: sinon.stub().resolves() };
- kuzzle.realtime.subscriptionsOff = new Map([
+ kuzzle.realtime._subscriptionsOff = new Map([
['foo', [roomA, roomB]],
['bar', [roomC]]
]);
- kuzzle.realtime.reconnected();
+ kuzzle.realtime.resubscribe();
- should(kuzzle.realtime.subscriptionsOff).be.empty();
- should(kuzzle.realtime.subscriptions).eql(new Map([
+ should(kuzzle.realtime._subscriptionsOff).be.empty();
+ should(kuzzle.realtime._subscriptions).eql(new Map([
['foo', [roomA, roomB]],
['bar', [roomC]]
]));
@@ -276,19 +311,19 @@ describe('Realtime Controller', () => {
});
});
- describe('#tokenExpired', () => {
- it('should clear all subscriptions and emit a "tokenExpired" event', () => {
+ describe('#removeSubscriptions', () => {
+ it('should clear all subscriptions', () => {
const stub = sinon.stub();
kuzzle.jwt = 'foobar';
for (let i = 0; i < 10; i++) {
- kuzzle.realtime.subscriptions.set(uuidv4(), [{removeListeners: stub}]);
+ kuzzle.realtime._subscriptions.set(uuidv4(), [{removeListeners: stub}]);
}
- kuzzle.realtime.tokenExpired();
+ kuzzle.realtime.removeSubscriptions();
- should(kuzzle.realtime.subscriptions).be.empty();
+ should(kuzzle.realtime._subscriptions).be.empty();
should(stub.callCount).be.eql(10);
});
});
diff --git a/test/kuzzle/connect.test.js b/test/kuzzle/connect.test.js
index 63c784b55..a151ffbd5 100644
--- a/test/kuzzle/connect.test.js
+++ b/test/kuzzle/connect.test.js
@@ -53,7 +53,7 @@ describe('Kuzzle connect', () => {
kuzzle = new Kuzzle(protocols.nowhere),
eventStub = sinon.stub();
- kuzzle.realtime.disconnected = sinon.stub();
+ kuzzle.realtime.saveSubscriptions = sinon.stub();
kuzzle.addListener('networkError', eventStub);
@@ -62,7 +62,7 @@ describe('Kuzzle connect', () => {
throw new Error('should not happen');
})
.catch(() => {
- should(kuzzle.realtime.disconnected).be.calledOnce();
+ should(kuzzle.realtime.saveSubscriptions).be.calledOnce();
should(eventStub).be.calledOnce();
});
});
@@ -85,13 +85,13 @@ describe('Kuzzle connect', () => {
kuzzle = new Kuzzle(protocols.somewhereagain),
eventStub = sinon.stub();
- kuzzle.realtime.reconnected = sinon.stub();
+ kuzzle.realtime.resubscribe = sinon.stub();
kuzzle.addListener('reconnected', eventStub);
return kuzzle.connect()
.then(() => {
- should(kuzzle.realtime.reconnected).be.calledOnce();
+ should(kuzzle.realtime.resubscribe).be.calledOnce();
should(eventStub).be.calledOnce();
});
});
@@ -137,14 +137,14 @@ describe('Kuzzle connect', () => {
kuzzle = new Kuzzle(protocols.somewhere),
eventStub = sinon.stub();
- kuzzle.realtime.disconnected = sinon.stub();
+ kuzzle.realtime.saveSubscriptions = sinon.stub();
kuzzle.addListener('disconnected', eventStub);
return kuzzle.connect()
.then(() => kuzzle.protocol.disconnect())
.then(() => {
- should(kuzzle.realtime.disconnected).be.calledOnce();
+ should(kuzzle.realtime.saveSubscriptions).be.calledOnce();
should(eventStub).be.calledOnce();
});
});
diff --git a/test/kuzzle/listenersManagement.test.js b/test/kuzzle/listenersManagement.test.js
index 0bd0599dc..a6d599315 100644
--- a/test/kuzzle/listenersManagement.test.js
+++ b/test/kuzzle/listenersManagement.test.js
@@ -2,7 +2,7 @@ const should = require('should');
const sinon = require('sinon');
const { Kuzzle } = require('../../src/Kuzzle');
-const { KuzzleEventEmitter } =require('../../src/core/KuzzleEventEmitter');
+const { KuzzleEventEmitter } = require('../../src/core/KuzzleEventEmitter');
const ProtocolMock = require('../mocks/protocol.mock');
describe('Kuzzle listeners management', () => {
diff --git a/test/protocol/Base.test.js b/test/protocol/Base.test.js
index bd2652459..bec5d3f0b 100644
--- a/test/protocol/Base.test.js
+++ b/test/protocol/Base.test.js
@@ -1,9 +1,9 @@
-const
- should = require('should'),
- sinon = require('sinon'),
- KuzzleError = require('../../src/KuzzleError'),
- { KuzzleAbstractProtocol } = require('../../src/protocols/abstract/Base'),
- PendingRequest = require('../../src/protocols/abstract/PendingRequest');
+const should = require('should');
+const sinon = require('sinon');
+
+const { KuzzleError } = require('../../src/KuzzleError');
+const { KuzzleAbstractProtocol } = require('../../src/protocols/abstract/Base');
+const { PendingRequest } = require('../../src/protocols/abstract/PendingRequest');
describe('Common Protocol', () => {
let
@@ -25,6 +25,30 @@ describe('Common Protocol', () => {
should(protocol.port).be.eql(443);
});
+ it('should use ssl option if available and fallback to sslConnection option', () => {
+ protocol = new KuzzleAbstractProtocol('somewhere', { ssl: true });
+
+ should(protocol.ssl).be.true();
+
+ protocol = new KuzzleAbstractProtocol('somewhere', { sslConnection: true });
+
+ should(protocol.ssl).be.true();
+ });
+
+ it('should use ssl connection when port is 443 or 7443 and option is not defined', () => {
+ protocol = new KuzzleAbstractProtocol('somewhere', { port: 443 });
+
+ should(protocol.ssl).be.true();
+
+ protocol = new KuzzleAbstractProtocol('somewhere', { port: 7443 });
+
+ should(protocol.ssl).be.true();
+
+ protocol = new KuzzleAbstractProtocol('somewhere', { port: 4242 });
+
+ should(protocol.ssl).be.false();
+ });
+
it('should use 7512 when no port is given or when port is not a parseable number', () => {
protocol = new KuzzleAbstractProtocol('somewhere', { port: 'foobar' });
@@ -91,7 +115,7 @@ describe('Common Protocol', () => {
const pending = protocol.pendingRequests.get('bar');
- pending.should.be.an.instanceOf(PendingRequest).and.match({request});
+ should(pending).be.instanceOf(PendingRequest).and.match({request});
});
it('should fire a "queryError" event and reject if an error occurred', () => {
@@ -161,7 +185,7 @@ describe('Common Protocol', () => {
should(error).be.instanceOf(KuzzleError);
should(error.message).be.eql('foo-bar');
should(error.status).be.eql(442);
- should(error.stack).be.eql('you are the bug');
+ should(error.kuzzleStack).be.eql('you are the bug');
});
});
@@ -185,7 +209,7 @@ describe('Common Protocol', () => {
should(error).be.instanceOf(KuzzleError);
should(error.message).be.eql('foo-bar');
should(error.status).be.eql(206);
- should(error.stack).be.eql('you are the bug');
+ should(error.kuzzleStack).be.eql('you are the bug');
should(error.errors).be.an.Array();
should(error.errors.length).eql(2);
should(error.count).eql(42);
diff --git a/test/protocol/Http.test.js b/test/protocol/Http.test.js
index d435a1b1b..18e122f08 100644
--- a/test/protocol/Http.test.js
+++ b/test/protocol/Http.test.js
@@ -3,7 +3,7 @@ const should = require('should');
const sinon = require('sinon');
const staticHttpRoutes = require('../../src/protocols/routes.json');
-const Http = require('../../src/protocols/Http');
+const { default: Http } = require('../../src/protocols/Http');
describe('HTTP networking module', () => {
let protocol;
@@ -557,7 +557,7 @@ describe('HTTP networking module', () => {
beforeEach(() => {
httpRequestStub = sinon.stub().resolves({body: JSON.stringify(mockResponseBody)});
- const MockHttp = proxyquire('../../src/protocols/Http', {
+ const { default: MockHttp } = proxyquire('../../src/protocols/Http', {
'min-req-promise': {request: httpRequestStub}
});
@@ -663,9 +663,7 @@ describe('HTTP networking module', () => {
return xhrStub;
};
- protocol = new Http('address', {
- port: 1234
- });
+ protocol = new Http('address', { port: 1234 });
});
afterEach(() => {
@@ -829,13 +827,14 @@ describe('HTTP networking module', () => {
}
},
};
-
- protocol.customRoutes = {
+ const customRoutes = {
foo: {
list: { verb: 'GET', url: '/overwrite/me/master' }
}
};
+ protocol = new Http('address', { port: 1234, customRoutes });
+
const routes = protocol._constructRoutes(publicApi);
should(routes.foo.list.url).be.eql('/overwrite/me/master');
diff --git a/test/protocol/WebSocket.test.js b/test/protocol/WebSocket.test.js
index cfd3d0989..205f0d443 100644
--- a/test/protocol/WebSocket.test.js
+++ b/test/protocol/WebSocket.test.js
@@ -1,10 +1,10 @@
-const
- should = require('should'),
- sinon = require('sinon'),
- lolex = require('lolex'),
- NodeWS = require('ws'),
- WS = require('../../src/protocols/WebSocket'),
- windowMock = require('../mocks/window.mock');
+const should = require('should');
+const sinon = require('sinon');
+const lolex = require('lolex');
+const NodeWS = require('ws');
+
+const { default: WS } = require('../../src/protocols/WebSocket');
+const windowMock = require('../mocks/window.mock');
describe('WebSocket networking module', () => {
let
@@ -246,8 +246,6 @@ describe('WebSocket networking module', () => {
clock.tick(10);
should(cb).be.calledOnce();
should(cb.firstCall.args[0]).be.an.instanceOf(Error);
- should(cb.firstCall.args[0].internal.status).be.equal(4666);
- should(cb.firstCall.args[0].internal.message).be.equal('foobar');
should(websocket.listeners('networkError').length).be.eql(1);
websocket.clear.should.be.calledOnce();
@@ -259,8 +257,6 @@ describe('WebSocket networking module', () => {
clock.tick(10);
should(cb).be.calledOnce();
should(cb.firstCall.args[0]).be.an.instanceOf(Error);
- should(cb.firstCall.args[0].internal.status).be.equal(4666);
- should(cb.firstCall.args[0].internal.message).be.equal('foobar');
should(websocket.listeners('networkError').length).be.eql(1);
websocket.clear.should.be.calledOnce();
});
diff --git a/tsconfig.json b/tsconfig.json
index 1ea049850..4af52bb73 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -7,7 +7,8 @@
"moduleResolution": "node",
"sourceMap": true,
"baseUrl": ".",
- "resolveJsonModule": true
+ "resolveJsonModule": true,
+ "esModuleInterop": true
},
"rootDir": "src/",
"include": [