Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: setup new EdgeWorker SDK with cloud and local bucketing #566

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/shared/bucketing/src/bucketing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ export const generateBucketedConfig = ({
}

segmentedFeatures.forEach(({ feature, target }) => {
const { _id, key, type, variations, settings } = feature
const { variations } = feature
const { rolloutHash, bucketingHash } = generateBoundedHashes(
user.user_id,
target._id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { Response } from 'cross-fetch'
import {
DevCycleOptions,
dvcDefaultLogger,
ResponseError,
} from '@devcycle/js-cloud-server-sdk'
import { DVCLogger } from '@devcycle/types'
import { getEnvironmentConfig } from '../src/request'
import { ResponseError } from '@devcycle/server-request'

const setInterval_mock = mocked(setInterval)
const getEnvironmentConfig_mock = mocked(getEnvironmentConfig)
Expand Down
14 changes: 3 additions & 11 deletions lib/shared/config-manager/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DVCLogger } from '@devcycle/types'
// import { UserError } from './utils/userError'
import { getEnvironmentConfig } from './request'
import { ResponseError, DevCycleOptions } from '@devcycle/js-cloud-server-sdk'
import { DevCycleOptions } from '@devcycle/js-cloud-server-sdk'
import { ResponseError, UserError } from '@devcycle/server-request'

type ConfigPollingOptions = DevCycleOptions & {
cdnURI?: string
Expand All @@ -10,15 +10,7 @@ type ConfigPollingOptions = DevCycleOptions & {
type SetIntervalInterface = (handler: () => void, timeout?: number) => any
type ClearIntervalInterface = (intervalTimeout: any) => void

type SetConfigBuffer = (sdkKey: string, projectConfig: string) => void

export class UserError extends Error {
constructor(error: Error | string) {
super(error instanceof Error ? error.message : error)
this.name = 'UserError'
this.stack = error instanceof Error ? error.stack : undefined
}
}
type SetConfigBuffer = (sdkKey: string, projectConfigStr: string) => void

export class EnvironmentConfigManager {
private readonly logger: DVCLogger
Expand Down
20 changes: 1 addition & 19 deletions lib/shared/config-manager/src/request.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { RequestInitWithRetry } from 'fetch-retry'
import { get } from '@devcycle/js-cloud-server-sdk'
import { getWithTimeout } from '@devcycle/server-request'

export async function getEnvironmentConfig(
url: string,
Expand All @@ -19,20 +18,3 @@ export async function getEnvironmentConfig(
requestTimeout,
)
}

async function getWithTimeout(
url: string,
requestConfig: RequestInit | RequestInitWithRetry,
timeout: number,
): Promise<Response> {
const controller = new AbortController()
const id = setTimeout(() => {
controller.abort()
}, timeout)
const response = await get(url, {
...requestConfig,
signal: controller.signal,
})
clearTimeout(id)
return response
}
18 changes: 18 additions & 0 deletions lib/shared/server-request/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
11 changes: 11 additions & 0 deletions lib/shared/server-request/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# server-request

This library contains common code for making requests to the DevCycle server from server SDKs.

## Building

Run `nx build server-request` to build the library.

## Running unit tests

Run `nx test server-request` to execute the unit tests via [Jest](https://jestjs.io).
6 changes: 6 additions & 0 deletions lib/shared/server-request/__mocks__/cross-fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const { Request, Response } = jest.requireActual('cross-fetch')

const fetch = jest.fn()

export { Request, Response }
export default fetch
2 changes: 2 additions & 0 deletions lib/shared/server-request/__mocks__/fetch-retry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const fetchWithRetry = (_fetch: unknown): unknown => _fetch
export default fetchWithRetry
63 changes: 63 additions & 0 deletions lib/shared/server-request/__tests__/models/requestEvent.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { DVCRequestEvent, EventTypes } from '../../src'

describe('DVCRequestEvent Unit Tests', () => {
it('should construct custom DVCRequestEvent from DVCEvent', () => {
const date = Date.now()
const requestEvent = new DVCRequestEvent(
{
type: 'type',
date,
target: 'target',
value: 610,
metaData: { meta: 'data' },
},
'user_id',
{ feature: 'vars' },
)

expect(requestEvent).toEqual({
type: 'customEvent',
customType: 'type',
user_id: 'user_id',
clientDate: date,
target: 'target',
value: 610,
featureVars: { feature: 'vars' },
metaData: { meta: 'data' },
})
})

it('should construct an event for an internal DVC Event', () => {
const requestEvent = new DVCRequestEvent(
{
type: EventTypes.variableEvaluated,
},
'user_id',
)
expect(requestEvent).toEqual(
expect.objectContaining({
type: EventTypes.variableEvaluated,
user_id: 'user_id',
clientDate: expect.any(Number),
}),
)
})

it('should check that type is defined as a string', () => {
expect(() => new (DVCRequestEvent as any)({})).toThrow(
'Missing parameter: type',
)
expect(() => new (DVCRequestEvent as any)({ type: 6 })).toThrow(
'type is not of type: string',
)
})

it('should check that user_id is defined as a string', () => {
expect(() => new (DVCRequestEvent as any)({ type: 'type' })).toThrow(
'Missing parameter: user_id',
)
expect(() => new (DVCRequestEvent as any)({ type: 'type' }, 6)).toThrow(
'user_id is not of type: string',
)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ global.fetch = fetch

const fetchRequestMock = fetch as jest.MockedFn<typeof fetch>

import { post, get } from '../src/request'
import { post, get } from '../src/'

describe('request.ts Unit Tests', () => {
beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
checkParamDefined,
checkParamType,
typeEnum,
} from '../../src/utils/paramUtils'
import { checkParamDefined, checkParamType, typeEnum } from '../../src'

describe('paramUtils Unit Tests', () => {
describe('checkParamDefined', () => {
Expand Down
13 changes: 13 additions & 0 deletions lib/shared/server-request/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* eslint-disable */
export default {
displayName: 'server-request',
preset: '../../../jest.preset.js',
transform: {
'^.+\\.[tj]s$': [
'ts-jest',
{ tsconfig: '<rootDir>/tsconfig.spec.json' },
],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../../coverage/lib/shared/server-request',
}
9 changes: 9 additions & 0 deletions lib/shared/server-request/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@devcycle/server-request",
"version": "1.0.0",
"type": "commonjs",
"private": true,
"dependencies": {
"fetch-retry": "^5.0.3"
}
}
40 changes: 40 additions & 0 deletions lib/shared/server-request/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "server-request",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "lib/shared/server-request/src",
"projectType": "library",
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/lib/shared/server-request",
"main": "lib/shared/server-request/src/index.ts",
"tsConfig": "lib/shared/server-request/tsconfig.lib.json",
"assets": ["lib/shared/server-request/*.md"]
}
},
"lint": {
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["lib/shared/server-request/**/*.ts"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "lib/shared/server-request/jest.config.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
}
},
"tags": []
}
5 changes: 5 additions & 0 deletions lib/shared/server-request/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from './request'
export * from './userError'
export * from './utils/paramUtils'
export * from './models/devcycleEvent'
export * from './models/requestEvent'
26 changes: 26 additions & 0 deletions lib/shared/server-request/src/models/devcycleEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export interface DevCycleEvent {
/**
* type of the event
*/
type: string

/**
* date event occurred according to client stored as time since epoch
*/
date?: number

/**
* target / subject of event. Contextual to event type
*/
target?: string

/**
* value for numerical events. Contextual to event type
*/
value?: number

/**
* extra metadata for event. Contextual to event type
*/
metaData?: Record<string, unknown>
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { EventTypes } from '../eventQueue'
import {
DevCycleEvent,
checkParamDefined,
checkParamString,
} from '@devcycle/js-cloud-server-sdk'
import { checkParamDefined, checkParamString } from '../utils/paramUtils'
import { DevCycleEvent } from './devcycleEvent'

export const AggregateEventTypes: Record<string, string> = {
variableEvaluated: 'variableEvaluated',
aggVariableEvaluated: 'aggVariableEvaluated',
variableDefaulted: 'variableDefaulted',
aggVariableDefaulted: 'aggVariableDefaulted',
}

export const EventTypes: Record<string, string> = {
...AggregateEventTypes,
}

export class DVCRequestEvent {
type: string
Expand Down
Loading