-
Notifications
You must be signed in to change notification settings - Fork 31
feat: Add Fastly Edge SDK #723
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
Changes from 8 commits
00ecc9a
809e1cd
0914d82
be7aa07
40f05ab
77485da
aff265d
7d47d12
cfddcdc
6079a15
f9b9561
7fd2d96
ce436a2
3717d13
e96311c
9c7c966
91819c9
584eef5
08cb672
53891b1
1fb5431
9c6d3dd
ed6764e
4282427
a422de4
6271e7c
dff0e69
7c1bc03
2eef68d
b41b07b
dda0ce5
389c52e
a73b761
0111854
3a67b2b
36d8136
c567c1a
7cd6bff
c90f23a
fa71eb6
8cb7fd0
67bde4a
58c7cd2
7047f2f
3eea8c2
ccd9d42
01f9784
98bb0e6
bf72203
fd91a2a
ecaad7b
7beddc1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ export interface EdgeProvider { | |
|
|
||
| export class EdgeFeatureStore implements LDFeatureStore { | ||
| private readonly _rootKey: string; | ||
| private _kvData: string | null | undefined; | ||
|
||
|
|
||
| constructor( | ||
| private readonly _edgeProvider: EdgeProvider, | ||
|
|
@@ -24,6 +25,18 @@ export class EdgeFeatureStore implements LDFeatureStore { | |
| this._rootKey = `LD-Env-${sdkKey}`; | ||
| } | ||
|
|
||
| /** | ||
| * This function is used to lazy load the KV data from the edge provider. This is necessary because Fastly Compute | ||
| * has a limit of 32 backend requests (including requests to fetch the KV data). | ||
| * https://docs.fastly.com/products/compute-resource-limits | ||
| */ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you want to describe in the readme or public APIs that data won't receive updates during the runtime of the fastly process/execution/request handler lifecycle? (I think I have that right)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the feedback. I just added a Usage Notes section to the README that contains this. |
||
| private async _getKVData(): Promise<string | null | undefined> { | ||
| if (!this._kvData) { | ||
| this._kvData = await this._edgeProvider.get(this._rootKey); | ||
| } | ||
| return this._kvData; | ||
| } | ||
|
|
||
| async get( | ||
| kind: DataKind, | ||
| dataKey: string, | ||
|
|
@@ -34,7 +47,7 @@ export class EdgeFeatureStore implements LDFeatureStore { | |
| this._logger.debug(`Requesting ${dataKey} from ${this._rootKey}.${kindKey}`); | ||
|
|
||
| try { | ||
| const i = await this._edgeProvider.get(this._rootKey); | ||
| const i = await this._getKVData(); | ||
|
|
||
| if (!i) { | ||
| throw new Error(`${this._rootKey}.${kindKey} is not found in KV.`); | ||
|
|
@@ -66,7 +79,7 @@ export class EdgeFeatureStore implements LDFeatureStore { | |
| const kindKey = namespace === 'features' ? 'flags' : namespace; | ||
| this._logger.debug(`Requesting all from ${this._rootKey}.${kindKey}`); | ||
| try { | ||
| const i = await this._edgeProvider.get(this._rootKey); | ||
| const i = await this._getKVData(); | ||
| if (!i) { | ||
| throw new Error(`${this._rootKey}.${kindKey} is not found in KV.`); | ||
| } | ||
|
|
@@ -93,7 +106,7 @@ export class EdgeFeatureStore implements LDFeatureStore { | |
| } | ||
|
|
||
| async initialized(callback: (isInitialized: boolean) => void = noop): Promise<void> { | ||
| const config = await this._edgeProvider.get(this._rootKey); | ||
| const config = await this._getKVData(); | ||
| const result = config !== null; | ||
| this._logger.debug(`Is ${this._rootKey} initialized? ${result}`); | ||
| callback(result); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| import { LDOptions as LDOptionsCommon } from '@launchdarkly/js-server-sdk-common'; | ||
| import { LDOptions as LDOptionsCommon, TypeValidators } from '@launchdarkly/js-server-sdk-common'; | ||
|
|
||
| /** | ||
| * The Launchdarkly Fastly Compute SDK configuration options. | ||
|
|
@@ -16,17 +16,23 @@ export type FastlySDKOptions = Pick<LDOptionsCommon, 'logger' | 'sendEvents' | ' | |
| */ | ||
| export type LDOptionsInternal = FastlySDKOptions & Pick<LDOptionsCommon, 'featureStore'>; | ||
|
|
||
| const validateOptions = (sdkKey: string, options: LDOptionsInternal) => { | ||
| const validators = { | ||
| clientSideId: TypeValidators.String, | ||
| featureStore: TypeValidators.ObjectOrFactory, | ||
| logger: TypeValidators.Object, | ||
| }; | ||
|
|
||
| const validateOptions = (clientSideId: string, options: LDOptionsInternal) => { | ||
| const { eventsBackendName, featureStore, logger, sendEvents, ...rest } = options; | ||
| if (!sdkKey) { | ||
| throw new Error('You must configure the client with a client key'); | ||
| if (!clientSideId || !validators.clientSideId.is(clientSideId)) { | ||
| throw new Error('You must configure the client with a client-side id'); | ||
| } | ||
|
|
||
| if (!featureStore || typeof featureStore !== 'object' || !featureStore.get) { | ||
| if (!featureStore || !validators.featureStore.is(featureStore)) { | ||
| throw new Error('You must configure the client with a feature store'); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is the logic used by the type validators for the feature store. https://github.com/launchdarkly/js-core/blob/main/packages/shared/common/src/validators.ts#L22
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. I started down this road and it seems promising. I have to sign off soon but I should have your suggestion in first thing tomorrow.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just updated it to use type validators. Thanks for pointing this out. |
||
|
|
||
| if (!logger) { | ||
| if (!logger || !validators.logger.is(logger)) { | ||
| throw new Error('You must configure the client with a logger'); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the logger is optional on most SDKs.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are always setting a logger here if not specified so the additional validation in validateOptions is maybe a little redundant. |
||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.