From 926a9f858f38c62c924c2b337a26a4b3971453bb Mon Sep 17 00:00:00 2001 From: Sahil Ahuja Date: Mon, 3 Mar 2025 15:19:59 +0530 Subject: [PATCH] Callers --- repo-template/node-based-repo/package.json | 7 +- .../src/exports/callerUtils.ts | 106 ++++++++++++++++++ .../node-based-repo/src/exports/index.ts | 3 + repo-template/node-based-repo/src/index.ts | 0 4 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 repo-template/node-based-repo/src/exports/callerUtils.ts create mode 100644 repo-template/node-based-repo/src/exports/index.ts create mode 100644 repo-template/node-based-repo/src/index.ts diff --git a/repo-template/node-based-repo/package.json b/repo-template/node-based-repo/package.json index 9b6e22e..ae1055a 100644 --- a/repo-template/node-based-repo/package.json +++ b/repo-template/node-based-repo/package.json @@ -2,8 +2,8 @@ "name": "@gmetrivr/definitions", "version": "1.0.163", "description": "GMetri Definitions", - "types": "./lib/esm/index.d.ts", "@comment main": "This key is still kept around until older version of node that don't understand exports key are used", + "types": "./lib/esm/index.d.ts", "main": "./lib/cjs/index.js", "exports": { "require": "./lib/cjs/index.js", @@ -14,6 +14,7 @@ "license": "UNLICENSED", "sideEffects": false, "type": "module", + "@comment files": "Files dictate what goes to npm", "files": [ "lib/*" ], @@ -39,8 +40,8 @@ "@gmetrixr/gdash": "1.*.*" }, "dependencies": { - "@types/superagent": "^8.1.9", - "superagent": "^10.1.1" + "superagent": "^10.1.1", + "superagent-prefix": "^0.0.2" }, "devDependencies": { "@eslint/js": "^9.20.0", diff --git a/repo-template/node-based-repo/src/exports/callerUtils.ts b/repo-template/node-based-repo/src/exports/callerUtils.ts new file mode 100644 index 0000000..d7b0d8d --- /dev/null +++ b/repo-template/node-based-repo/src/exports/callerUtils.ts @@ -0,0 +1,106 @@ +import request, { SuperAgent } from "superagent"; +import prefix from "superagent-prefix"; + +export function customErrorHandler(err: Error): request.Response { + // optional chaining doesn't work in repos that don't use node-ts yet. + const errMsg = (err as any) && (err as any).response && (err as any).response.text? (err as any).response.text: err.message; + throw new Error(errMsg); +} + +export abstract class BaseCaller { + /** + * Makes the request after prefixing the apiUrl to the request path + * https://visionmedia.github.io/superagent/#get-requests + */ + protected agent: SuperAgent; + + /** + * base API url + */ + protected apiUrl: string; + + /** + * Used in case we use the default token used at the time this class was initialized + */ + private authTokenString: string | undefined; + + /** + * In case the caller decides to pass a function to use to get the authToken + */ + private authTokenFunction: (() => string) | undefined; + + protected useBearerToken = true; + + /** + * Used in case we pass a function to resolve the authToken at realTime + * By default, this simply returns the passed authToken + */ + protected getAuthToken = (): string => { + if (this.authTokenString !== undefined) { + if(this.useBearerToken) { + if(!this.authTokenString.startsWith("Bearer ")){ + return `Bearer ${this.authTokenString}` + } + } + return `${this.authTokenString}`; + } else if (this.authTokenFunction !== undefined) { + return this.authTokenFunction(); + } else { + console.log(`Error from BaseCaller: no auth token set`); + return ""; + } + } + + /** + * Used for callers where the only option is to use API token + * Can be used in the Caller code instead of calling callerInstance.setUseBearerToken(false) in the implementation file + * which would set the Bearer option globally for this callerInstance + */ + protected getApiToken = (): string => { + if (this.authTokenString !== undefined) { + return `${this.authTokenString}`; + } else { + console.log(`Error from BaseCaller: no auth token set`); + return ""; + } + } + + private setAuthToken(authToken: string | (() => string)) { + if(typeof authToken === "string") { + this.authTokenString = authToken; + } else { + this.authTokenFunction = authToken; + } + } + + /** + * authToken accepts either a string or a function. + */ + constructor(apiUrl: string, authToken?: string | (() => string), useBearerToken?: boolean) { + this.apiUrl = apiUrl; + if(authToken !== undefined) { + this.setAuthToken(authToken); + } + if(useBearerToken !== undefined) { + this.setUseBearerToken(useBearerToken); + } + this.agent = request.agent().use(prefix(apiUrl)); + /** + * !IMPORTANT: DO NOT ADD ERROR HANDLING. API ALWAYS RETURNS RESPONSES AND ERRORS. + */ + /*.on("error", (err) => { + console.log(`Error while making request. Status: ${err.status}, Text: ${err.response?.text}`); + throw err; + });*/ + } + + public setUseBearerToken(value = true): void { + this.useBearerToken = value; + } + + /** + * @example + * return new ExampleCaller(this.apiUrl, token); + */ + abstract withToken(token: string): BaseCaller +} diff --git a/repo-template/node-based-repo/src/exports/index.ts b/repo-template/node-based-repo/src/exports/index.ts new file mode 100644 index 0000000..c6cddef --- /dev/null +++ b/repo-template/node-based-repo/src/exports/index.ts @@ -0,0 +1,3 @@ +import { BaseCaller } from "./callerUtils.js"; + +export { BaseCaller }; diff --git a/repo-template/node-based-repo/src/index.ts b/repo-template/node-based-repo/src/index.ts new file mode 100644 index 0000000..e69de29