From 407d9c0abe10b0e453ec2d2d17bf274febc8db46 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Thu, 7 Mar 2024 12:57:13 -0500 Subject: [PATCH 01/20] personal key auth draft --- projects/js-upload-api/src/AbstractClient.ts | 164 +++++++++++++++ projects/js-upload-api/src/Client.ts | 121 ++--------- projects/js-upload-api/src/ClientPkey.ts | 208 +++++++++++++++++++ projects/js-upload-api/src/index.ts | 1 + 4 files changed, 387 insertions(+), 107 deletions(-) create mode 100644 projects/js-upload-api/src/AbstractClient.ts create mode 100644 projects/js-upload-api/src/ClientPkey.ts diff --git a/projects/js-upload-api/src/AbstractClient.ts b/projects/js-upload-api/src/AbstractClient.ts new file mode 100644 index 0000000..5c0fe81 --- /dev/null +++ b/projects/js-upload-api/src/AbstractClient.ts @@ -0,0 +1,164 @@ +export abstract class AbstractClient { + public readonly protocol: string; + public readonly host: string; + public readonly clientProtocolHostname: string; + public readonly agent: string; + public readonly version?: string; + public readonly org?: string; + + + protected _getAuthTokenPromise?: Promise; // undefined if not configured + + protected _token?: string; + + protected fetch: any; // eslint-disable-line @typescript-eslint/no-explicit-any + + /** + * @param org The organization to use (optional) + * @param protocol The protocol to use for the server during uploads: 'http' or 'https'. + * @param host The hostname of the server during uploads: defaults to 'hub.graphistry.com' + * @param clientProtocolHostname Base path to use inside the browser and when sharing public URLs: defaults to '{protocol}://{host}' + * @param fetch The fetch implementation to use + * @param version The version of the client library + * @param agent The agent name to use when communicating with the server + */ + constructor ( + org?: string, + protocol = 'https', host = 'hub.graphistry.com', + clientProtocolHostname?: string, + fetchFn: any = fetch, + version?: string, + agent = '@graphistry/js-upload-api', + ) { + this.org = org; + this.protocol = protocol; + this.host = host; + this.fetch = fetchFn; + this.version = version; + this.agent = agent; + this.clientProtocolHostname = clientProtocolHostname || `${protocol}://${host}`; + } + + /** + * + * See examples at top of file + * + * Set JWT token if already known + * + * @param token The token to use for authentication. + * @returns The client instance. + */ + public setToken(token: string) { + this._token = token; + return this; + } + + /** + * + * @returns Whether the current token is valid + * + */ + public authTokenValid(): boolean { + const out = !!this._token; + return out; + } + + /** + * @internal + * Internal helper + * @param uri The URI to upload to. + * @param payload The payload to upload. + * @param baseHeaders Optionally override base header object to mix with auth header for the upload. + * @returns The response from the server. + */ + public async post(uri: string, payload: any, baseHeaders: any = undefined): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any + console.debug('post', {uri, payload}); + const headers = await this.getSecureHeaders(baseHeaders); + console.debug('post', {headers}); + const response = await this.postToApi(uri, payload, headers); + console.debug('post response', {uri, payload, response}); + return response; + } + + public static isConfigurationValid(username: string, password: string, host: string): boolean { + console.debug('isConfigurationValid', {username: username, password: password, host: host}); + return (username || '') !== '' && (password || '') !== '' && (host || '') !== ''; + } + + protected async getToApi(url: string, headers: any, baseUrl?: string) { + const resolvedFetch = this.fetch; + console.debug('getToApi', {url, headers}); + const response = await resolvedFetch((baseUrl ?? this.getBaseUrl()) + url, { + method: 'GET', + headers, + }); + console.debug('getToApi', {url, headers}); + return await response.json(); + } + + protected async postToApi(url: string, data: any, headers: any, baseUrl?: string): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any + const resolvedFetch = this.fetch; + console.debug('postToApi', {url, data, headers}); + const response = await resolvedFetch((baseUrl ?? this.getBaseUrl()) + url, { // change this + method: 'POST', + headers, + body: + //TypedArray + ArrayBuffer.isView(data) && !(data instanceof DataView) ? data + : JSON.stringify(data), + }) + console.debug('postToApi', {url, data, headers, response}); + return await response.json(); + } + + protected getBaseHeaders(): any { // eslint-disable-line @typescript-eslint/no-explicit-any + return ({ + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }); + } + + protected getBaseUrl(): string { + return `${this.protocol}://${this.host}/`; + } + + private async getSecureHeaders(baseHeaders: any = undefined): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any + const headers = baseHeaders || this.getBaseHeaders(); + const tok = await this.getAuthToken(); + console.debug('getSecureHeaders', {headers, tok}); + headers.Authorization = `Bearer ${tok}`; + console.debug('getSecureHeaders', {headers}); + return headers; + } + + public abstract isServerConfigured(): boolean; + + public abstract checkStale(username: string, password: string, protocol: string, host: string, clientProtocolHostname?: string): boolean; + + /** + * Get the authentication token for the current user. + * By default, reuses current token if available. + * + * @param force If true, forces a new token to be generated; defaults to false + * + * @returns The authentication token + * + */ + protected abstract getAuthToken(): Promise; + + /** + * + * @param username + * @param password + * @param org + * @param protocol + * @param host + * @returns Promise for the authentication token + * + * Helper to fetch a token for a given user + * + */ + public abstract fetchToken( + username: string, password: string, org?: string, protocol?: string, host?: string + ): Promise +} \ No newline at end of file diff --git a/projects/js-upload-api/src/Client.ts b/projects/js-upload-api/src/Client.ts index 1070db8..562e55d 100644 --- a/projects/js-upload-api/src/Client.ts +++ b/projects/js-upload-api/src/Client.ts @@ -1,3 +1,8 @@ +import { AbstractClient } from './AbstractClient.js'; + + +const AUTH_API_ENDPOINT = 'api/v2/auth/token/generate'; + /** * # Client examples * @@ -64,24 +69,13 @@ * import { Client } from '@graphistry/node-api'; * const client = new Client(); * client.setToken('Bearer 123abc'); + * ``` */ -export class Client { + +export class Client extends AbstractClient { public readonly username: string; private _password: string; - public readonly protocol: string; - public readonly host: string; - public readonly clientProtocolHostname: string; - public readonly agent: string; - public readonly version?: string; - public readonly org?: string; - - - private _getAuthTokenPromise?: Promise; // undefined if not configured - - private _token?: string; - - private fetch: any; // eslint-disable-line @typescript-eslint/no-explicit-any /** * @@ -105,53 +99,16 @@ export class Client { version?: string, agent = '@graphistry/js-upload-api', ) { + super(org, protocol, host, clientProtocolHostname, fetch, version, agent); + this.username = username; this._password = password; - this.org = org; - this.protocol = protocol; - this.host = host; - this.fetch = fetch; - this.version = version; - this.agent = agent; - this.clientProtocolHostname = clientProtocolHostname || `${protocol}://${host}`; + if (this.isServerConfigured()) { this._getAuthTokenPromise = this.getAuthToken(); } } - /** - * - * See examples at top of file - * - * Set JWT token if already known - * - * @param token The token to use for authentication. - * @returns The client instance. - */ - public setToken(token: string) { - this._token = token; - return this; - } - - /** - * @internal - * Internal helper - * @param uri The URI to upload to. - * @param payload The payload to upload. - * @param baseHeaders Optionally override base header object to mix with auth header for the upload. - * @returns The response from the server. - */ - public async post(uri: string, payload: any, baseHeaders: any = undefined): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any - console.debug('post', {uri, payload}); - const headers = await this.getSecureHeaders(baseHeaders); - console.debug('post', {headers}); - const response = await this.postToApi(uri, payload, headers); - console.debug('post response', {uri, payload, response}); - return response; - } - - - public isServerConfigured(): boolean { console.debug('isServerConfigured', {username: this.username, _password: this._password, host: this.host}); return (this.username || '') !== '' && (this._password || '') !== '' && (this.host || '') !== ''; @@ -181,11 +138,6 @@ export class Client { return false; } - public static isConfigurationValid(username: string, password: string, host: string): boolean { - console.debug('isConfigurationValid', {username: username, password: password, host: host}); - return (username || '') !== '' && (password || '') !== '' && (host || '') !== ''; - } - /** * Get the authentication token for the current user. * By default, reuses current token if available. @@ -195,7 +147,7 @@ export class Client { * @returns The authentication token * */ - private async getAuthToken(force = false): Promise { + protected async getAuthToken(force = false): Promise { if (!force && this.authTokenValid()) { return this._token || ''; // workaround ts not recognizing that _token is set } @@ -214,7 +166,7 @@ export class Client { console.debug('getAuthToken', {username: this.username, _password: this._password, host: this.host}); const response = await this.postToApi( - 'api/v2/auth/token/generate', + AUTH_API_ENDPOINT, { username: this.username, password: this._password, @@ -250,7 +202,7 @@ export class Client { username: string, password: string, org?: string, protocol = 'https', host = 'hub.graphistry.com' ): Promise { return (await this.postToApi( - 'api/v2/auth/token/generate', + AUTH_API_ENDPOINT, { username: username, password: password, @@ -260,49 +212,4 @@ export class Client { `${protocol}://${host}/` )).token; } - - /** - * - * @returns Whether the current token is valid - * - */ - public authTokenValid(): boolean { - const out = !!this._token; - return out; - } - - private async postToApi(url: string, data: any, headers: any, baseUrl?: string): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any - const resolvedFetch = this.fetch; - console.debug('postToApi', {url, data, headers}); - const response = await resolvedFetch((baseUrl ?? this.getBaseUrl()) + url, { // change this - method: 'POST', - headers, - body: - //TypedArray - ArrayBuffer.isView(data) && !(data instanceof DataView) ? data - : JSON.stringify(data), - }) - console.debug('postToApi', {url, data, headers, response}); - return await response.json(); - } - - private getBaseHeaders(): any { // eslint-disable-line @typescript-eslint/no-explicit-any - return ({ - 'Accept': 'application/json', - 'Content-Type': 'application/json', - }); - } - - private async getSecureHeaders(baseHeaders: any = undefined): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any - const headers = baseHeaders || this.getBaseHeaders(); - const tok = await this.getAuthToken(); - console.debug('getSecureHeaders', {headers, tok}); - headers.Authorization = `Bearer ${tok}`; - console.debug('getSecureHeaders', {headers}); - return headers; - } - - private getBaseUrl(): string { - return `${this.protocol}://${this.host}/`; - } } \ No newline at end of file diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPkey.ts new file mode 100644 index 0000000..c008c78 --- /dev/null +++ b/projects/js-upload-api/src/ClientPkey.ts @@ -0,0 +1,208 @@ +import { AbstractClient } from './AbstractClient.js'; + +const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; + +/** + * # Client examples + * + * Authenticate against a Graphistry server and manage communications with it. + * + * Different authentication modes may be desirable depending on the type of Graphistry server. + * + *
+ * + * --- + * + *
+ * + * @example **Authenticate against Graphistry Hub for a personal account** + * ```javascript + * import { Client } from '@graphistry/node-api'; + * const client = new Client('my_username', 'my_password'); + * ``` + * + *
+ * + * @example **Authenticate against an org in Graphistry Hub** + * ```javascript + * import { Client } from '@graphistry/node-api'; + * const client = new Client('my_username', 'my_password', 'my_org'); + * ``` + * + *
+ * + * @example **Authenticate against a private Graphistry server** + * ```javascript + * import { Client } from '@graphistry/node-api'; + * const client = new Client('my_username', 'my_password', 'http', 'my-ec2.aws.com:8080'); + * ``` + * + *
+ * +* @example **Upload via internal IP but publish urls via a public domain** + * ```javascript + * import { Client } from '@graphistry/node-api'; + * const client = new Client( + * 'my_username', 'my_password', + * 'http', '10.20.0.1:8080', + * 'https://www.my-site.com' + * ); + * ``` + * + *
+ * + * @example **Upload through the local docker network but publish urls via a public domain** + * ```javascript + * import { Client } from '@graphistry/node-api'; + * const client = new Client( + * 'my_username', 'my_password', + * 'http', 'nginx', + * 'https://www.my-site.com' + * ); + * ``` + * + *
+ * + * @example **Create a client with an externally-provided JWT token** + * ```javascript + * import { Client } from '@graphistry/node-api'; + * const client = new Client(); + * client.setToken('Bearer 123abc'); + * ``` + */ + +export class ClientPkey extends AbstractClient { + + public readonly personalKeyId: string; + private _personalKeySecret: string; + + /** + * + * See examples at top of file + * + * @param personalKeyId The personal key id to authenticate with. + * @param personalKeySecret The personal key secret to authenticate with. + * @param org The organization to use (optional) + * @param protocol The protocol to use for the server during uploads: 'http' or 'https'. + * @param host The hostname of the server during uploads: defaults to 'hub.graphistry.com' + * @param clientProtocolHostname Base path to use inside the browser and when sharing public URLs: defaults to '{protocol}://{host}' + * @param fetch The fetch implementation to use + * @param version The version of the client library + * @param agent The agent name to use when communicating with the server + */ + constructor ( + personalKeyId: string, personalKeySecret: string, org?: string, + protocol = 'https', host = 'hub.graphistry.com', + clientProtocolHostname?: string, + fetch?: any, // eslint-disable-line @typescript-eslint/no-explicit-any + version?: string, + agent = '@graphistry/js-upload-api', + ) { + super(org, protocol, host, clientProtocolHostname, fetch, version, agent); + + this.personalKeyId = personalKeyId; + this._personalKeySecret = personalKeySecret; + + if (this.isServerConfigured()) { + this._getAuthTokenPromise = this.getAuthToken(); + } + } + + public isServerConfigured(): boolean { + console.debug('isServerConfigured', {personalKeyId: this.personalKeyId, _personalKeySecret: this._personalKeySecret, host: this.host}); + return (this.personalKeyId || '') !== '' && (this._personalKeySecret || '') !== '' && (this.host || '') !== ''; + } + + public checkStale(personalKeyId: string, personalKeySecret: string, protocol: string, host: string, clientProtocolHostname?: string): boolean { + if (this.personalKeyId !== personalKeyId) { + console.debug('personalKeyId changed', {currentPersonalKeyId: this.personalKeyId, newPersonalKeyId: personalKeyId}, this); + return true; + } + if (this._personalKeySecret !== personalKeySecret) { + console.debug('personalKeySecret changed', {currentPersonalKeySecret: this._personalKeySecret, newPersonalKeySecret: personalKeySecret}, this); + return true; + } + if (this.protocol !== protocol) { + console.debug('protocol changed', {currentProtocol: this.protocol, newProtocol: protocol}, this); + return true; + } + if (this.host !== host) { + console.debug('host changed', {currentHost: this.host, newHost: host}, this); + return true; + } + if (this.clientProtocolHostname !== clientProtocolHostname) { + console.debug('clientProtocolHostname changed', {currentClientProtocolHostname: this.clientProtocolHostname, newClientProtocolHostname: clientProtocolHostname}, this); + return true; + } + return false; + } + + /** + * Get the authentication token for the current user. + * By default, reuses current token if available. + * + * @param force If true, forces a new token to be generated; defaults to false + * + * @returns The authentication token + * + */ + protected async getAuthToken(force = false): Promise { + if (!force && this.authTokenValid()) { + return this._token || ''; // workaround ts not recognizing that _token is set + } + + //Throw exception if invalid personalKeyId or personalKeySecret + if (!this.isServerConfigured()) { + console.debug('current config', {personalKeyId: this.personalKeyId, _personalKeySecret: this._personalKeySecret, host: this.host}); + throw new Error('Invalid personalKeyId or personalKeySecret'); + } + + if (!force && this._getAuthTokenPromise) { + console.debug('reusing outstanding auth promise'); + return await this._getAuthTokenPromise; + } + + console.debug('getAuthToken', {personalKeyId: this.personalKeyId, personalKeySecret: this._personalKeySecret, host: this.host}); + + const response = await this.getToApi( + AUTH_API_ENDPOINT, + { + "Authorization": `PersonalKey ${this.personalKeyId}:${this._personalKeySecret}`, + }, + ) + + const tok : string = response.token; + this._token = tok; + + if (!this.authTokenValid()) { + console.error('auth token failure', {response, personalKeyId: this.personalKeyId, host: this.host}); + throw new Error({'error': 'Auth token failure', ...(response||{})}); + } + + return tok; + } + + /** + * + * @param personalKeyId + * @param password + * @param org + * @param protocol + * @param host + * @returns Promise for the authentication token + * + * Helper to fetch a token for a given user + * + */ + public async fetchToken( + personalKeyId: string, personalKeySecret: string, org?: string, protocol = 'https', host = 'hub.graphistry.com' + ): Promise { + return (await this.getToApi( + AUTH_API_ENDPOINT, + { + "Authorization": `PersonalKey ${personalKeyId}:${personalKeySecret}`, + }, + `${protocol}://${host}/` + )).token; + } +} \ No newline at end of file diff --git a/projects/js-upload-api/src/index.ts b/projects/js-upload-api/src/index.ts index dec99b8..82527aa 100644 --- a/projects/js-upload-api/src/index.ts +++ b/projects/js-upload-api/src/index.ts @@ -1,5 +1,6 @@ "use strict"; export { Client } from "./Client.js"; +export { ClientPkey } from "./ClientPkey.js"; export { FileType, File, EdgeFile, NodeFile } from "./File.js"; export { Dataset } from "./Dataset.js"; export { Privacy } from "./Privacy.js"; From 186dd2d73a608a1109e8d0094bb92e5b6b9ac27d Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Thu, 7 Mar 2024 13:09:40 -0500 Subject: [PATCH 02/20] update functions with Client as arg to accept Client and ClientPkey --- projects/js-upload-api/src/Dataset.ts | 9 +++++---- projects/js-upload-api/src/File.ts | 9 +++++---- projects/js-upload-api/src/Privacy.ts | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/projects/js-upload-api/src/Dataset.ts b/projects/js-upload-api/src/Dataset.ts index 789b8f4..bc3cca1 100644 --- a/projects/js-upload-api/src/Dataset.ts +++ b/projects/js-upload-api/src/Dataset.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Client } from './Client.js'; +import { ClientPkey } from './ClientPkey.js'; import { File, FileType, EdgeFile, NodeFile } from './File.js'; import { Mode, ModeAction, Privacy } from './Privacy.js'; @@ -297,7 +298,7 @@ export class Dataset { * @param client Client object * @returns Promise that resolves when the dataset is uploaded */ - public async upload(client: Client): Promise { + public async upload(client: Client | ClientPkey): Promise { if (!client) { throw new Error('No client provided'); @@ -341,7 +342,7 @@ export class Dataset { //////////////////////////////////////////////////////////////////////////////// - private async createDataset(client: Client, bindings: Record): Promise { + private async createDataset(client: Client | ClientPkey, bindings: Record): Promise { this.fillMetadata(bindings, client); const dataJsonResults = await client.post('api/v2/upload/datasets/', bindings); this._createDatasetResponse = dataJsonResults; @@ -389,7 +390,7 @@ export class Dataset { /////////////////////////////////////////////////////////////////////////////// - private fillMetadata(data: any, client: Client): void{ + private fillMetadata(data: any, client: Client | ClientPkey): void{ if (!data) { throw new Error('No data to fill metadata; call setData() first or provide to File constructor'); } @@ -432,7 +433,7 @@ export class Dataset { * @throws Error if server call fails */ public async privacy( - client: Client, + client: Client | ClientPkey, mode: Mode = 'private', modeAction?: ModeAction, invitedUsers: string[] = [], diff --git a/projects/js-upload-api/src/File.ts b/projects/js-upload-api/src/File.ts index cab880c..a78aaaf 100644 --- a/projects/js-upload-api/src/File.ts +++ b/projects/js-upload-api/src/File.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Client } from './Client.js'; +import { ClientPkey } from './ClientPkey.js'; /** @@ -209,7 +210,7 @@ export class File { * @param force If true, will force upload even if file has already been uploaded * @returns Promise that resolves to the uploaded File object when it completes uploading */ - public async upload(client : Client, force = false): Promise { + public async upload(client : Client | ClientPkey, force = false): Promise { if (!client) { throw new Error('No client provided'); } @@ -242,7 +243,7 @@ export class File { * @param force If true, will force creation of a new ID even if file has already been uploaded * @returns */ - public async createFile(client : Client, force = false): Promise { + public async createFile(client : Client | ClientPkey, force = false): Promise { if (!force && this._fileCreated) { console.debug('File already created, skipping'); return this._fileCreated; @@ -275,7 +276,7 @@ export class File { * @param force If true, will force upload even if file has already been uploaded * @returns */ - public async uploadData(client : Client, force = false): Promise { + public async uploadData(client : Client | ClientPkey, force = false): Promise { if (!force && this._fileUploaded) { return this._fileUploaded; } @@ -312,7 +313,7 @@ export class File { /////////////////////////////////////////////////////////////////////////////// - private fillMetadata(data: any, client: Client): void { + private fillMetadata(data: any, client: Client | ClientPkey): void { if (!data) { throw new Error('No data to fill metadata; call setData() first or provide to File constructor'); } diff --git a/projects/js-upload-api/src/Privacy.ts b/projects/js-upload-api/src/Privacy.ts index b7374ae..1c8a7f7 100644 --- a/projects/js-upload-api/src/Privacy.ts +++ b/projects/js-upload-api/src/Privacy.ts @@ -1,4 +1,5 @@ import { Client } from './Client.js'; +import { ClientPkey } from './ClientPkey.js'; /** @@ -144,7 +145,7 @@ export class Privacy { * @throws Error if the upload fails * */ - public async upload(client: Client): Promise { + public async upload(client: Client | ClientPkey): Promise { if (!client) { throw new Error('No client provided'); From 8ebea49c88e9279d975bbf4b50b752c47ecc3b91 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Thu, 7 Mar 2024 13:20:54 -0500 Subject: [PATCH 03/20] fix misnamed args --- projects/js-upload-api/src/AbstractClient.ts | 6 +++--- projects/js-upload-api/src/ClientPkey.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/js-upload-api/src/AbstractClient.ts b/projects/js-upload-api/src/AbstractClient.ts index 5c0fe81..85d5c73 100644 --- a/projects/js-upload-api/src/AbstractClient.ts +++ b/projects/js-upload-api/src/AbstractClient.ts @@ -148,8 +148,8 @@ export abstract class AbstractClient { /** * - * @param username - * @param password + * @param userId + * @param secret * @param org * @param protocol * @param host @@ -159,6 +159,6 @@ export abstract class AbstractClient { * */ public abstract fetchToken( - username: string, password: string, org?: string, protocol?: string, host?: string + userId: string, secret: string, org?: string, protocol?: string, host?: string ): Promise } \ No newline at end of file diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPkey.ts index c008c78..5396a14 100644 --- a/projects/js-upload-api/src/ClientPkey.ts +++ b/projects/js-upload-api/src/ClientPkey.ts @@ -185,7 +185,7 @@ export class ClientPkey extends AbstractClient { /** * * @param personalKeyId - * @param password + * @param personalKeySecret * @param org * @param protocol * @param host From 8d51cda893b7ace9175abb3c48a4ddd4873eec09 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Thu, 7 Mar 2024 14:57:53 -0500 Subject: [PATCH 04/20] code cleanup --- projects/js-upload-api/src/AbstractClient.ts | 27 ++++++++++---------- projects/js-upload-api/src/Client.ts | 6 ++--- projects/js-upload-api/src/ClientPkey.ts | 3 ++- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/projects/js-upload-api/src/AbstractClient.ts b/projects/js-upload-api/src/AbstractClient.ts index 85d5c73..2086738 100644 --- a/projects/js-upload-api/src/AbstractClient.ts +++ b/projects/js-upload-api/src/AbstractClient.ts @@ -18,7 +18,7 @@ export abstract class AbstractClient { * @param protocol The protocol to use for the server during uploads: 'http' or 'https'. * @param host The hostname of the server during uploads: defaults to 'hub.graphistry.com' * @param clientProtocolHostname Base path to use inside the browser and when sharing public URLs: defaults to '{protocol}://{host}' - * @param fetch The fetch implementation to use + * @param fetch The fetch implementation to use: defaults to JavaScript fetch function * @param version The version of the client library * @param agent The agent name to use when communicating with the server */ @@ -58,9 +58,8 @@ export abstract class AbstractClient { * @returns Whether the current token is valid * */ - public authTokenValid(): boolean { - const out = !!this._token; - return out; + public authTokenValid() { + return Boolean(this._token); } /** @@ -71,7 +70,7 @@ export abstract class AbstractClient { * @param baseHeaders Optionally override base header object to mix with auth header for the upload. * @returns The response from the server. */ - public async post(uri: string, payload: any, baseHeaders: any = undefined): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any + public async post(uri: string, payload: any, baseHeaders: any = undefined) { console.debug('post', {uri, payload}); const headers = await this.getSecureHeaders(baseHeaders); console.debug('post', {headers}); @@ -80,9 +79,9 @@ export abstract class AbstractClient { return response; } - public static isConfigurationValid(username: string, password: string, host: string): boolean { - console.debug('isConfigurationValid', {username: username, password: password, host: host}); - return (username || '') !== '' && (password || '') !== '' && (host || '') !== ''; + public static isConfigurationValid(userId: string, secret: string, host: string) { + console.debug('isConfigurationValid', {userId, secret, host: host}); + return (userId || '') !== '' && (secret || '') !== '' && (host || '') !== ''; } protected async getToApi(url: string, headers: any, baseUrl?: string) { @@ -96,7 +95,7 @@ export abstract class AbstractClient { return await response.json(); } - protected async postToApi(url: string, data: any, headers: any, baseUrl?: string): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any + protected async postToApi(url: string, data: any, headers: any, baseUrl?: string) { const resolvedFetch = this.fetch; console.debug('postToApi', {url, data, headers}); const response = await resolvedFetch((baseUrl ?? this.getBaseUrl()) + url, { // change this @@ -111,18 +110,18 @@ export abstract class AbstractClient { return await response.json(); } - protected getBaseHeaders(): any { // eslint-disable-line @typescript-eslint/no-explicit-any + protected getBaseHeaders() { return ({ 'Accept': 'application/json', 'Content-Type': 'application/json', }); } - protected getBaseUrl(): string { + protected getBaseUrl() { return `${this.protocol}://${this.host}/`; } - private async getSecureHeaders(baseHeaders: any = undefined): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any + private async getSecureHeaders(baseHeaders?: any) { const headers = baseHeaders || this.getBaseHeaders(); const tok = await this.getAuthToken(); console.debug('getSecureHeaders', {headers, tok}); @@ -133,7 +132,9 @@ export abstract class AbstractClient { public abstract isServerConfigured(): boolean; - public abstract checkStale(username: string, password: string, protocol: string, host: string, clientProtocolHostname?: string): boolean; + public abstract checkStale( + username: string, password: string, protocol: string, host: string, clientProtocolHostname?: string + ): boolean; /** * Get the authentication token for the current user. diff --git a/projects/js-upload-api/src/Client.ts b/projects/js-upload-api/src/Client.ts index 562e55d..82b9f1e 100644 --- a/projects/js-upload-api/src/Client.ts +++ b/projects/js-upload-api/src/Client.ts @@ -109,12 +109,12 @@ export class Client extends AbstractClient { } } - public isServerConfigured(): boolean { + public isServerConfigured() { console.debug('isServerConfigured', {username: this.username, _password: this._password, host: this.host}); return (this.username || '') !== '' && (this._password || '') !== '' && (this.host || '') !== ''; } - public checkStale(username: string, password: string, protocol: string, host: string, clientProtocolHostname?: string): boolean { + public checkStale(username: string, password: string, protocol: string, host: string, clientProtocolHostname?: string) { if (this.username !== username) { console.debug('username changed', {currentUsername: this.username, newUsername: username}, this); return true; @@ -147,7 +147,7 @@ export class Client extends AbstractClient { * @returns The authentication token * */ - protected async getAuthToken(force = false): Promise { + protected async getAuthToken(force = false) { if (!force && this.authTokenValid()) { return this._token || ''; // workaround ts not recognizing that _token is set } diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPkey.ts index 5396a14..3c8bb27 100644 --- a/projects/js-upload-api/src/ClientPkey.ts +++ b/projects/js-upload-api/src/ClientPkey.ts @@ -1,5 +1,6 @@ import { AbstractClient } from './AbstractClient.js'; + const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; /** @@ -94,7 +95,7 @@ export class ClientPkey extends AbstractClient { personalKeyId: string, personalKeySecret: string, org?: string, protocol = 'https', host = 'hub.graphistry.com', clientProtocolHostname?: string, - fetch?: any, // eslint-disable-line @typescript-eslint/no-explicit-any + fetch?: any, version?: string, agent = '@graphistry/js-upload-api', ) { From 0276ecbc4fdd8e3f71023447d4dcdb804a334aab Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Thu, 7 Mar 2024 17:06:53 -0500 Subject: [PATCH 05/20] update jsdocs --- projects/js-upload-api/src/Client.ts | 8 ++++---- projects/js-upload-api/src/ClientPkey.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/projects/js-upload-api/src/Client.ts b/projects/js-upload-api/src/Client.ts index 82b9f1e..700b00d 100644 --- a/projects/js-upload-api/src/Client.ts +++ b/projects/js-upload-api/src/Client.ts @@ -6,7 +6,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/token/generate'; /** * # Client examples * - * Authenticate against a Graphistry server and manage communications with it. + * Authenticate against a Graphistry server using a username and password, and manage communications with it. * * Different authentication modes may be desirable depending on the type of Graphistry server. * @@ -35,7 +35,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/token/generate'; * @example **Authenticate against a private Graphistry server** * ```javascript * import { Client } from '@graphistry/node-api'; - * const client = new Client('my_username', 'my_password', 'http', 'my-ec2.aws.com:8080'); + * const client = new Client('my_username', 'my_password', '', 'http', 'my-ec2.aws.com:8080'); * ``` * *
@@ -44,7 +44,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/token/generate'; * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client( - * 'my_username', 'my_password', + * 'my_username', 'my_password', '', * 'http', '10.20.0.1:8080', * 'https://www.my-site.com' * ); @@ -56,7 +56,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/token/generate'; * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client( - * 'my_username', 'my_password', + * 'my_username', 'my_password', '', * 'http', 'nginx', * 'https://www.my-site.com' * ); diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPkey.ts index 3c8bb27..5409cb6 100644 --- a/projects/js-upload-api/src/ClientPkey.ts +++ b/projects/js-upload-api/src/ClientPkey.ts @@ -6,7 +6,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; /** * # Client examples * - * Authenticate against a Graphistry server and manage communications with it. + * Authenticate against a Graphistry server using a personal key id and secret, and manage communications with it. * * Different authentication modes may be desirable depending on the type of Graphistry server. * @@ -19,7 +19,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; * @example **Authenticate against Graphistry Hub for a personal account** * ```javascript * import { Client } from '@graphistry/node-api'; - * const client = new Client('my_username', 'my_password'); + * const client = new Client('my_personal_key_id', 'my_personal_key_secret'); * ``` * *
@@ -27,7 +27,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; * @example **Authenticate against an org in Graphistry Hub** * ```javascript * import { Client } from '@graphistry/node-api'; - * const client = new Client('my_username', 'my_password', 'my_org'); + * const client = new Client('my_personal_key_id', 'my_personal_key_secret', 'my_org'); * ``` * *
@@ -35,7 +35,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; * @example **Authenticate against a private Graphistry server** * ```javascript * import { Client } from '@graphistry/node-api'; - * const client = new Client('my_username', 'my_password', 'http', 'my-ec2.aws.com:8080'); + * const client = new Client('my_personal_key_id', 'my_personal_key_secret', '', 'http', 'my-ec2.aws.com:8080'); * ``` * *
@@ -44,7 +44,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client( - * 'my_username', 'my_password', + * 'my_username', 'my_password', '', * 'http', '10.20.0.1:8080', * 'https://www.my-site.com' * ); @@ -56,7 +56,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client( - * 'my_username', 'my_password', + * 'my_username', 'my_password', '', * 'http', 'nginx', * 'https://www.my-site.com' * ); From b6c7d560bf87b34e147867a7634f3ba7d61c5ee5 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Fri, 8 Mar 2024 15:43:25 -0500 Subject: [PATCH 06/20] documentation fixes --- projects/js-upload-api/src/ClientPkey.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPkey.ts index 5409cb6..6431594 100644 --- a/projects/js-upload-api/src/ClientPkey.ts +++ b/projects/js-upload-api/src/ClientPkey.ts @@ -44,7 +44,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client( - * 'my_username', 'my_password', '', + * 'my_personal_key_id', 'my_personal_key_secret', '', * 'http', '10.20.0.1:8080', * 'https://www.my-site.com' * ); @@ -56,7 +56,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client( - * 'my_username', 'my_password', '', + * 'my_personal_key_id', 'my_personal_key_secret', '', * 'http', 'nginx', * 'https://www.my-site.com' * ); From 8ba16b6fb999c840ab56a33dff668bf5a27cfe65 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Fri, 8 Mar 2024 15:50:48 -0500 Subject: [PATCH 07/20] remove more redundant types --- projects/js-upload-api/src/ClientPkey.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPkey.ts index 6431594..ff0934f 100644 --- a/projects/js-upload-api/src/ClientPkey.ts +++ b/projects/js-upload-api/src/ClientPkey.ts @@ -109,12 +109,12 @@ export class ClientPkey extends AbstractClient { } } - public isServerConfigured(): boolean { + public isServerConfigured() { console.debug('isServerConfigured', {personalKeyId: this.personalKeyId, _personalKeySecret: this._personalKeySecret, host: this.host}); return (this.personalKeyId || '') !== '' && (this._personalKeySecret || '') !== '' && (this.host || '') !== ''; } - public checkStale(personalKeyId: string, personalKeySecret: string, protocol: string, host: string, clientProtocolHostname?: string): boolean { + public checkStale(personalKeyId: string, personalKeySecret: string, protocol: string, host: string, clientProtocolHostname?: string) { if (this.personalKeyId !== personalKeyId) { console.debug('personalKeyId changed', {currentPersonalKeyId: this.personalKeyId, newPersonalKeyId: personalKeyId}, this); return true; @@ -147,7 +147,7 @@ export class ClientPkey extends AbstractClient { * @returns The authentication token * */ - protected async getAuthToken(force = false): Promise { + protected async getAuthToken(force = false) { if (!force && this.authTokenValid()) { return this._token || ''; // workaround ts not recognizing that _token is set } From e576d6be5e192fc4698187f1b3d7693b622f197d Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Mon, 11 Mar 2024 10:29:34 -0400 Subject: [PATCH 08/20] org unused arg --- projects/js-upload-api/src/ClientPkey.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPkey.ts index ff0934f..150b7d8 100644 --- a/projects/js-upload-api/src/ClientPkey.ts +++ b/projects/js-upload-api/src/ClientPkey.ts @@ -196,7 +196,7 @@ export class ClientPkey extends AbstractClient { * */ public async fetchToken( - personalKeyId: string, personalKeySecret: string, org?: string, protocol = 'https', host = 'hub.graphistry.com' + personalKeyId: string, personalKeySecret: string, _org?: string, protocol = 'https', host = 'hub.graphistry.com' ): Promise { return (await this.getToApi( AUTH_API_ENDPOINT, From bbf5d48b320f65d44fa9ed8ed28da439acdcfd50 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Mon, 11 Mar 2024 10:30:31 -0400 Subject: [PATCH 09/20] change "Client | ClientPkey" types to "AbstractClient" --- projects/js-upload-api/src/Dataset.ts | 11 +++++------ projects/js-upload-api/src/File.ts | 11 +++++------ projects/js-upload-api/src/Privacy.ts | 5 ++--- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/projects/js-upload-api/src/Dataset.ts b/projects/js-upload-api/src/Dataset.ts index bc3cca1..9eef265 100644 --- a/projects/js-upload-api/src/Dataset.ts +++ b/projects/js-upload-api/src/Dataset.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Client } from './Client.js'; -import { ClientPkey } from './ClientPkey.js'; +import { AbstractClient } from './AbstractClient.js'; import { File, FileType, EdgeFile, NodeFile } from './File.js'; import { Mode, ModeAction, Privacy } from './Privacy.js'; @@ -298,7 +297,7 @@ export class Dataset { * @param client Client object * @returns Promise that resolves when the dataset is uploaded */ - public async upload(client: Client | ClientPkey): Promise { + public async upload(client: AbstractClient): Promise { if (!client) { throw new Error('No client provided'); @@ -342,7 +341,7 @@ export class Dataset { //////////////////////////////////////////////////////////////////////////////// - private async createDataset(client: Client | ClientPkey, bindings: Record): Promise { + private async createDataset(client: AbstractClient, bindings: Record): Promise { this.fillMetadata(bindings, client); const dataJsonResults = await client.post('api/v2/upload/datasets/', bindings); this._createDatasetResponse = dataJsonResults; @@ -390,7 +389,7 @@ export class Dataset { /////////////////////////////////////////////////////////////////////////////// - private fillMetadata(data: any, client: Client | ClientPkey): void{ + private fillMetadata(data: any, client: AbstractClient): void{ if (!data) { throw new Error('No data to fill metadata; call setData() first or provide to File constructor'); } @@ -433,7 +432,7 @@ export class Dataset { * @throws Error if server call fails */ public async privacy( - client: Client | ClientPkey, + client: AbstractClient, mode: Mode = 'private', modeAction?: ModeAction, invitedUsers: string[] = [], diff --git a/projects/js-upload-api/src/File.ts b/projects/js-upload-api/src/File.ts index a78aaaf..abd4804 100644 --- a/projects/js-upload-api/src/File.ts +++ b/projects/js-upload-api/src/File.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Client } from './Client.js'; -import { ClientPkey } from './ClientPkey.js'; +import { AbstractClient } from './AbstractClient.js'; /** @@ -210,7 +209,7 @@ export class File { * @param force If true, will force upload even if file has already been uploaded * @returns Promise that resolves to the uploaded File object when it completes uploading */ - public async upload(client : Client | ClientPkey, force = false): Promise { + public async upload(client : AbstractClient, force = false): Promise { if (!client) { throw new Error('No client provided'); } @@ -243,7 +242,7 @@ export class File { * @param force If true, will force creation of a new ID even if file has already been uploaded * @returns */ - public async createFile(client : Client | ClientPkey, force = false): Promise { + public async createFile(client : AbstractClient, force = false): Promise { if (!force && this._fileCreated) { console.debug('File already created, skipping'); return this._fileCreated; @@ -276,7 +275,7 @@ export class File { * @param force If true, will force upload even if file has already been uploaded * @returns */ - public async uploadData(client : Client | ClientPkey, force = false): Promise { + public async uploadData(client : AbstractClient, force = false): Promise { if (!force && this._fileUploaded) { return this._fileUploaded; } @@ -313,7 +312,7 @@ export class File { /////////////////////////////////////////////////////////////////////////////// - private fillMetadata(data: any, client: Client | ClientPkey): void { + private fillMetadata(data: any, client: AbstractClient): void { if (!data) { throw new Error('No data to fill metadata; call setData() first or provide to File constructor'); } diff --git a/projects/js-upload-api/src/Privacy.ts b/projects/js-upload-api/src/Privacy.ts index 1c8a7f7..56346a5 100644 --- a/projects/js-upload-api/src/Privacy.ts +++ b/projects/js-upload-api/src/Privacy.ts @@ -1,5 +1,4 @@ -import { Client } from './Client.js'; -import { ClientPkey } from './ClientPkey.js'; +import { AbstractClient } from './AbstractClient.js'; /** @@ -145,7 +144,7 @@ export class Privacy { * @throws Error if the upload fails * */ - public async upload(client: Client | ClientPkey): Promise { + public async upload(client: AbstractClient): Promise { if (!client) { throw new Error('No client provided'); From 04543eeb4d02758fb163c54dd40f2548d06712eb Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Mon, 11 Mar 2024 10:48:43 -0400 Subject: [PATCH 10/20] add client-api pkey export --- projects/client-api/src/index.js | 42 ++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/projects/client-api/src/index.js b/projects/client-api/src/index.js index fabcb5d..5a8728f 100644 --- a/projects/client-api/src/index.js +++ b/projects/client-api/src/index.js @@ -3,7 +3,7 @@ import shallowEqual from 'shallowequal'; import { Model } from '@graphistry/falcor-model-rxjs'; import { PostMessageDataSource } from '@graphistry/falcor-socket-datasource'; import { $ref, $atom, $value } from '@graphistry/falcor-json-graph'; -import { Client as ClientBase, Dataset as DatasetBase, File as FileBase, EdgeFile as EdgeFileBase, NodeFile as NodeFileBase } from '@graphistry/js-upload-api'; +import { Client as ClientBase, ClientPkey as ClientPkeyBase, Dataset as DatasetBase, File as FileBase, EdgeFile as EdgeFileBase, NodeFile as NodeFileBase } from '@graphistry/js-upload-api'; const CLIENT_SUBSCRIPTION_API_VERSION = 1; @@ -16,7 +16,7 @@ export const NodeFile = NodeFileBase; //FIXME not generating jsdoc /** - * Class wrapping @graphistry/js-upload-api::Client for client->server File and Dataset uploads. + * Class wrapping @graphistry/js-upload-api::Client for client->server File and Dataset uploads using username and password authentication. * @global * @extends ClientBase */ @@ -53,6 +53,44 @@ export class Client extends ClientBase { } } +/** + * Class wrapping @graphistry/js-upload-api::ClientPkey for client->server File and Dataset uploads using personal key authentication. + * @global + * @extends ClientPkeyBase + */ +export class ClientPkey extends ClientPkeyBase { + /** + * Create a Client + * @constructor + * @param {string} personalKeyId - Graphistry server personal key ID + * @param {string} personalKeySecret - Graphistry server personal key secret + * @param {string} org - Graphistry organization (optional) + * @param {string} [protocol='https'] - 'http' or 'https' for client->server upload communication + * @param {string} [host='hub.graphistry.com'] - Graphistry server hostname + * @param {clientProtocolHostname} clientProtocolHostname - Override URL base path shown in browsers. By default uses protocol/host combo, e.g., https://hub.graphistry.com + * + * For more examples, see @graphistry/node-api and @graphistry/js-upload-api docs + * + * @example **Authenticate against Graphistry Hub** + * ```javascript + * import { Client } from '@graphistry/client-api'; + * const client = new Client('my_personal_key_id', 'my_personal_key_secret'); + * ``` + */ + constructor( + personalKeyId, personalKeySecret, org = undefined, + protocol = 'https', host = 'hub.graphistry.com', + clientProtocolHostname, + version + ) { + console.debug('new client', { personalKeyId }, { personalKeySecret }, { protocol }, { host }, { clientProtocolHostname }, { version }); + super( + personalKeyId, personalKeySecret, org, + protocol, host, clientProtocolHostname, + window.fetch.bind(window), version, '@graphistry/client-api'); + } +} + import { ajax, catchError, From f7767fb71e48f7e983fd3d2836536ce420f8806d Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Mon, 11 Mar 2024 10:55:51 -0400 Subject: [PATCH 11/20] add client-api-react pkey export --- projects/client-api-react/src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/client-api-react/src/index.js b/projects/client-api-react/src/index.js index 55d7314..d402d3b 100644 --- a/projects/client-api-react/src/index.js +++ b/projects/client-api-react/src/index.js @@ -9,9 +9,10 @@ import * as gAPI from '@graphistry/client-api'; import { ajax, catchError, first, forkJoin, map, of, switchMap, tap } from '@graphistry/client-api'; // avoid explicit rxjs dep import { bg } from './bg'; import { bindings, panelNames, calls } from './bindings.js'; -import { Client as ClientBase, selectionUpdates, subscribeLabels } from '@graphistry/client-api'; +import { Client as ClientBase, ClientPkey as ClientPkeyBase, selectionUpdates, subscribeLabels } from '@graphistry/client-api'; export const Client = ClientBase; +export const ClientPkey = ClientPkeyBase; //https://blog.logrocket.com/how-to-get-previous-props-state-with-react-hooks/ function usePrevious(value) { From 6b52a2abef3854d1ab020cf8c85d569ad85bceb6 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Mon, 11 Mar 2024 11:01:09 -0400 Subject: [PATCH 12/20] add node-api pkey export --- projects/node-api/src/index.ts | 42 +++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/projects/node-api/src/index.ts b/projects/node-api/src/index.ts index ca0b8ca..3e864f2 100644 --- a/projects/node-api/src/index.ts +++ b/projects/node-api/src/index.ts @@ -1,4 +1,4 @@ -import { Client as ClientBase } from '@graphistry/js-upload-api'; +import { Client as ClientBase, ClientPkey as ClientPkeyBase } from '@graphistry/js-upload-api'; import { version as VERSION } from './version.js'; import fetch from 'node-fetch-commonjs'; @@ -50,3 +50,43 @@ export class Client extends ClientBase { '@graphistry/node-api'); } } + +/** + * Class wrapping @graphistry/js-upload-api::ClientPkey for client->server File and Dataset uploads using personal key authentication. + * @global + * @extends ClientPkeyBase + */ +export class ClientPkey extends ClientPkeyBase { + /** + * Create a Client + * @constructor + * @param {string} personalKeyId - Graphistry server personal key ID + * @param {string} personalKeySecret - Graphistry server personal key secret + * @param {string} org - Graphistry organization (optional) + * @param {string} [protocol='https'] - 'http' or 'https' for client->server upload communication + * @param {string} [host='hub.graphistry.com'] - Graphistry server hostname + * @param {clientProtocolHostname} clientProtocolHostname - Override URL base path shown in browsers. By default uses protocol/host combo, e.g., https://hub.graphistry.com + * + * For more examples, see @graphistry/node-api and @graphistry/js-upload-api docs + * + * @example **Authenticate against Graphistry Hub** + * ```javascript + * import { Client } from '@graphistry/client-api'; + * const client = new Client('my_personal_key_id', 'my_personal_key_secret'); + * ``` + */ + constructor( + personalKeyId: string, personalKeySecret: string, org?: string, + protocol = 'https', host = 'hub.graphistry.com', + clientProtocolHostname?: string, + version: string = VERSION + ) { + console.debug('new client', { personalKeyId }, { personalKeySecret }, { protocol }, { host }, { clientProtocolHostname }, { version }); + super( + personalKeyId, personalKeySecret, org, + protocol, host, clientProtocolHostname, + fetch, + version, + '@graphistry/node-api'); + } +} From f53717994599f032e7568c812abc7a11159c8782 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Mon, 11 Mar 2024 11:45:45 -0400 Subject: [PATCH 13/20] Revert "change "Client | ClientPkey" types to "AbstractClient"" This reverts commit bbf5d48b320f65d44fa9ed8ed28da439acdcfd50. --- projects/js-upload-api/src/Dataset.ts | 11 ++++++----- projects/js-upload-api/src/File.ts | 11 ++++++----- projects/js-upload-api/src/Privacy.ts | 5 +++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/projects/js-upload-api/src/Dataset.ts b/projects/js-upload-api/src/Dataset.ts index 9eef265..bc3cca1 100644 --- a/projects/js-upload-api/src/Dataset.ts +++ b/projects/js-upload-api/src/Dataset.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { AbstractClient } from './AbstractClient.js'; +import { Client } from './Client.js'; +import { ClientPkey } from './ClientPkey.js'; import { File, FileType, EdgeFile, NodeFile } from './File.js'; import { Mode, ModeAction, Privacy } from './Privacy.js'; @@ -297,7 +298,7 @@ export class Dataset { * @param client Client object * @returns Promise that resolves when the dataset is uploaded */ - public async upload(client: AbstractClient): Promise { + public async upload(client: Client | ClientPkey): Promise { if (!client) { throw new Error('No client provided'); @@ -341,7 +342,7 @@ export class Dataset { //////////////////////////////////////////////////////////////////////////////// - private async createDataset(client: AbstractClient, bindings: Record): Promise { + private async createDataset(client: Client | ClientPkey, bindings: Record): Promise { this.fillMetadata(bindings, client); const dataJsonResults = await client.post('api/v2/upload/datasets/', bindings); this._createDatasetResponse = dataJsonResults; @@ -389,7 +390,7 @@ export class Dataset { /////////////////////////////////////////////////////////////////////////////// - private fillMetadata(data: any, client: AbstractClient): void{ + private fillMetadata(data: any, client: Client | ClientPkey): void{ if (!data) { throw new Error('No data to fill metadata; call setData() first or provide to File constructor'); } @@ -432,7 +433,7 @@ export class Dataset { * @throws Error if server call fails */ public async privacy( - client: AbstractClient, + client: Client | ClientPkey, mode: Mode = 'private', modeAction?: ModeAction, invitedUsers: string[] = [], diff --git a/projects/js-upload-api/src/File.ts b/projects/js-upload-api/src/File.ts index abd4804..a78aaaf 100644 --- a/projects/js-upload-api/src/File.ts +++ b/projects/js-upload-api/src/File.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { AbstractClient } from './AbstractClient.js'; +import { Client } from './Client.js'; +import { ClientPkey } from './ClientPkey.js'; /** @@ -209,7 +210,7 @@ export class File { * @param force If true, will force upload even if file has already been uploaded * @returns Promise that resolves to the uploaded File object when it completes uploading */ - public async upload(client : AbstractClient, force = false): Promise { + public async upload(client : Client | ClientPkey, force = false): Promise { if (!client) { throw new Error('No client provided'); } @@ -242,7 +243,7 @@ export class File { * @param force If true, will force creation of a new ID even if file has already been uploaded * @returns */ - public async createFile(client : AbstractClient, force = false): Promise { + public async createFile(client : Client | ClientPkey, force = false): Promise { if (!force && this._fileCreated) { console.debug('File already created, skipping'); return this._fileCreated; @@ -275,7 +276,7 @@ export class File { * @param force If true, will force upload even if file has already been uploaded * @returns */ - public async uploadData(client : AbstractClient, force = false): Promise { + public async uploadData(client : Client | ClientPkey, force = false): Promise { if (!force && this._fileUploaded) { return this._fileUploaded; } @@ -312,7 +313,7 @@ export class File { /////////////////////////////////////////////////////////////////////////////// - private fillMetadata(data: any, client: AbstractClient): void { + private fillMetadata(data: any, client: Client | ClientPkey): void { if (!data) { throw new Error('No data to fill metadata; call setData() first or provide to File constructor'); } diff --git a/projects/js-upload-api/src/Privacy.ts b/projects/js-upload-api/src/Privacy.ts index 56346a5..1c8a7f7 100644 --- a/projects/js-upload-api/src/Privacy.ts +++ b/projects/js-upload-api/src/Privacy.ts @@ -1,4 +1,5 @@ -import { AbstractClient } from './AbstractClient.js'; +import { Client } from './Client.js'; +import { ClientPkey } from './ClientPkey.js'; /** @@ -144,7 +145,7 @@ export class Privacy { * @throws Error if the upload fails * */ - public async upload(client: AbstractClient): Promise { + public async upload(client: Client | ClientPkey): Promise { if (!client) { throw new Error('No client provided'); From 90391c5f77112e180ecd1dea50c19491e89c1815 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Mon, 11 Mar 2024 12:06:48 -0400 Subject: [PATCH 14/20] change "Client | ClientPkey" types to "ClientType" --- projects/js-upload-api/src/Dataset.ts | 11 +++++------ projects/js-upload-api/src/File.ts | 11 +++++------ projects/js-upload-api/src/Privacy.ts | 5 ++--- projects/js-upload-api/src/index.ts | 1 + projects/js-upload-api/src/types.ts | 14 ++++++++++++++ 5 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 projects/js-upload-api/src/types.ts diff --git a/projects/js-upload-api/src/Dataset.ts b/projects/js-upload-api/src/Dataset.ts index bc3cca1..51eca11 100644 --- a/projects/js-upload-api/src/Dataset.ts +++ b/projects/js-upload-api/src/Dataset.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Client } from './Client.js'; -import { ClientPkey } from './ClientPkey.js'; +import { ClientType } from './types.js'; import { File, FileType, EdgeFile, NodeFile } from './File.js'; import { Mode, ModeAction, Privacy } from './Privacy.js'; @@ -298,7 +297,7 @@ export class Dataset { * @param client Client object * @returns Promise that resolves when the dataset is uploaded */ - public async upload(client: Client | ClientPkey): Promise { + public async upload(client: ClientType): Promise { if (!client) { throw new Error('No client provided'); @@ -342,7 +341,7 @@ export class Dataset { //////////////////////////////////////////////////////////////////////////////// - private async createDataset(client: Client | ClientPkey, bindings: Record): Promise { + private async createDataset(client: ClientType, bindings: Record): Promise { this.fillMetadata(bindings, client); const dataJsonResults = await client.post('api/v2/upload/datasets/', bindings); this._createDatasetResponse = dataJsonResults; @@ -390,7 +389,7 @@ export class Dataset { /////////////////////////////////////////////////////////////////////////////// - private fillMetadata(data: any, client: Client | ClientPkey): void{ + private fillMetadata(data: any, client: ClientType): void{ if (!data) { throw new Error('No data to fill metadata; call setData() first or provide to File constructor'); } @@ -433,7 +432,7 @@ export class Dataset { * @throws Error if server call fails */ public async privacy( - client: Client | ClientPkey, + client: ClientType, mode: Mode = 'private', modeAction?: ModeAction, invitedUsers: string[] = [], diff --git a/projects/js-upload-api/src/File.ts b/projects/js-upload-api/src/File.ts index a78aaaf..a1983f6 100644 --- a/projects/js-upload-api/src/File.ts +++ b/projects/js-upload-api/src/File.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Client } from './Client.js'; -import { ClientPkey } from './ClientPkey.js'; +import { ClientType } from './types.js'; /** @@ -210,7 +209,7 @@ export class File { * @param force If true, will force upload even if file has already been uploaded * @returns Promise that resolves to the uploaded File object when it completes uploading */ - public async upload(client : Client | ClientPkey, force = false): Promise { + public async upload(client : ClientType, force = false): Promise { if (!client) { throw new Error('No client provided'); } @@ -243,7 +242,7 @@ export class File { * @param force If true, will force creation of a new ID even if file has already been uploaded * @returns */ - public async createFile(client : Client | ClientPkey, force = false): Promise { + public async createFile(client : ClientType, force = false): Promise { if (!force && this._fileCreated) { console.debug('File already created, skipping'); return this._fileCreated; @@ -276,7 +275,7 @@ export class File { * @param force If true, will force upload even if file has already been uploaded * @returns */ - public async uploadData(client : Client | ClientPkey, force = false): Promise { + public async uploadData(client : ClientType, force = false): Promise { if (!force && this._fileUploaded) { return this._fileUploaded; } @@ -313,7 +312,7 @@ export class File { /////////////////////////////////////////////////////////////////////////////// - private fillMetadata(data: any, client: Client | ClientPkey): void { + private fillMetadata(data: any, client: ClientType): void { if (!data) { throw new Error('No data to fill metadata; call setData() first or provide to File constructor'); } diff --git a/projects/js-upload-api/src/Privacy.ts b/projects/js-upload-api/src/Privacy.ts index 1c8a7f7..fe3479a 100644 --- a/projects/js-upload-api/src/Privacy.ts +++ b/projects/js-upload-api/src/Privacy.ts @@ -1,5 +1,4 @@ -import { Client } from './Client.js'; -import { ClientPkey } from './ClientPkey.js'; +import { ClientType } from './types.js'; /** @@ -145,7 +144,7 @@ export class Privacy { * @throws Error if the upload fails * */ - public async upload(client: Client | ClientPkey): Promise { + public async upload(client: ClientType): Promise { if (!client) { throw new Error('No client provided'); diff --git a/projects/js-upload-api/src/index.ts b/projects/js-upload-api/src/index.ts index 82527aa..284286c 100644 --- a/projects/js-upload-api/src/index.ts +++ b/projects/js-upload-api/src/index.ts @@ -1,6 +1,7 @@ "use strict"; export { Client } from "./Client.js"; export { ClientPkey } from "./ClientPkey.js"; +export { ClientType } from "./types.js"; export { FileType, File, EdgeFile, NodeFile } from "./File.js"; export { Dataset } from "./Dataset.js"; export { Privacy } from "./Privacy.js"; diff --git a/projects/js-upload-api/src/types.ts b/projects/js-upload-api/src/types.ts new file mode 100644 index 0000000..91558ea --- /dev/null +++ b/projects/js-upload-api/src/types.ts @@ -0,0 +1,14 @@ +import { Client } from "./Client.js"; +import { ClientPkey } from "./ClientPkey.js"; + +/** + * @internal + * + *
+ * + * ## ClientType + * + * A type including clients with all available authentication methods + * + */ +export type ClientType = Client | ClientPkey; \ No newline at end of file From 0d4c606735e557d89a1819f617921032471e9b88 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Wed, 13 Mar 2024 17:16:20 -0400 Subject: [PATCH 15/20] remove cred debug statements --- projects/client-api/src/index.js | 4 ++-- projects/node-api/src/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/client-api/src/index.js b/projects/client-api/src/index.js index 5a8728f..dbacd16 100644 --- a/projects/client-api/src/index.js +++ b/projects/client-api/src/index.js @@ -45,7 +45,7 @@ export class Client extends ClientBase { clientProtocolHostname, version ) { - console.debug('new client', { username }, { password }, { protocol }, { host }, { clientProtocolHostname }, { version }); + // console.debug('new client', { username }, { password }, { protocol }, { host }, { clientProtocolHostname }, { version }); super( username, password, org, protocol, host, clientProtocolHostname, @@ -83,7 +83,7 @@ export class ClientPkey extends ClientPkeyBase { clientProtocolHostname, version ) { - console.debug('new client', { personalKeyId }, { personalKeySecret }, { protocol }, { host }, { clientProtocolHostname }, { version }); + // console.debug('new client', { personalKeyId }, { personalKeySecret }, { protocol }, { host }, { clientProtocolHostname }, { version }); super( personalKeyId, personalKeySecret, org, protocol, host, clientProtocolHostname, diff --git a/projects/node-api/src/index.ts b/projects/node-api/src/index.ts index 3e864f2..fb4ed33 100644 --- a/projects/node-api/src/index.ts +++ b/projects/node-api/src/index.ts @@ -41,7 +41,7 @@ export class Client extends ClientBase { clientProtocolHostname?: string, version: string = VERSION ) { - console.debug('new client', { username }, { password }, { protocol }, { host }, { clientProtocolHostname }, { version }); + // console.debug('new client', { username }, { password }, { protocol }, { host }, { clientProtocolHostname }, { version }); super( username, password, org, protocol, host, clientProtocolHostname, @@ -81,7 +81,7 @@ export class ClientPkey extends ClientPkeyBase { clientProtocolHostname?: string, version: string = VERSION ) { - console.debug('new client', { personalKeyId }, { personalKeySecret }, { protocol }, { host }, { clientProtocolHostname }, { version }); + // console.debug('new client', { personalKeyId }, { personalKeySecret }, { protocol }, { host }, { clientProtocolHostname }, { version }); super( personalKeyId, personalKeySecret, org, protocol, host, clientProtocolHostname, From b9f2a6028143d234d96012ceaa97c81aee229d5f Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Thu, 14 Mar 2024 16:04:18 -0400 Subject: [PATCH 16/20] minor node-api README correction --- projects/node-api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/node-api/README.md b/projects/node-api/README.md index 55e56af..8479315 100644 --- a/projects/node-api/README.md +++ b/projects/node-api/README.md @@ -48,7 +48,7 @@ const dataset = new Dataset({ name: 'testdata', }, edgesFile, nodesFile); -await dataset.upload(); +await dataset.upload(client); console.info(`View at ${dataset.datasetID} at ${dataset.datasetURL}`); ``` From 9dc61318da12972ad9ce958c5cb4bd7f7cbb3b47 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Fri, 15 Mar 2024 11:20:02 -0400 Subject: [PATCH 17/20] use POST jwt endpoint to send org info --- projects/js-upload-api/src/AbstractClient.ts | 6 +-- projects/js-upload-api/src/Client.ts | 11 ++-- projects/js-upload-api/src/ClientPkey.ts | 55 +++++++++++++++++--- 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/projects/js-upload-api/src/AbstractClient.ts b/projects/js-upload-api/src/AbstractClient.ts index 2086738..81f6884 100644 --- a/projects/js-upload-api/src/AbstractClient.ts +++ b/projects/js-upload-api/src/AbstractClient.ts @@ -74,7 +74,7 @@ export abstract class AbstractClient { console.debug('post', {uri, payload}); const headers = await this.getSecureHeaders(baseHeaders); console.debug('post', {headers}); - const response = await this.postToApi(uri, payload, headers); + const response = await (await this.postToApi(uri, payload, headers)).json(); console.debug('post response', {uri, payload, response}); return response; } @@ -92,7 +92,7 @@ export abstract class AbstractClient { headers, }); console.debug('getToApi', {url, headers}); - return await response.json(); + return response; } protected async postToApi(url: string, data: any, headers: any, baseUrl?: string) { @@ -107,7 +107,7 @@ export abstract class AbstractClient { : JSON.stringify(data), }) console.debug('postToApi', {url, data, headers, response}); - return await response.json(); + return response; } protected getBaseHeaders() { diff --git a/projects/js-upload-api/src/Client.ts b/projects/js-upload-api/src/Client.ts index 700b00d..1756a9d 100644 --- a/projects/js-upload-api/src/Client.ts +++ b/projects/js-upload-api/src/Client.ts @@ -165,7 +165,7 @@ export class Client extends AbstractClient { console.debug('getAuthToken', {username: this.username, _password: this._password, host: this.host}); - const response = await this.postToApi( + let response = await this.postToApi( AUTH_API_ENDPOINT, { username: this.username, @@ -173,7 +173,8 @@ export class Client extends AbstractClient { ...(this.org ? {org_name: this.org} : {}), }, this.getBaseHeaders(), - ) + ); + response = await response.json(); const tok : string = response.token; this._token = tok; @@ -201,7 +202,7 @@ export class Client extends AbstractClient { public async fetchToken( username: string, password: string, org?: string, protocol = 'https', host = 'hub.graphistry.com' ): Promise { - return (await this.postToApi( + let response = await this.postToApi( AUTH_API_ENDPOINT, { username: username, @@ -210,6 +211,8 @@ export class Client extends AbstractClient { }, this.getBaseHeaders(), `${protocol}://${host}/` - )).token; + ); + response = await response.json(); + return response.token; } } \ No newline at end of file diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPkey.ts index 150b7d8..31fb9c9 100644 --- a/projects/js-upload-api/src/ClientPkey.ts +++ b/projects/js-upload-api/src/ClientPkey.ts @@ -138,6 +138,10 @@ export class ClientPkey extends AbstractClient { return false; } + private getPkeyString(id: string, secret: string) { + return `PersonalKey ${id}:${secret}`; + } + /** * Get the authentication token for the current user. * By default, reuses current token if available. @@ -165,12 +169,29 @@ export class ClientPkey extends AbstractClient { console.debug('getAuthToken', {personalKeyId: this.personalKeyId, personalKeySecret: this._personalKeySecret, host: this.host}); - const response = await this.getToApi( + let response = await this.postToApi( AUTH_API_ENDPOINT, { - "Authorization": `PersonalKey ${this.personalKeyId}:${this._personalKeySecret}`, + ...(this.org ? {org_name: this.org} : {}), }, - ) + { + "Authorization": this.getPkeyString(this.personalKeyId, this._personalKeySecret), + ...this.getBaseHeaders(), + } + ); + // fallback to personal-only GET pkey auth if 405 (Method Not Allowed) + if(response.status === 405) { + if(this.org) { + console.warn('Host does not support org auth via pkey, use username/password auth instead'); + } + response = await this.getToApi( + AUTH_API_ENDPOINT, + { + "Authorization": this.getPkeyString(this.personalKeyId, this._personalKeySecret), + } + ); + } + response = await response.json(); const tok : string = response.token; this._token = tok; @@ -196,14 +217,34 @@ export class ClientPkey extends AbstractClient { * */ public async fetchToken( - personalKeyId: string, personalKeySecret: string, _org?: string, protocol = 'https', host = 'hub.graphistry.com' + personalKeyId: string, personalKeySecret: string, org?: string, protocol = 'https', host = 'hub.graphistry.com' ): Promise { - return (await this.getToApi( + let response = await this.postToApi( AUTH_API_ENDPOINT, { - "Authorization": `PersonalKey ${personalKeyId}:${personalKeySecret}`, + ...(org ? {org_name: org} : {}), + }, + { + "Authorization": this.getPkeyString(personalKeyId, personalKeySecret), + ...this.getBaseHeaders(), }, `${protocol}://${host}/` - )).token; + ); + // fallback to personal-only GET pkey auth if 405 (Method Not Allowed) + if(response.status === 405) { + if(org) { + console.warn('Host does not support org auth via pkey, use username/password auth instead'); + } + response = await this.getToApi( + AUTH_API_ENDPOINT, + { + "Authorization": this.getPkeyString(personalKeyId, personalKeySecret), + }, + `${protocol}://${host}/` + ); + } + response = await response.json(); + + return response.token; } } \ No newline at end of file From 494bf5169027e55477550b4be74b3af7fbb26520 Mon Sep 17 00:00:00 2001 From: Leo Meyerovich Date: Fri, 15 Mar 2024 09:34:30 -0700 Subject: [PATCH 18/20] docs(changelog): ClientPKey --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1e4395..7c69eb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ## Dev +## 5.1.0 - 2024-03-15 + +### Added + +* **client-api**: Add API-key-based `ClientPKey` upload client +* **client-api-react**: Add API-key-based `ClientPKey` upload client +* **node-api**: Add API-key-based `ClientPKey` upload client +* **js-upload-api**: Add API-key-based `ClientPKey` upload client + +### Refactor + +* Factor out base class `AbstractClient` and add type export of `ClientType` + ## 5.0.2 - 2024-02-13 ### Added From 2e51e94f8e4b61373a123d4379b87693e2de0be1 Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Fri, 15 Mar 2024 15:04:25 -0400 Subject: [PATCH 19/20] rename "Pkey" to "PKey" --- projects/client-api-react/src/index.js | 4 ++-- projects/client-api/src/index.js | 8 ++++---- projects/js-upload-api/src/ClientPkey.ts | 16 ++++++++-------- projects/js-upload-api/src/index.ts | 2 +- projects/js-upload-api/src/types.ts | 4 ++-- projects/node-api/src/index.ts | 8 ++++---- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/projects/client-api-react/src/index.js b/projects/client-api-react/src/index.js index d402d3b..5ec9dd7 100644 --- a/projects/client-api-react/src/index.js +++ b/projects/client-api-react/src/index.js @@ -9,10 +9,10 @@ import * as gAPI from '@graphistry/client-api'; import { ajax, catchError, first, forkJoin, map, of, switchMap, tap } from '@graphistry/client-api'; // avoid explicit rxjs dep import { bg } from './bg'; import { bindings, panelNames, calls } from './bindings.js'; -import { Client as ClientBase, ClientPkey as ClientPkeyBase, selectionUpdates, subscribeLabels } from '@graphistry/client-api'; +import { Client as ClientBase, ClientPKey as ClientPKeyBase, selectionUpdates, subscribeLabels } from '@graphistry/client-api'; export const Client = ClientBase; -export const ClientPkey = ClientPkeyBase; +export const ClientPKey = ClientPKeyBase; //https://blog.logrocket.com/how-to-get-previous-props-state-with-react-hooks/ function usePrevious(value) { diff --git a/projects/client-api/src/index.js b/projects/client-api/src/index.js index dbacd16..54e5970 100644 --- a/projects/client-api/src/index.js +++ b/projects/client-api/src/index.js @@ -3,7 +3,7 @@ import shallowEqual from 'shallowequal'; import { Model } from '@graphistry/falcor-model-rxjs'; import { PostMessageDataSource } from '@graphistry/falcor-socket-datasource'; import { $ref, $atom, $value } from '@graphistry/falcor-json-graph'; -import { Client as ClientBase, ClientPkey as ClientPkeyBase, Dataset as DatasetBase, File as FileBase, EdgeFile as EdgeFileBase, NodeFile as NodeFileBase } from '@graphistry/js-upload-api'; +import { Client as ClientBase, ClientPKey as ClientPKeyBase, Dataset as DatasetBase, File as FileBase, EdgeFile as EdgeFileBase, NodeFile as NodeFileBase } from '@graphistry/js-upload-api'; const CLIENT_SUBSCRIPTION_API_VERSION = 1; @@ -54,11 +54,11 @@ export class Client extends ClientBase { } /** - * Class wrapping @graphistry/js-upload-api::ClientPkey for client->server File and Dataset uploads using personal key authentication. + * Class wrapping @graphistry/js-upload-api::ClientPKey for client->server File and Dataset uploads using personal key authentication. * @global - * @extends ClientPkeyBase + * @extends ClientPKeyBase */ -export class ClientPkey extends ClientPkeyBase { +export class ClientPKey extends ClientPKeyBase { /** * Create a Client * @constructor diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPkey.ts index 31fb9c9..6461f98 100644 --- a/projects/js-upload-api/src/ClientPkey.ts +++ b/projects/js-upload-api/src/ClientPkey.ts @@ -72,7 +72,7 @@ const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; * ``` */ -export class ClientPkey extends AbstractClient { +export class ClientPKey extends AbstractClient { public readonly personalKeyId: string; private _personalKeySecret: string; @@ -138,7 +138,7 @@ export class ClientPkey extends AbstractClient { return false; } - private getPkeyString(id: string, secret: string) { + private getPKeyString(id: string, secret: string) { return `PersonalKey ${id}:${secret}`; } @@ -175,19 +175,19 @@ export class ClientPkey extends AbstractClient { ...(this.org ? {org_name: this.org} : {}), }, { - "Authorization": this.getPkeyString(this.personalKeyId, this._personalKeySecret), + "Authorization": this.getPKeyString(this.personalKeyId, this._personalKeySecret), ...this.getBaseHeaders(), } ); // fallback to personal-only GET pkey auth if 405 (Method Not Allowed) if(response.status === 405) { if(this.org) { - console.warn('Host does not support org auth via pkey, use username/password auth instead'); + console.warn('Host does not support org auth via PKey, use username/password auth instead'); } response = await this.getToApi( AUTH_API_ENDPOINT, { - "Authorization": this.getPkeyString(this.personalKeyId, this._personalKeySecret), + "Authorization": this.getPKeyString(this.personalKeyId, this._personalKeySecret), } ); } @@ -225,7 +225,7 @@ export class ClientPkey extends AbstractClient { ...(org ? {org_name: org} : {}), }, { - "Authorization": this.getPkeyString(personalKeyId, personalKeySecret), + "Authorization": this.getPKeyString(personalKeyId, personalKeySecret), ...this.getBaseHeaders(), }, `${protocol}://${host}/` @@ -233,12 +233,12 @@ export class ClientPkey extends AbstractClient { // fallback to personal-only GET pkey auth if 405 (Method Not Allowed) if(response.status === 405) { if(org) { - console.warn('Host does not support org auth via pkey, use username/password auth instead'); + console.warn('Host does not support org auth via PKey, use username/password auth instead'); } response = await this.getToApi( AUTH_API_ENDPOINT, { - "Authorization": this.getPkeyString(personalKeyId, personalKeySecret), + "Authorization": this.getPKeyString(personalKeyId, personalKeySecret), }, `${protocol}://${host}/` ); diff --git a/projects/js-upload-api/src/index.ts b/projects/js-upload-api/src/index.ts index 284286c..c4899e7 100644 --- a/projects/js-upload-api/src/index.ts +++ b/projects/js-upload-api/src/index.ts @@ -1,6 +1,6 @@ "use strict"; export { Client } from "./Client.js"; -export { ClientPkey } from "./ClientPkey.js"; +export { ClientPKey } from "./ClientPkey.js"; export { ClientType } from "./types.js"; export { FileType, File, EdgeFile, NodeFile } from "./File.js"; export { Dataset } from "./Dataset.js"; diff --git a/projects/js-upload-api/src/types.ts b/projects/js-upload-api/src/types.ts index 91558ea..31eac2e 100644 --- a/projects/js-upload-api/src/types.ts +++ b/projects/js-upload-api/src/types.ts @@ -1,5 +1,5 @@ import { Client } from "./Client.js"; -import { ClientPkey } from "./ClientPkey.js"; +import { ClientPKey } from "./ClientPkey.js"; /** * @internal @@ -11,4 +11,4 @@ import { ClientPkey } from "./ClientPkey.js"; * A type including clients with all available authentication methods * */ -export type ClientType = Client | ClientPkey; \ No newline at end of file +export type ClientType = Client | ClientPKey; \ No newline at end of file diff --git a/projects/node-api/src/index.ts b/projects/node-api/src/index.ts index fb4ed33..58e5693 100644 --- a/projects/node-api/src/index.ts +++ b/projects/node-api/src/index.ts @@ -1,4 +1,4 @@ -import { Client as ClientBase, ClientPkey as ClientPkeyBase } from '@graphistry/js-upload-api'; +import { Client as ClientBase, ClientPKey as ClientPKeyBase } from '@graphistry/js-upload-api'; import { version as VERSION } from './version.js'; import fetch from 'node-fetch-commonjs'; @@ -52,11 +52,11 @@ export class Client extends ClientBase { } /** - * Class wrapping @graphistry/js-upload-api::ClientPkey for client->server File and Dataset uploads using personal key authentication. + * Class wrapping @graphistry/js-upload-api::ClientPKey for client->server File and Dataset uploads using personal key authentication. * @global - * @extends ClientPkeyBase + * @extends ClientPKeyBase */ -export class ClientPkey extends ClientPkeyBase { +export class ClientPKey extends ClientPKeyBase { /** * Create a Client * @constructor From cba99160e2c095f2da73f0a6b4bcdac0a9c3108f Mon Sep 17 00:00:00 2001 From: Manfred Cheung Date: Fri, 15 Mar 2024 15:34:55 -0400 Subject: [PATCH 20/20] rename clientPkey file --- projects/js-upload-api/src/{ClientPkey.ts => ClientPKey.ts} | 0 projects/js-upload-api/src/index.ts | 2 +- projects/js-upload-api/src/types.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename projects/js-upload-api/src/{ClientPkey.ts => ClientPKey.ts} (100%) diff --git a/projects/js-upload-api/src/ClientPkey.ts b/projects/js-upload-api/src/ClientPKey.ts similarity index 100% rename from projects/js-upload-api/src/ClientPkey.ts rename to projects/js-upload-api/src/ClientPKey.ts diff --git a/projects/js-upload-api/src/index.ts b/projects/js-upload-api/src/index.ts index c4899e7..20d40fe 100644 --- a/projects/js-upload-api/src/index.ts +++ b/projects/js-upload-api/src/index.ts @@ -1,6 +1,6 @@ "use strict"; export { Client } from "./Client.js"; -export { ClientPKey } from "./ClientPkey.js"; +export { ClientPKey } from "./ClientPKey.js"; export { ClientType } from "./types.js"; export { FileType, File, EdgeFile, NodeFile } from "./File.js"; export { Dataset } from "./Dataset.js"; diff --git a/projects/js-upload-api/src/types.ts b/projects/js-upload-api/src/types.ts index 31eac2e..cec857b 100644 --- a/projects/js-upload-api/src/types.ts +++ b/projects/js-upload-api/src/types.ts @@ -1,5 +1,5 @@ import { Client } from "./Client.js"; -import { ClientPKey } from "./ClientPkey.js"; +import { ClientPKey } from "./ClientPKey.js"; /** * @internal