From 89bc849bbcf8fa523692af22f5f9db39c886d247 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Sun, 21 May 2023 12:24:26 -0700 Subject: [PATCH] Refactored and fixed types --- src/lib/remote.ts | 15 ++++---- src/lib/resolver.ts | 11 +++--- src/lib/snapshot.ts | 17 ++++----- src/switcher-client.ts | 51 +++++++++++++++------------ src/types/index.d.ts | 59 ++++++++++++++++++++++++++++++++ test/switcher-integrated.test.ts | 4 +-- test/switcher-snapshot.test.ts | 4 +-- 7 files changed, 116 insertions(+), 45 deletions(-) diff --git a/src/lib/remote.ts b/src/lib/remote.ts index 000830d..de9b8fd 100644 --- a/src/lib/remote.ts +++ b/src/lib/remote.ts @@ -7,10 +7,11 @@ import { CriteriaError, SnapshotServiceError, } from './exceptions/index.ts'; +import { RetryOptions, SwitcherContext, SwitcherOptions } from '../types/index.d.ts'; const getConnectivityError = (code: string) => `Connection has been refused - ${code}`; -const getHeader = (token: string) => { +const getHeader = (token: string | undefined) => { return { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', @@ -37,7 +38,7 @@ export const getEntry = (input?: string[][]) => { return entry; }; -export const checkAPIHealth = async (url: string, options: any) => { +export const checkAPIHealth = async (url: string, options: SwitcherOptions, retryOptions: RetryOptions) => { try { const response = await fetch(`${url}/check`, { method: 'get' }); if (response.status != 200) { @@ -47,7 +48,7 @@ export const checkAPIHealth = async (url: string, options: any) => { if (options && 'silentMode' in options) { if (options.silentMode) { const expirationTime = new DateMoment(new Date()) - .add(options.retryTime, options.retryDurationIn).getDate(); + .add(retryOptions.retryTime, retryOptions.retryDurationIn).getDate(); return { data: { @@ -61,7 +62,7 @@ export const checkAPIHealth = async (url: string, options: any) => { }; export const checkCriteria = async ( - context: any, + context: SwitcherContext, key?: string, input?: string[][], showReason = false, @@ -85,7 +86,7 @@ export const checkCriteria = async ( } }; -export const auth = async (context: any) => { +export const auth = async (context: SwitcherContext) => { try { const response = await fetch(`${context.url}/criteria/auth`, { method: 'post', @@ -95,7 +96,7 @@ export const auth = async (context: any) => { environment: context.environment, }), headers: { - 'switcher-api-key': context.apiKey, + 'switcher-api-key': context.apiKey || '', 'Content-Type': 'application/json', }, }); @@ -108,7 +109,7 @@ export const auth = async (context: any) => { export const checkSwitchers = async ( url: string, - token: string, + token: string | undefined, switcherKeys: string[], ) => { try { diff --git a/src/lib/resolver.ts b/src/lib/resolver.ts index 0582724..d382904 100644 --- a/src/lib/resolver.ts +++ b/src/lib/resolver.ts @@ -1,9 +1,10 @@ // deno-lint-ignore-file no-explicit-any import { processOperation } from './snapshot.ts'; import * as services from '../lib/remote.ts'; +import { Config, Group, Snapshot, SnapshotData } from '../types/index.d.ts'; async function resolveCriteria( - data: any, + data: SnapshotData, key: string, input?: string[][], ) { @@ -44,7 +45,7 @@ async function resolveCriteria( * @return true if Switcher found */ async function checkGroup( - groups: any[], + groups: Group[], key: string, input?: string[][], ) { @@ -68,7 +69,7 @@ async function checkGroup( * @param {*} input Strategy input if exists * @return true if Switcher found */ -async function checkConfig(group: any, config: any, input?: string[][]) { +async function checkConfig(group: Group, config: Config, input?: string[][]) { if (!config) { return false; } @@ -88,7 +89,7 @@ async function checkConfig(group: any, config: any, input?: string[][]) { return true; } -async function checkStrategy(config: any, input: string[][]) { +async function checkStrategy(config: Config, input: string[][]) { const { strategies } = config; const entry = services.getEntry(input); @@ -127,7 +128,7 @@ async function checkStrategyInput(entry?: any[], strategyInput?: any) { } export default async function checkCriteriaOffline( - snapshot: any, + snapshot: Snapshot | undefined, key: string, input?: string[][], ) { diff --git a/src/lib/snapshot.ts b/src/lib/snapshot.ts index d048b2b..84d4075 100644 --- a/src/lib/snapshot.ts +++ b/src/lib/snapshot.ts @@ -7,6 +7,7 @@ import TimedMatch from './utils/timed-match/index.ts'; import { parseJSON, payloadReader } from './utils/payloadReader.ts'; import { CheckSwitcherError } from './exceptions/index.ts'; import { checkSnapshotVersion, resolveSnapshot } from './remote.ts'; +import { Snapshot, SwitcherContext } from '../types/index.d.ts'; export const loadDomain = (snapshotLocation: string, environment: string) => { let dataJSON; @@ -36,23 +37,23 @@ export const loadDomain = (snapshotLocation: string, environment: string) => { }; export const validateSnapshot = async ( - context: any, - snapshotLocation: string, + context: SwitcherContext, + snapshotLocation: string | undefined, snapshotVersion: number, ) => { const { status } = await checkSnapshotVersion( - context.url, - context.token, + context.url || '', + context.token || '', snapshotVersion, ); if (!status) { const snapshot = await resolveSnapshot( - context.url, - context.token, + context.url || '', + context.token || '', context.domain, context.environment, - context.component, + context.component || '', ); Deno.writeTextFile( @@ -64,7 +65,7 @@ export const validateSnapshot = async ( return false; }; -export const checkSwitchers = (snapshot: any, switcherKeys: string[]) => { +export const checkSwitchers = (snapshot: Snapshot, switcherKeys: string[]) => { const { group } = snapshot.data.domain; const notFound = []; let found = false; diff --git a/src/switcher-client.ts b/src/switcher-client.ts index 16faf5f..ee7daba 100644 --- a/src/switcher-client.ts +++ b/src/switcher-client.ts @@ -6,6 +6,7 @@ import TimedMatch from './lib/utils/timed-match/index.ts'; import { checkSwitchers, loadDomain, validateSnapshot } from './lib/snapshot.ts'; import * as services from './lib/remote.ts'; import checkCriteriaOffline from './lib/resolver.ts'; +import { RetryOptions, Snapshot, SwitcherContext, SwitcherOptions } from './types/index.d.ts'; const DEFAULT_ENVIRONMENT = 'default'; const DEFAULT_SNAPSHOT_LOCATION = './snapshot/'; @@ -26,9 +27,10 @@ export class Switcher { private static _watcher: Deno.FsWatcher; private static _watchDebounce = new Map(); - private static _snapshot: any; - private static _context: any; - private static _options: any; + private static _snapshot?: Snapshot; + private static _context: SwitcherContext; + private static _options: SwitcherOptions; + private static _retryOptions: RetryOptions; private _delay = 0; private _nextRun = 0; @@ -41,11 +43,14 @@ export class Switcher { * @param context Necessary arguments * @param options */ - static buildContext(context: any, options?: any) { + static buildContext(context: SwitcherContext, options?: SwitcherOptions) { this._testEnabled = DEFAULT_TEST_MODE; this._snapshot = undefined; - this._context = {}; + this._context = { + domain: context.domain, + environment: context.environment, + }; this._context = context; this._context.url = context.url; this._context.environment = context.environment || DEFAULT_ENVIRONMENT; @@ -75,11 +80,15 @@ export class Switcher { } if ('retryAfter' in options) { - this._options.retryTime = options.retryAfter.slice(0, -1); - this._options.retryDurationIn = options.retryAfter.slice(-1); + this._retryOptions = { + retryTime: parseInt(options.retryAfter?.slice(0, -1) || DEFAULT_RETRY_TIME.charAt(0)), + retryDurationIn: options.retryAfter?.slice(-1) || DEFAULT_RETRY_TIME.charAt(1), + }; } else { - this._options.retryTime = DEFAULT_RETRY_TIME.charAt(0); - this._options.retryDurationIn = DEFAULT_RETRY_TIME.charAt(1); + this._retryOptions = { + retryTime: parseInt(DEFAULT_RETRY_TIME.charAt(0)), + retryDurationIn: DEFAULT_RETRY_TIME.charAt(1), + }; } this._initTimedMatch(options); @@ -128,11 +137,11 @@ export class Switcher { */ static async loadSnapshot(watchSnapshot?: boolean) { Switcher._snapshot = loadDomain( - Switcher._options.snapshotLocation, + Switcher._options.snapshotLocation || '', Switcher._context.environment, ); if ( - Switcher._snapshot.data.domain.version == 0 && + Switcher._snapshot?.data.domain.version == 0 && !Switcher._options.offline ) { await Switcher.checkSnapshot(); @@ -193,12 +202,12 @@ export class Switcher { * @throws when one or more Switcher Keys were not found */ static async checkSwitchers(switcherKeys: string[]) { - if (Switcher._options.offline) { + if (Switcher._options.offline && Switcher._snapshot) { checkSwitchers(Switcher._snapshot, switcherKeys); } else { await Switcher._auth(); await services.checkSwitchers( - Switcher._context.url, + Switcher._context.url || '', Switcher._context.token, switcherKeys, ); @@ -210,7 +219,7 @@ export class Switcher { if (event.kind === 'modify') { try { Switcher._snapshot = loadDomain( - Switcher._options.snapshotLocation, + Switcher._options.snapshotLocation || '', Switcher._context.environment, ); @@ -250,8 +259,8 @@ export class Switcher { ) { const expirationTime = new DateMoment(new Date()) .add( - Switcher._options.retryTime, - Switcher._options.retryDurationIn, + Switcher._retryOptions.retryTime, + Switcher._retryOptions.retryDurationIn, ) .getDate(); @@ -260,11 +269,11 @@ export class Switcher { } } - const response = await services.checkAPIHealth(Switcher._context.url, { - silentMode: Switcher._options.silentMode, - retryTime: Switcher._options.retryTime, - retryDurationIn: Switcher._options.retryDurationIn, - }); + const response = await services.checkAPIHealth( + Switcher._context.url || '', + Switcher._options, + Switcher._retryOptions, + ); if (response) { Switcher._context.token = response.data.token; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 73f8c95..3b1998c 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -11,3 +11,62 @@ declare global { input: string; } } + +export interface SwitcherContext { + url?: string; + apiKey?: string; + domain: string; + component?: string; + environment: string; + token?: string; + exp?: number; +} + +export interface SwitcherOptions { + offline?: boolean; + logger?: boolean; + snapshotLocation?: string; + silentMode?: boolean; + retryAfter?: string; + regexMaxBlackList?: number; + regexMaxTimeLimit?: number; +} + +export interface RetryOptions { + retryTime: number; + retryDurationIn: string; +} + +export interface Snapshot { + data: SnapshotData; +} + +export interface SnapshotData { + domain: Domain; +} + +export interface Domain { + name: string; + version: number; + activated: boolean; + group: Group[]; +} + +export interface Group { + name: string; + activated: boolean; + config: Config[]; +} + +export interface Config { + key: string; + activated: boolean; + strategies: Strategy[]; +} + +export interface Strategy { + strategy: string; + activated: boolean; + operation: string; + values: string[]; +} diff --git a/test/switcher-integrated.test.ts b/test/switcher-integrated.test.ts index 2c1f2b6..484f818 100644 --- a/test/switcher-integrated.test.ts +++ b/test/switcher-integrated.test.ts @@ -1,4 +1,3 @@ -// deno-lint-ignore-file no-explicit-any import { describe, it, afterAll, afterEach, beforeEach } from 'https://deno.land/std@0.188.0/testing/bdd.ts'; import { assertEquals, assertNotEquals, assertRejects, assertFalse } from 'https://deno.land/std@0.188.0/testing/asserts.ts'; import { assertSpyCalls, spy } from 'https://deno.land/std@0.177.0/testing/mock.ts'; @@ -14,10 +13,11 @@ import { checkNumeric, checkPayload } from '../mod.ts'; +import { SwitcherContext } from '../src/types/index.d.ts'; describe('Integrated test - Switcher:', function () { - let contextSettings: any; + let contextSettings: SwitcherContext; afterAll(function() { Switcher.unloadSnapshot(); diff --git a/test/switcher-snapshot.test.ts b/test/switcher-snapshot.test.ts index aecdf27..9acca6e 100644 --- a/test/switcher-snapshot.test.ts +++ b/test/switcher-snapshot.test.ts @@ -1,4 +1,3 @@ -// deno-lint-ignore-file no-explicit-any import { describe, it, afterAll, beforeEach } from 'https://deno.land/std@0.188.0/testing/bdd.ts'; import { assertRejects, assertFalse, assertExists } from 'https://deno.land/std@0.188.0/testing/asserts.ts'; import { delay } from 'https://deno.land/std@0.177.0/async/delay.ts'; @@ -6,12 +5,13 @@ import { existsSync } from 'https://deno.land/std@0.110.0/fs/mod.ts'; import { given, givenError, tearDown, generateAuth, generateStatus, assertTrue } from './helper/utils.ts'; import { Switcher } from '../mod.ts'; +import { SwitcherContext } from '../src/types/index.d.ts'; const testSettings = { sanitizeOps: false, sanitizeResources: false, sanitizeExit: false }; describe('E2E test - Switcher offline - Snapshot:', function () { const token = '[token]'; - let contextSettings: any; + let contextSettings: SwitcherContext; const dataBuffer = Deno.readTextFileSync('./snapshot/dev.json'); const dataJSON = dataBuffer.toString();