Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@oada/client

Package Overview
Dependencies
Maintainers
8
Versions
77
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@oada/client - npm Package Compare versions

Comparing version 0.0.3 to 1.0.0

41

dist/client.d.ts

@@ -1,26 +0,33 @@

import { Response } from "./websocket";
import { WebSocketClient } from "./websocket";
import { SocketResponse } from "./websocket";
import { Json, Change } from ".";
export interface Config {
domain: string;
options?: {
redirect: string;
metadata: string;
scope: string;
};
token?: string;
concurrency?: number;
_ws?: WebSocketClient;
}
export declare type Response = SocketResponse;
export interface GETRequest {
path: string;
tree?: object;
watchCallback?: (response: Response) => void;
watchCallback?: (response: Readonly<Change>) => void;
}
export interface WatchRequest {
path: string;
watchCallback: (response: Response) => void;
rev?: string;
watchCallback: (response: Readonly<Change>) => void;
}
export interface PUTRequest {
path: string;
data: object;
data: Json;
contentType?: string;
tree?: object;
}
export interface POSTRequest {
path: string;
data: Json;
contentType?: string;
tree?: object;
}
export interface HEADRequest {

@@ -34,10 +41,16 @@ path: string;

private _token;
private _ws?;
constructor();
connect(config: Config): Promise<void>;
disconnect(): void;
private _domain;
private _concurrency;
private _ws;
constructor(config: Config);
clone(token: string): OADAClient;
getToken(): string;
getDomain(): string;
disconnect(): Promise<void>;
get(request: GETRequest): Promise<Response>;
watch(request: WatchRequest): Promise<Response>;
watch(request: WatchRequest): Promise<string>;
unwatch(requestId: string): Promise<Response>;
private _recursiveGet;
put(request: PUTRequest): Promise<Response>;
post(request: POSTRequest): Promise<Response>;
head(request: HEADRequest): Promise<Response>;

@@ -44,0 +57,0 @@ delete(request: DELETERequest): Promise<Response>;

@@ -17,30 +17,37 @@ "use strict";

class OADAClient {
constructor() {
constructor(config) {
this._token = "";
this._domain = "";
this._concurrency = 1;
this._domain = config.domain;
this._token = config.token || this._token;
this._concurrency = config.concurrency || this._concurrency;
this._ws = new websocket_1.WebSocketClient(this._domain, this._concurrency);
}
connect(config) {
if (this._ws && this._ws.isConnected()) {
throw new Error("Already connected");
}
if (!config.token) {
throw new Error("Token is required.");
}
this._ws = new websocket_1.WebSocketClient(config.domain);
this._token = config.token;
return this._ws.connect();
clone(token) {
const c = new OADAClient({
domain: this._domain,
token: token,
concurrency: this._concurrency,
_ws: this._ws,
});
return c;
}
getToken() {
return this._token;
}
getDomain() {
return this._domain;
}
disconnect() {
if (!this._ws || !this._ws.isConnected()) {
if (!this._ws.isConnected()) {
throw new Error("Not connected");
}
this._ws.disconnect();
return this._ws.disconnect();
}
async get(request) {
if (!this._ws || !this._ws.isConnected()) {
throw new Error("Not connected.");
}
const topLevelResponse = await this._ws.request({
method: "get",
headers: {
authorization: "Bearer " + this._token,
authorization: `Bearer ${this._token}`,
},

@@ -52,7 +59,11 @@ path: request.path,

const subTree = utils.getObjectAtPath(request.tree, arrayPath);
topLevelResponse.data = await this._recursiveGet(request.path, subTree, topLevelResponse.data);
topLevelResponse.data = await this._recursiveGet(request.path, subTree, topLevelResponse.data || {});
}
if (request.watchCallback) {
const watchResponse = await this.watch({
const rev = topLevelResponse.headers
? topLevelResponse.headers["x-oada-rev"]
: undefined;
await this.watch({
path: request.path,
rev,
watchCallback: request.watchCallback,

@@ -64,19 +75,29 @@ });

async watch(request) {
if (!this._ws || !this._ws.isConnected()) {
throw new Error("Not connected.");
let headers = {};
if (request.rev) {
headers["x-oada-rev"] = request.rev;
}
const callback = (response) => {
if (!response.change) {
return;
const r = await this._ws.request({
method: "watch",
headers: Object.assign({ authorization: `Bearer ${this._token}` }, headers),
path: request.path,
}, (resp) => {
for (const change of resp.change) {
request.watchCallback(change);
}
request.watchCallback(response);
};
const wsReq = {
method: "watch",
});
if (r.status !== 200) {
throw new Error("Watch request failed!");
}
return r.requestId[0];
}
async unwatch(requestId) {
return await this._ws.request({
path: "",
headers: {
authorization: "Bearer " + this._token,
authorization: "",
},
path: request.path,
};
return await this._ws.request(wsReq, callback);
method: "unwatch",
requestId: requestId,
});
}

@@ -92,4 +113,4 @@ async _recursiveGet(path, subTree, data) {

if (subTree["*"]) {
children = Object.keys(data || {}).reduce((acc, key) => {
if (typeof data[key] == "object") {
children = Object.keys(data).reduce((acc, key) => {
if (data && typeof data[key] == "object") {
acc.push({ treeKey: "*", dataKey: key });

@@ -102,3 +123,3 @@ }

children = Object.keys(subTree || {}).reduce((acc, key) => {
if (typeof data[key] == "object") {
if (data && typeof data[key] == "object") {
acc.push({ treeKey: key, dataKey: key });

@@ -111,2 +132,5 @@ }

const childPath = path + "/" + item.dataKey;
if (!data) {
return;
}
const res = await this._recursiveGet(childPath, subTree[item.treeKey], data[item.dataKey]);

@@ -121,8 +145,5 @@ data[item.dataKey] = res;

async put(request) {
if (!this._ws || !this._ws.isConnected()) {
throw new Error("Not connected.");
}
const pathArray = utils.toArrayPath(request.path);
if (request.tree) {
let linkObj;
let linkObj = null;
let newResourcePathArray = [];

@@ -161,13 +182,10 @@ for (let i = pathArray.length - 1; i >= 0; i--) {

let contentType = request.contentType ||
request.data["_type"] ||
(request.data && request.data["_type"]) ||
(request.tree
? utils.getObjectAtPath(request.tree, pathArray)["_type"]
: undefined);
if (!contentType) {
throw new Error("Content type is not specified.");
}
: "application/json");
return this._ws.request({
method: "put",
headers: {
authorization: "Bearer " + this._token,
authorization: `Bearer ${this._token}`,
"content-type": contentType,

@@ -179,10 +197,29 @@ },

}
async head(request) {
if (!this._ws || !this._ws.isConnected()) {
throw new Error("Not connected.");
async post(request) {
const pathArray = utils.toArrayPath(request.path);
const data = request.data;
if (request.tree) {
request.data = {};
await this.put(request);
}
let contentType = request.contentType ||
(request.data && request.data["_type"]) ||
(request.tree
? utils.getObjectAtPath(request.tree, pathArray)["_type"]
: "application/json");
return this._ws.request({
method: "post",
headers: {
authorization: `Bearer ${this._token}`,
"content-type": contentType,
},
path: request.path,
data,
});
}
async head(request) {
return this._ws.request({
method: "head",
headers: {
authorization: "Bearer " + this._token,
authorization: `Bearer ${this._token}`,
},

@@ -193,9 +230,6 @@ path: request.path,

async delete(request) {
if (!this._ws || !this._ws.isConnected()) {
throw new Error("Not connected.");
}
return this._ws.request({
method: "delete",
headers: {
authorization: "Bearer " + this._token,
authorization: `Bearer ${this._token}`,
},

@@ -207,6 +241,5 @@ path: request.path,

const resourceId = "resources/" + ksuid_1.default.randomSync().string;
const fullData = Object.assign({ _id: resourceId, _type: contentType }, data);
const putResponse = await this.put({
await this.put({
path: "/" + resourceId,
data: fullData,
data,
contentType,

@@ -217,3 +250,5 @@ });

async _resourceExists(path) {
const headResponse = await this.head({ path }).catch((msg) => {
const headResponse = await this.head({
path,
}).catch((msg) => {
if (msg.status == 404) {

@@ -223,3 +258,3 @@ return msg;

else {
throw new Error("Error");
throw new Error(`Error: ${msg.statusText}`);
}

@@ -226,0 +261,0 @@ });

import { OADAClient, Config } from "./client";
export declare function createInstance(): OADAClient;
export declare function createInstance(config: Config): OADAClient;
export declare function connect(config: Config): Promise<OADAClient>;
export { OADAClient, Config, GETRequest, PUTRequest, HEADRequest, WatchRequest } from "./client";
export { OADAClient, Config, GETRequest, PUTRequest, HEADRequest, WatchRequest, } from "./client";
export declare type Json = null | boolean | number | string | Json[] | {
[prop: string]: Json;
};
export declare type JsonCompatible<T> = {
[P in keyof T]: T[P] extends Json ? T[P] : Pick<T, P> extends Required<Pick<T, P>> ? never : T[P] extends (() => unknown) | undefined ? never : JsonCompatible<T[P]>;
};
export interface Change {
type: "merge" | "delete";
body: Json;
path: string;
resource_id: string;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const client_1 = require("./client");
function createInstance() {
return new client_1.OADAClient();
function createInstance(config) {
return new client_1.OADAClient(config);
}
exports.createInstance = createInstance;
async function connect(config) {
const instance = createInstance();
await instance.connect(config);
return Promise.resolve(instance);
return new client_1.OADAClient(config);
}

@@ -13,0 +11,0 @@ exports.connect = connect;

@@ -1,15 +0,22 @@

export interface Request {
method: string;
headers: {
[key: string]: string;
};
import { Json, Change } from ".";
export interface SocketRequest {
requestId?: string;
path: string;
data?: object;
requestId?: string;
method: "head" | "get" | "put" | "post" | "delete" | "watch" | "unwatch";
headers: Record<string, string>;
data?: Json;
}
export interface Response {
headers: object;
export interface SocketResponse {
requestId: string | Array<string>;
status: number;
data: object;
statusText: string;
headers: Record<string, string>;
data: Json;
}
export interface SocketChange {
requestId: Array<string>;
resourceId: string;
path_leftover: string | Array<string>;
change: Array<Change>;
}
export declare class WebSocketClient {

@@ -20,8 +27,9 @@ private _ws;

private _requests;
constructor(domain: string);
connect(): Promise<void>;
disconnect(): void;
private _q;
constructor(domain: string, concurrency?: number);
disconnect(): Promise<void>;
isConnected(): boolean;
request(req: Request, callback?: (response: Response) => void): Promise<Response>;
request(req: SocketRequest, callback?: (response: Readonly<SocketChange>) => void): Promise<SocketResponse>;
private doRequest;
private _receive;
}
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -8,31 +19,38 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

const ksuid_1 = __importDefault(require("ksuid"));
const p_queue_1 = __importDefault(require("p-queue"));
const debug_1 = __importDefault(require("debug"));
const trace = debug_1.default("@oada/client:ws:trace");
const error = debug_1.default("@oada/client:ws:error");
const request_1 = require("@oada/types/oada/websockets/request");
const response_1 = require("@oada/types/oada/websockets/response");
const change_1 = require("@oada/types/oada/websockets/change");
const v2_1 = require("@oada/types/oada/change/v2");
class WebSocketClient {
constructor(domain) {
constructor(domain, concurrency = 10) {
this._connected = false;
this._domain = domain;
this._requests = new Map();
}
connect() {
if (this._connected) {
throw new Error("Already connected to server.");
}
return new Promise((resolve, reject) => {
this._ws = new WebSocket("wss://" + this._domain, {
this._ws = new Promise((resolve) => {
const ws = new WebSocket("wss://" + this._domain, {
origin: "https://" + this._domain,
});
this._ws.onopen = (e) => {
ws.onopen = () => {
this._connected = true;
resolve();
resolve(ws);
};
this._ws.onclose = () => {
ws.onclose = () => {
this._connected = false;
};
this._ws.onmessage = this._receive.bind(this);
ws.onmessage = this._receive.bind(this);
});
this._q = new p_queue_1.default({ concurrency });
this._q.on("active", () => {
trace(`WS Queue. Size: ${this._q.size} pending: ${this._q.pending}`);
});
}
disconnect() {
async disconnect() {
if (!this._connected) {
return;
}
this._ws.close();
(await this._ws).close();
}

@@ -43,11 +61,9 @@ isConnected() {

request(req, callback) {
if (!this._connected) {
throw new Error("Not connected to server.");
}
if (req.requestId) {
throw new Error("Request ID exists.");
}
const requestId = ksuid_1.default.randomSync().string;
return this._q.add(() => this.doRequest(req, callback));
}
async doRequest(req, callback) {
const requestId = req.requestId || ksuid_1.default.randomSync().string;
req.requestId = requestId;
this._ws.send(JSON.stringify(req));
request_1.assert(req);
(await this._ws).send(JSON.stringify(req));
return new Promise((resolve, reject) => {

@@ -63,33 +79,55 @@ this._requests.set(requestId, {

}
_receive(e) {
let msg = JSON.parse(e.data);
if (!msg.requestId) {
return;
}
let request = this._requests.get(msg.requestId);
if (request) {
if (!request.settled) {
request.settled = true;
if (msg.status && msg.status == "success") {
msg.status = 200;
_receive(m) {
try {
const msg = JSON.parse(m.data.toString());
let requestIds;
if (Array.isArray(msg.requestId)) {
requestIds = msg.requestId;
}
else {
requestIds = [msg.requestId];
}
for (const requestId of requestIds) {
let request = this._requests.get(requestId);
if (request) {
if (response_1.is(msg)) {
if (!request.callback) {
this._requests.delete(requestId);
}
if (!request.settled) {
request.settled = true;
if (msg.status && msg.status >= 200 && msg.status < 300) {
request.resolve(msg);
}
else if (msg.status) {
request.reject(msg);
}
else {
throw new Error("Request failed");
}
}
}
else if (request.callback && change_1.is(msg)) {
v2_1.assert(msg.change);
const m = {
requestId: msg.requestId,
resourceId: msg.resourceId,
path_leftover: msg.path_leftover,
change: msg.change.map((_a) => {
var { body } = _a, rest = __rest(_a, ["body"]);
return Object.assign(Object.assign({}, rest), { body: body });
}),
};
request.callback(m);
}
else {
throw new Error("Invalid websocket payload received");
}
}
if (msg.status && msg.status >= 200 && msg.status < 300) {
const response = {
headers: msg.headers,
status: msg.status,
data: msg.data,
};
request.resolve(response);
}
else if (msg.status) {
request.reject(msg);
}
else {
throw new Error("Request failed");
}
}
if (request.callback) {
request.callback(msg);
}
}
catch (e) {
error(`[Websocket ${this._domain}] Received invalid response. Ignoring.`);
trace(`[Websocket ${this._domain}] Received invalid response. %O`, e);
}
}

@@ -96,0 +134,0 @@ }

{
"name": "@oada/client",
"version": "0.0.3",
"version": "1.0.0",
"description": "A lightweight client tool to interact with an OADA-compliant server",

@@ -18,6 +18,9 @@ "main": "dist/index.js",

"author": "",
"license": "ISC",
"license": "Apache-2.0",
"dependencies": {
"@oada/types": "^1.0.6",
"debug": "^4.1.1",
"isomorphic-ws": "^4.0.1",
"ksuid": "^1.2.0",
"p-queue": "^6.4.0",
"ws": "^7.2.3"

@@ -27,5 +30,7 @@ },

"@types/chai": "^4.2.11",
"@types/debug": "^4.1.5",
"@types/mocha": "^7.0.2",
"@types/node": "^13.13.4",
"@types/uuid": "^7.0.2",
"@types/ws": "^7.2.4",
"chai": "^4.2.0",

@@ -32,0 +37,0 @@ "mocha": "^7.1.1",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc