Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ try {
*/

console.log('API key successfully created');

// Then use it with your client. Note: You don't need to call login after this because this bypasses the authentication system.
kuzzle.setAPIKey(apiKey._source.token)
} catch (e) {
console.error(e);
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kuzzle-sdk",
"version": "7.10.6",
"version": "7.10.7",
"description": "Official Javascript SDK for Kuzzle",
"author": "The Kuzzle Team <[email protected]>",
"repository": {
Expand Down
69 changes: 65 additions & 4 deletions src/Kuzzle.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { KuzzleEventEmitter } from "./core/KuzzleEventEmitter";
import {
KuzzleEventEmitter,
PrivateAndPublicSDKEvents,
PublicKuzzleEvents,
} from "./core/KuzzleEventEmitter";
import { KuzzleAbstractProtocol } from "./protocols/abstract/Base";

import { AuthController } from "./controllers/Auth";
Expand All @@ -15,11 +19,13 @@ import { Deprecation } from "./utils/Deprecation";
import { uuidv4 } from "./utils/uuidv4";
import { proxify } from "./utils/proxify";
import { debug } from "./utils/debug";
import { BaseRequest, JSONObject } from "./types";
import { BaseRequest, JSONObject, Notification } from "./types";
import { RequestPayload } from "./types/RequestPayload";
import { ResponsePayload } from "./types/ResponsePayload";
import { RequestTimeoutError } from "./RequestTimeoutError";
import { BaseProtocolRealtime } from "./protocols/abstract/Realtime";
import { KuzzleError } from "./KuzzleError";
import { DisconnectionOrigin } from "./protocols/DisconnectionOrigin";

// Defined by webpack plugin
declare const SDKVERSION: any;
Expand Down Expand Up @@ -72,7 +78,7 @@ export class Kuzzle extends KuzzleEventEmitter {
/**
* List of every events emitted by the SDK.
*/
public events = [
public events: PublicKuzzleEvents[] = [
"callbackError",
"connected",
"discarded",
Expand Down Expand Up @@ -542,7 +548,7 @@ export class Kuzzle extends KuzzleEventEmitter {
* Emit an event to all registered listeners
* An event cannot be emitted multiple times before a timeout has been reached.
*/
emit(eventName: string, ...payload) {
public emit(eventName: PrivateAndPublicSDKEvents, ...payload: unknown[]) {
const now = Date.now(),
protectedEvent = this._protectedEvents[eventName];

Expand All @@ -563,6 +569,48 @@ export class Kuzzle extends KuzzleEventEmitter {
return super.emit(eventName, ...payload);
}

on(
eventName: "connected" | "reconnected" | "reAuthenticated" | "tokenExpired",
listener: () => void
): this;

on(
eventName: "logoutAttempt",
listener: (status: { success: true }) => void
): this;
on(
eventName: "loginAttempt",
listener: (data: { success: boolean; error: string }) => void
): this;
on(eventName: "discarded", listener: (request: RequestPayload) => void): this;
on(
eventName: "disconnected",
listener: (context: { origin: DisconnectionOrigin }) => void
): this;
on(
eventName: "networkError" | "reconnectionError",
listener: (error: Error) => void
): this;
on(
eventName: "offlineQueuePop",
listener: (request: RequestPayload) => void
): this;
on(
eventName: "offlineQueuePush",
listener: (data: { request: RequestPayload }) => void
): this;
on(
eventName: "queryError",
listener: (data: { error: KuzzleError; request: RequestPayload }) => void
): this;
on(
eventName: "callbackError",
listener: (data: { error: KuzzleError; notification: Notification }) => void
): this;
on(eventName: PublicKuzzleEvents, listener: (args: any) => void): this {
return super.on(eventName, listener);
}

/**
* Connects to a Kuzzle instance
*/
Expand Down Expand Up @@ -620,6 +668,19 @@ export class Kuzzle extends KuzzleEventEmitter {
return this.protocol.connect();
}

/**
* Set this client to use a specific API key.
*
* After doing this you don't need to use login as it bypasses the authentication process.
*/
public setAPIKey(apiKey: string) {
if (apiKey.match(/^kapikey-/) === null) {
throw new Error("Invalid API key. Missing the `kapikey-` prefix.");
}

this.jwt = apiKey;
}

async _reconnect() {
if (this._reconnectInProgress) {
return;
Expand Down
69 changes: 60 additions & 9 deletions src/core/KuzzleEventEmitter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
type ListenerFunction = (...args: unknown[]) => unknown;

class Listener {
public fn: (...any) => any;
public fn: ListenerFunction;
public once: boolean;

constructor(fn, once = false) {
Expand All @@ -8,6 +10,37 @@ class Listener {
}
}

export type PublicKuzzleEvents =
| "callbackError"
| "connected"
| "discarded"
| "disconnected"
| "loginAttempt"
| "logoutAttempt"
| "networkError"
| "offlineQueuePush"
| "offlineQueuePop"
| "queryError"
| "reAuthenticated"
| "reconnected"
| "reconnectionError"
| "tokenExpired";

type PrivateKuzzleEvents =
| "connect"
| "reconnect"
| "disconnect"
| "offlineQueuePush"
| "websocketRenewalStart"
| "websocketRenewalDone";

/**
* For internal use only
*/
export type PrivateAndPublicSDKEvents =
| PublicKuzzleEvents
| PrivateKuzzleEvents;

/**
* @todo proper TS conversion
*/
Expand All @@ -18,23 +51,28 @@ export class KuzzleEventEmitter {
this._events = new Map();
}

private _exists(listeners, fn) {
private _exists(listeners: Listener[], fn: ListenerFunction) {
return Boolean(listeners.find((listener) => listener.fn === fn));
}

listeners(eventName) {
listeners(eventName: PrivateAndPublicSDKEvents) {
if (!this._events.has(eventName)) {
return [];
}

return this._events.get(eventName).map((listener) => listener.fn);
}

addListener(eventName, listener, once = false) {
addListener(
eventName: PrivateAndPublicSDKEvents,
listener: ListenerFunction,
once = false
) {
if (!eventName || !listener) {
return this;
}

// TODO: this check could be safely, when TypeScript type will be completed.
const listenerType = typeof listener;

if (listenerType !== "function") {
Expand All @@ -54,7 +92,10 @@ export class KuzzleEventEmitter {
return this;
}

on(eventName, listener) {
on(
eventName: PrivateAndPublicSDKEvents,
listener: (args: any) => void
): this {
return this.addListener(eventName, listener);
}

Expand Down Expand Up @@ -90,7 +131,12 @@ export class KuzzleEventEmitter {
return this.prependListener(eventName, listener, true);
}

removeListener(eventName, listener) {
removeListener(
eventName: PrivateAndPublicSDKEvents,
listener: () => void
): this;
removeListener(eventName: string, listener: () => void): this;
removeListener(eventName: string, listener: (...args: unknown[]) => void) {
const listeners = this._events.get(eventName);

if (!listeners || !listeners.length) {
Expand All @@ -110,7 +156,9 @@ export class KuzzleEventEmitter {
return this;
}

removeAllListeners(eventName?: string) {
removeAllListeners(eventName?: PrivateAndPublicSDKEvents): this;
removeAllListeners(eventName?: string): this;
removeAllListeners(eventName?: string): this {
if (eventName) {
this._events.delete(eventName);
} else {
Expand All @@ -120,7 +168,10 @@ export class KuzzleEventEmitter {
return this;
}

emit(eventName, ...payload) {
// TODO: Improve these unknown type someday, to secure all emit events and be sure they match {@link KuzzleEventEmitter.on}.
emit(eventName: PrivateAndPublicSDKEvents, ...payload: unknown[]): boolean;
emit(eventName: string, ...payload: unknown[]): boolean;
emit(eventName: string, ...payload: unknown[]): boolean {
const listeners = this._events.get(eventName);

if (listeners === undefined) {
Expand Down Expand Up @@ -148,7 +199,7 @@ export class KuzzleEventEmitter {
return Array.from(this._events.keys());
}

listenerCount(eventName) {
listenerCount(eventName: PrivateAndPublicSDKEvents) {
return (
(this._events.has(eventName) && this._events.get(eventName).length) || 0
);
Expand Down
10 changes: 5 additions & 5 deletions src/protocols/DisconnectionOrigin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const WEBSOCKET_AUTH_RENEWAL = "websocket/auth-renewal";
const USER_CONNECTION_CLOSED = "user/connection-closed";
const NETWORK_ERROR = "network/error";

export { WEBSOCKET_AUTH_RENEWAL, USER_CONNECTION_CLOSED, NETWORK_ERROR };
export enum DisconnectionOrigin {
WEBSOCKET_AUTH_RENEWAL = "websocket/auth-renewal",
USER_CONNECTION_CLOSED = "user/connection-closed",
NETWORK_ERROR = "network/error",
}
4 changes: 2 additions & 2 deletions src/protocols/WebSocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { BaseProtocolRealtime } from "./abstract/Realtime";
import { JSONObject } from "../types";
import { RequestPayload } from "../types/RequestPayload";
import HttpProtocol from "./Http";
import * as DisconnectionOrigin from "./DisconnectionOrigin";
import { DisconnectionOrigin } from "./DisconnectionOrigin";

/**
* WebSocket protocol used to connect to a Kuzzle server.
Expand Down Expand Up @@ -285,7 +285,7 @@ export default class WebSocketProtocol extends BaseProtocolRealtime {
/**
* @override
*/
clientDisconnected(origin: string) {
clientDisconnected(origin: DisconnectionOrigin) {
clearInterval(this.pingIntervalId);
this.pingIntervalId = null;
super.clientDisconnected(origin);
Expand Down
9 changes: 5 additions & 4 deletions src/protocols/abstract/Realtime.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"use strict";

import { KuzzleAbstractProtocol } from "./Base";
import * as DisconnectionOrigin from "../DisconnectionOrigin";
import { getBrowserWindow, isBrowser } from "../../utils/browser";
import { DisconnectionOrigin } from "../DisconnectionOrigin";
import { KuzzleError } from "../../KuzzleError";

export abstract class BaseProtocolRealtime extends KuzzleAbstractProtocol {
protected _reconnectionDelay: number;
Expand Down Expand Up @@ -56,17 +57,17 @@ export abstract class BaseProtocolRealtime extends KuzzleAbstractProtocol {
*
* @param {string} origin String that describe what is causing the disconnection
*/
clientDisconnected(origin: string) {
clientDisconnected(origin: DisconnectionOrigin) {
this.clear();
this.emit("disconnect", { origin });
}

/**
* Called when the client's connection is closed with an error state
*
* @param {Error} error
* @param {KuzzleError} error
*/
clientNetworkError(error) {
clientNetworkError(error: KuzzleError) {
// Only emit disconnect once, if the connection was ready before
if (this.isReady()) {
this.emit("disconnect", { origin: DisconnectionOrigin.NETWORK_ERROR });
Expand Down
4 changes: 1 addition & 3 deletions src/types/JSONObject.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/**
* An interface representing an object with string key and any value
*/
export interface JSONObject {
[key: string]: JSONObject | any;
}
export type JSONObject = Record<PropertyKey, any>;
22 changes: 13 additions & 9 deletions src/types/Notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@ import { KDocument, KDocumentContentGeneric } from ".";
*/
export type NotificationType = "document" | "user" | "TokenExpired";

/**
* Real-time notifications sent by Kuzzle.
*
*/
export interface Notification {
export interface BaseNotification {
/**
* Notification type
*/
type: NotificationType;
}

export interface BaseNotification extends Notification {
/**
* Controller that triggered the notification
*/
Expand Down Expand Up @@ -62,11 +56,13 @@ export interface BaseNotification extends Notification {
* Notification triggered by a document change.
* (create, update, delete)
*/
export interface DocumentNotification extends BaseNotification {
export interface DocumentNotification<
TDocContent extends KDocumentContentGeneric = KDocumentContentGeneric
> extends BaseNotification {
/**
* Updated document that triggered the notification
*/
result: KDocument<KDocumentContentGeneric>;
result: KDocument<TDocContent>;
/**
* State of the document regarding the scope (`in` or `out`)
*/
Expand Down Expand Up @@ -105,3 +101,11 @@ export interface ServerNotification extends BaseNotification {

type: "TokenExpired";
}

/**
* Real-time notifications sent by Kuzzle.
*/
export type Notification =
| DocumentNotification
| UserNotification
| ServerNotification;
Loading