diff --git a/deno.jsonc b/deno.jsonc index 38b608d..0511ec8 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,6 +1,6 @@ { "name": "@switcherapi/switcher-client-deno", - "version": "2.3.2", + "version": "2.4.0", "description": "Switcher4Deno is a Feature Flag Deno Client SDK for Switcher API", "tasks": { "cache-reload": "deno cache --reload --lock=deno.lock mod.ts", diff --git a/sonar-project.properties b/sonar-project.properties index f2c88be..f21809c 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,7 +1,7 @@ sonar.projectKey=switcherapi_switcher-client-deno sonar.projectName=switcher-client-deno sonar.organization=switcherapi -sonar.projectVersion=2.3.2 +sonar.projectVersion=2.4.0 sonar.javascript.lcov.reportPaths=coverage/report.lcov diff --git a/src/client.ts b/src/client.ts index 442a4ee..d948bfe 100644 --- a/src/client.ts +++ b/src/client.ts @@ -153,7 +153,7 @@ export class Client { util.get(Client._context.domain, ''), util.get(Client._context.environment, DEFAULT_ENVIRONMENT), util.get(Client._context.component, ''), - GlobalSnapshot.snapshot.data.domain.version, + GlobalSnapshot.snapshot.domain.version, ); if (snapshot) { @@ -204,7 +204,7 @@ export class Client { * - GlobalOptions.local is false, meaning it will not use the local snapshot. */ private static _isCheckSnapshotAvailable(fetchRemote: boolean): boolean { - return GlobalSnapshot.snapshot?.data.domain.version == 0 && (fetchRemote || !GlobalOptions.local); + return GlobalSnapshot.snapshot?.domain.version == 0 && (fetchRemote || !GlobalOptions.local); } /** @@ -365,6 +365,6 @@ export class Client { * Returns the current snapshot version. */ static get snapshotVersion(): number { - return GlobalSnapshot.snapshot?.data.domain.version || 0; + return GlobalSnapshot.snapshot?.domain.version || 0; } } diff --git a/src/lib/remote.ts b/src/lib/remote.ts index 91243c6..bb2b18d 100644 --- a/src/lib/remote.ts +++ b/src/lib/remote.ts @@ -1,5 +1,5 @@ import { CheckSwitcherError, ClientError, RemoteError } from './exceptions/index.ts'; -import type { AuthResponse, CheckSnapshotVersionResponse, Entry, SwitcherContext } from '../types/index.d.ts'; +import type { AuthResponse, CheckSnapshotVersionResponse, Domain, Entry, SwitcherContext } from '../types/index.d.ts'; import type { SwitcherResult } from './result.ts'; import * as util from './utils/index.ts'; import { GlobalAuth } from './globals/globalAuth.ts'; @@ -147,6 +147,12 @@ export const resolveSnapshot = async ( environment: string, component: string, ) => { + type GraphQLResponse = { + data: { + domain: Domain; + }; + }; + const data = { query: ` query domain { @@ -172,7 +178,7 @@ export const resolveSnapshot = async ( }); if (response.status == 200) { - return JSON.stringify(await response.json(), null, 4); + return JSON.stringify((await response.json() as GraphQLResponse).data, null, 4); } throw new RemoteError(`[resolveSnapshot] failed with status ${response.status}`); diff --git a/src/lib/resolver.ts b/src/lib/resolver.ts index d7cf77c..6a4d756 100644 --- a/src/lib/resolver.ts +++ b/src/lib/resolver.ts @@ -1,26 +1,26 @@ import { processOperation } from './snapshot.ts'; import { getEntry } from '../lib/remote.ts'; import * as util from '../lib/utils/index.ts'; -import type { Config, Entry, Group, Snapshot, SnapshotData, Strategy } from '../types/index.d.ts'; +import type { Config, Domain, Entry, Group, Snapshot, Strategy } from '../types/index.d.ts'; import type { SwitcherRequest } from '../switcherRequest.ts'; import { SwitcherResult } from './result.ts'; /** - * Resolves the criteria for a given switcher request against the snapshot data. + * Resolves the criteria for a given switcher request against the snapshot domain. * - * @param {SnapshotData} data - The snapshot data containing domain and group information. + * @param {Domain} domain - The domain containing groups and configurations. * @param {SwitcherRequest} switcher - The switcher request to be evaluated. * @returns {SwitcherResult} - The result of the switcher evaluation. */ function resolveCriteria( - data: SnapshotData, + domain: Domain, switcher: SwitcherRequest, ): SwitcherResult { - if (!data.domain.activated) { + if (!domain.activated) { return SwitcherResult.disabled('Domain disabled'); } - const { group } = data.domain; + const { group } = domain; return checkGroup(group, switcher); } @@ -138,7 +138,7 @@ function isStrategyFulfilled(strategyEntry: Entry[], strategyConfig: Strategy) { /** * Checks the criteria for a switcher request against the local snapshot. * - * @param {Snapshot | undefined} snapshot - The snapshot containing the data to check against. + * @param {Snapshot | undefined} snapshot - The snapshot containing the domain to check against. * @param {SwitcherRequest} switcher - The switcher request to be evaluated. * @returns {SwitcherResult} - The result of the switcher evaluation. * @throws {Error} - If the snapshot is not loaded. @@ -153,6 +153,6 @@ export default function checkCriteriaLocal( ); } - const { data } = snapshot; - return resolveCriteria(data, switcher); + const { domain } = snapshot; + return resolveCriteria(domain, switcher); } diff --git a/src/lib/snapshot.ts b/src/lib/snapshot.ts index 21581f3..74f5245 100644 --- a/src/lib/snapshot.ts +++ b/src/lib/snapshot.ts @@ -73,7 +73,7 @@ export const loadDomain = (snapshotLocation: string, environment: string) => { dataBuffer = Deno.readTextFileSync(snapshotFile); } else { dataBuffer = JSON.stringify( - { data: { domain: { version: 0 } } }, + { domain: { version: 0 } }, null, 4, ); @@ -111,7 +111,7 @@ export const validateSnapshot = async ( }; export const checkSwitchersLocal = (snapshot: Snapshot, switcherKeys: string[]) => { - const { group } = snapshot.data.domain; + const { group } = snapshot.domain; const notFound = []; let found = false; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index c7be365..c03244c 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -157,10 +157,6 @@ export type CheckSnapshotVersionResponse = { // Switcher API domain types export type Snapshot = { - data: SnapshotData; -}; - -export type SnapshotData = { domain: Domain; }; diff --git a/tests/playground/index.ts b/tests/playground/index.ts index 6559f2d..2d88f43 100644 --- a/tests/playground/index.ts +++ b/tests/playground/index.ts @@ -195,7 +195,7 @@ const _testSnapshotAutoUpdate = async () => { const time = Date.now(); await switcher.isItOn(SWITCHER_KEY); console.clear(); - console.log(Client.getLogger(SWITCHER_KEY), `executed in ${Date.now() - time}ms`); + console.log(JSON.stringify(Client.getLogger(SWITCHER_KEY)), `executed in ${Date.now() - time}ms`); }, 2000); }; diff --git a/tests/playground/snapshot/default.json b/tests/playground/snapshot/default.json index a2abbd2..aaa868e 100644 --- a/tests/playground/snapshot/default.json +++ b/tests/playground/snapshot/default.json @@ -1,34 +1,32 @@ { - "data": { - "domain": { - "name": "Switcher API", - "version": 1, - "activated": true, - "group": [ - { - "name": "Test Project", - "activated": true, - "config": [ - { - "key": "CLIENT_DENO_FEATURE", - "activated": true, - "strategies": [ - { - "strategy": "VALUE_VALIDATION", - "activated": false, - "operation": "EXIST", - "values": [ - "user_1" - ] - } - ], - "components": [ - "switcher4deno" - ] - } - ] - } - ] - } + "domain": { + "name": "Switcher API", + "version": 1, + "activated": true, + "group": [ + { + "name": "Test Project", + "activated": true, + "config": [ + { + "key": "CLIENT_DENO_FEATURE", + "activated": true, + "strategies": [ + { + "strategy": "VALUE_VALIDATION", + "activated": false, + "operation": "EXIST", + "values": [ + "user_1" + ] + } + ], + "components": [ + "switcher4deno" + ] + } + ] + } + ] } } \ No newline at end of file diff --git a/tests/playground/snapshot/local.json b/tests/playground/snapshot/local.json index 1e719a8..c517a40 100644 --- a/tests/playground/snapshot/local.json +++ b/tests/playground/snapshot/local.json @@ -1,25 +1,23 @@ { - "data": { - "domain": { - "name": "Switcher API", - "version": 1, - "activated": true, - "group": [ - { - "name": "Test Project", - "activated": true, - "config": [ - { - "key": "CLIENT_DENO_FEATURE", - "activated": true, - "strategies": [], - "components": [ - "switcher4deno" - ] - } - ] - } - ] - } + "domain": { + "name": "Switcher API", + "version": 1, + "activated": true, + "group": [ + { + "name": "Test Project", + "activated": true, + "config": [ + { + "key": "CLIENT_DENO_FEATURE", + "activated": true, + "strategies": [], + "components": [ + "switcher4deno" + ] + } + ] + } + ] } } \ No newline at end of file diff --git a/tests/snapshot/default.json b/tests/snapshot/default.json index a2d3174..f51b04c 100644 --- a/tests/snapshot/default.json +++ b/tests/snapshot/default.json @@ -1,161 +1,159 @@ { - "data": { - "domain": { - "name": "Business", - "description": "Business description", - "activated": true, - "group": [ - { - "name": "Rollout 2020", - "description": "Changes that will be applied during the rollout", - "activated": true, - "config": [ - { - "key": "FF2FOR2020", - "description": "Feature Flag", - "activated": true, - "strategies": [ - { - "strategy": "NETWORK_VALIDATION", - "activated": true, - "operation": "EXIST", - "values": [ - "10.0.0.3/24" - ] - }, - { - "strategy": "VALUE_VALIDATION", - "activated": true, - "operation": "NOT_EXIST", - "values": [ - "USA", - "Canada", - "Australia", - "Africa" - ] - } - ], - "components": [] - }, - { - "key": "FF2FOR2021", - "description": "Strategy disabled", - "activated": true, - "strategies": [ - { - "strategy": "NETWORK_VALIDATION", - "activated": false, - "operation": "EXIST", - "values": [ - "10.0.0.3/24" - ] - } - ], - "components": [] - }, - { - "key": "FF2FOR2022", - "description": "No strategies", - "activated": true, - "components": [] - }, - { - "key": "FF2FOR2023", - "description": "Feature Flag - Payload Strategy", - "activated": true, - "strategies": [ - { - "strategy": "PAYLOAD_VALIDATION", - "activated": true, - "operation": "HAS_ALL", - "values": [ - "id", "user", "user.login", "user.role" - ] - } - ], - "components": [] - }, - { - "key": "FF2FOR2024", - "description": "reDOS safe test", - "activated": true, - "strategies": [ - { - "strategy": "REGEX_VALIDATION", - "activated": true, - "operation": "EXIST", - "values": [ - "^(([a-z])+.)+[A-Z]([a-z])+$" - ] - } - ], - "components": [] - } - ] - }, - { - "name": "Rollout 2030", - "description": "Changes that will be applied during the rollout", - "activated": true, - "config": [ - { - "key": "FF2FOR2030", - "description": "Feature Flag", - "activated": true, - "strategies": [], - "components": [] - }, - { - "key": "FF2FOR2031", - "description": "Feature Flag disabled", - "activated": false, - "strategies": [], - "components": [] - } - ] - }, - { - "name": "Rollout 2040", - "description": "Project is disabled", - "activated": false, - "config": [ - { - "key": "FF2FOR2040", - "description": "Feature Flag", - "activated": true, - "strategies": [], - "components": [] - } - ] - }, - { - "name": "Relay test", - "description": "Relay group", - "activated": true, - "config": [ - { - "key": "USECASE103", - "description": "Relay enabled", - "activated": true, - "relay": { - "type": "VALIDATOR", - "activated": true + "domain": { + "name": "Business", + "description": "Business description", + "activated": true, + "group": [ + { + "name": "Rollout 2020", + "description": "Changes that will be applied during the rollout", + "activated": true, + "config": [ + { + "key": "FF2FOR2020", + "description": "Feature Flag", + "activated": true, + "strategies": [ + { + "strategy": "NETWORK_VALIDATION", + "activated": true, + "operation": "EXIST", + "values": [ + "10.0.0.3/24" + ] }, - "components": [] + { + "strategy": "VALUE_VALIDATION", + "activated": true, + "operation": "NOT_EXIST", + "values": [ + "USA", + "Canada", + "Australia", + "Africa" + ] + } + ], + "components": [] + }, + { + "key": "FF2FOR2021", + "description": "Strategy disabled", + "activated": true, + "strategies": [ + { + "strategy": "NETWORK_VALIDATION", + "activated": false, + "operation": "EXIST", + "values": [ + "10.0.0.3/24" + ] + } + ], + "components": [] + }, + { + "key": "FF2FOR2022", + "description": "No strategies", + "activated": true, + "components": [] + }, + { + "key": "FF2FOR2023", + "description": "Feature Flag - Payload Strategy", + "activated": true, + "strategies": [ + { + "strategy": "PAYLOAD_VALIDATION", + "activated": true, + "operation": "HAS_ALL", + "values": [ + "id", "user", "user.login", "user.role" + ] + } + ], + "components": [] + }, + { + "key": "FF2FOR2024", + "description": "reDOS safe test", + "activated": true, + "strategies": [ + { + "strategy": "REGEX_VALIDATION", + "activated": true, + "operation": "EXIST", + "values": [ + "^(([a-z])+.)+[A-Z]([a-z])+$" + ] + } + ], + "components": [] + } + ] + }, + { + "name": "Rollout 2030", + "description": "Changes that will be applied during the rollout", + "activated": true, + "config": [ + { + "key": "FF2FOR2030", + "description": "Feature Flag", + "activated": true, + "strategies": [], + "components": [] + }, + { + "key": "FF2FOR2031", + "description": "Feature Flag disabled", + "activated": false, + "strategies": [], + "components": [] + } + ] + }, + { + "name": "Rollout 2040", + "description": "Project is disabled", + "activated": false, + "config": [ + { + "key": "FF2FOR2040", + "description": "Feature Flag", + "activated": true, + "strategies": [], + "components": [] + } + ] + }, + { + "name": "Relay test", + "description": "Relay group", + "activated": true, + "config": [ + { + "key": "USECASE103", + "description": "Relay enabled", + "activated": true, + "relay": { + "type": "VALIDATOR", + "activated": true }, - { - "key": "USECASE104", - "description": "Relay disabled", - "relay": { - "type": "VALIDATOR", - "activated": false - }, - "activated": true, - "components": [] - } - ] - } - ] - } + "components": [] + }, + { + "key": "USECASE104", + "description": "Relay disabled", + "relay": { + "type": "VALIDATOR", + "activated": false + }, + "activated": true, + "components": [] + } + ] + } + ] } } \ No newline at end of file diff --git a/tests/snapshot/default_disabled.json b/tests/snapshot/default_disabled.json index 7d30c80..e70b62f 100644 --- a/tests/snapshot/default_disabled.json +++ b/tests/snapshot/default_disabled.json @@ -1,10 +1,8 @@ { - "data": { - "domain": { - "name": "Business", - "description": "Business description", - "activated": false, - "group": [] - } + "domain": { + "name": "Business", + "description": "Business description", + "activated": false, + "group": [] } } \ No newline at end of file diff --git a/tests/snapshot/dev.json b/tests/snapshot/dev.json index 4ec6ed6..1a0c957 100644 --- a/tests/snapshot/dev.json +++ b/tests/snapshot/dev.json @@ -1,26 +1,24 @@ { - "data": { - "domain": { - "name": "Business", - "description": "Business description", - "version": 1588557288037, - "activated": true, - "group": [ - { - "name": "Rollout 2030", - "description": "Changes that will be applied during the rollout", - "activated": true, - "config": [ - { - "key": "FF2FOR2030", - "description": "Feature Flag", - "activated": false, - "strategies": [], - "components": [] - } - ] - } - ] - } + "domain": { + "name": "Business", + "description": "Business description", + "version": 1588557288037, + "activated": true, + "group": [ + { + "name": "Rollout 2030", + "description": "Changes that will be applied during the rollout", + "activated": true, + "config": [ + { + "key": "FF2FOR2030", + "description": "Feature Flag", + "activated": false, + "strategies": [], + "components": [] + } + ] + } + ] } } \ No newline at end of file diff --git a/tests/snapshot/dev_v2.json b/tests/snapshot/dev_v2.json index 17dd1d2..ed53063 100644 --- a/tests/snapshot/dev_v2.json +++ b/tests/snapshot/dev_v2.json @@ -1,26 +1,24 @@ { - "data": { - "domain": { - "name": "Business", - "description": "Business description", - "version": 1588557288040, - "activated": true, - "group": [ - { - "name": "Rollout 2030", - "description": "Changes that will be applied during the rollout", - "activated": true, - "config": [ - { - "key": "FF2FOR2030", - "description": "Feature Flag", - "activated": true, - "strategies": [], - "components": [] - } - ] - } - ] - } + "domain": { + "name": "Business", + "description": "Business description", + "version": 1588557288040, + "activated": true, + "group": [ + { + "name": "Rollout 2030", + "description": "Changes that will be applied during the rollout", + "activated": true, + "config": [ + { + "key": "FF2FOR2030", + "description": "Feature Flag", + "activated": true, + "strategies": [], + "components": [] + } + ] + } + ] } } \ No newline at end of file diff --git a/tests/switcher-snapshot.test.ts b/tests/switcher-snapshot.test.ts index 76815ea..58cd945 100644 --- a/tests/switcher-snapshot.test.ts +++ b/tests/switcher-snapshot.test.ts @@ -11,10 +11,10 @@ describe('E2E test - Client local - Snapshot:', function () { let contextSettings: SwitcherContext; const dataBuffer = Deno.readTextFileSync('./tests/snapshot/dev.json'); - const dataJSON = dataBuffer.toString(); + const dataJSON = `{ "data": ${dataBuffer.toString()} }`; const dataBufferV2 = Deno.readTextFileSync('./tests/snapshot/dev_v2.json'); - const dataJSONV2 = dataBufferV2.toString(); + const dataJSONV2 = `{ "data": ${dataBufferV2.toString()} }`; beforeEach(function() { Client.unloadSnapshot(); diff --git a/tests/switcher-watch-snapshot.test.ts b/tests/switcher-watch-snapshot.test.ts index b5e07e4..c31555f 100644 --- a/tests/switcher-watch-snapshot.test.ts +++ b/tests/switcher-watch-snapshot.test.ts @@ -12,7 +12,7 @@ const updateSwitcher = (status: boolean) => { const dataBuffer = Deno.readTextFileSync('./tests/snapshot/dev.json'); const dataJSON = JSON.parse(dataBuffer.toString()); - dataJSON.data.domain.group[0].config[0].activated = status; + dataJSON.domain.group[0].config[0].activated = status; Deno.mkdirSync('generated-snapshots/', { recursive: true }); Deno.writeTextFileSync('generated-snapshots/watch.json', JSON.stringify(dataJSON, null, 4));