Skip to content

Commit

Permalink
Merge pull request #725 from kuzzleio/7.10.7-proposal
Browse files Browse the repository at this point in the history
# [7.10.7](https://github.com/kuzzleio/sdk-javascript/releases/tag/7.10.7) (2023-03-06)


#### Enhancements

- [ [#723](#723) ] Improve typings   ([ScreamZ](https://github.com/ScreamZ))
- [ [#724](#724) ] Add support and documentation to use API keys   ([ScreamZ](https://github.com/ScreamZ))
---
  • Loading branch information
Aschen authored Mar 15, 2023
2 parents 2033928 + 065accf commit 9da1b1b
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 48 deletions.
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 <support@kuzzle.io>",
"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

0 comments on commit 9da1b1b

Please sign in to comment.