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!: Support transient identities and traits #240

Merged
merged 26 commits into from
Oct 2, 2024

Conversation

khvn26
Copy link
Member

@khvn26 khvn26 commented Jul 19, 2024

Closes #236.

types.ts Outdated Show resolved Hide resolved
flagsmith-core.ts Outdated Show resolved Hide resolved
flagsmith-core.ts Outdated Show resolved Hide resolved
flagsmith-core.ts Outdated Show resolved Hide resolved
@kyle-ssg
Copy link
Member

Awesome, I can see the tests pass so we must be good on regression. I guess we do need additional tests around this:

  • Matching tests setting transient traits in the same way we do normal
  • Checking we can cache a mix of transient and non-transient traits
  • Checking what happens when we call getFlags after identifying with transient traits (does it still send them over, I guess it should)

utils.ts Outdated Show resolved Hide resolved
@khvn26 khvn26 marked this pull request as ready for review July 23, 2024 17:19
@khvn26 khvn26 requested a review from kyle-ssg July 23, 2024 17:19
@khvn26
Copy link
Member Author

khvn26 commented Jul 23, 2024

@kyle-ssg I've added:

  • Fetch mocks, as discussed in Slack.
  • Tests to ensure proper getFlags behaviour.
  • A test to ensure that the client preserves transient traits correctly.

@khvn26 khvn26 requested a review from novakzaballa July 23, 2024 18:48
@khvn26 khvn26 force-pushed the feat/transient-identities-and-traits branch from 628e45b to e0c9881 Compare July 24, 2024 10:38
test/init.test.ts Outdated Show resolved Hide resolved
@khvn26 khvn26 requested a review from novakzaballa July 24, 2024 14:47
Copy link
Contributor

@novakzaballa novakzaballa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@khvn26 khvn26 changed the title feat: Support transient identities and traits feat!: Support transient identities and traits Aug 6, 2024
package.json Outdated
@@ -8,7 +8,8 @@
"deploy": "npm run build && npm test && cd ./lib/flagsmith/ && npm publish && cd ../../lib/react-native-flagsmith && npm publish && cd ../../lib/flagsmith-es && npm publish",
"deploy:beta": "npm run build && npm test && cd ./lib/flagsmith/ && npm publish --tag beta && cd ../../lib/react-native-flagsmith && npm publish --tag beta && cd ../../lib/flagsmith-es && npm publish --tag beta",
"build": "rollup -c && node ./move-react.js",
"test": "jest --env=jsdom"
"test": "jest --env=jsdom",
"generatetypes": "npm exec quicktype https://raw.githubusercontent.com/Flagsmith/flagsmith/feat/evaluation-context-schema/sdk/evaluation-context.json -- -o evaluation-context.ts --src-lang schema --just-types --prefer-types"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: change branch reference to main after Flagsmith/flagsmith#4414 is merged.

@khvn26
Copy link
Member Author

khvn26 commented Aug 6, 2024

Rewrote the implementation keeping existing interfaces intact and adding support for the evaluationContext: EvaluationContext configuration entry.

@khvn26 khvn26 force-pushed the feat/transient-identities-and-traits branch from e86d808 to 34d9f6a Compare August 8, 2024 15:43
@khvn26
Copy link
Member Author

khvn26 commented Aug 8, 2024

As discussed offline, added transiency support to identify, setTrait and setTraits interfaces.


export type TraitEvaluationContext = {
transient?: boolean;
value: any;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value is actually a IFlagsmithValue, this is important so that people don't send objects.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sorted out for client input.

[property: string]: any;
}

export type TraitEvaluationContext = {
Copy link
Member

@kyle-ssg kyle-ssg Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here we should let people supply just a value or an object. The reason being is that 99% of the time, traits are not transient and would much rather see the following all over my code

traits:{a:1,b:2,c:{value:3, transient: true}}

than

traits:{a:{value:1,transient:false}, b:{}.....}

Also, a lot of people will just blindly send up an object they received from an api or one they've constructed themselves, with this new api they'd have to go through the hassle of converting a key value pair object to what we expect.

Copy link
Member Author

@khvn26 khvn26 Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the following ways forward here:

  1. Modify the common eval context schema to support a union trait type. IMO, this will not improve UX for strictly typed SDKs at all, and the end result will be harder to support.
  2. Add a ClientEvaluationContext type with the union value that will be used in all public interfaces. Envelope the simple trait values internally. Again, more code to support, but slightly more preferable.
  3. Don't do anything with the types but export a utility function for the users to wrap their traits with:
toTraitEvaluationContext(input: { [key: string]: IFlagsmithValue }) => { [key: string]: TraitEvaluationContext }

Copy link
Member

@kyle-ssg kyle-ssg Aug 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essentially I think the following code should work for when (most cases) traits aren't transient

flagsmith.setTraits({ a: 'foo' });
flagsmith.setTrait('a', 'foo');
flagsmith.init({ traits: { a: 'foo' } });

And I guess with evaluationContext

flagsmith.init({ evaluationContext: { identity: { traits: { a:  "foo" } }});

As long as the types reflect that option I'm not that concerned about implementation detail

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason for this other than less code / easier to read is it means that in most cases we wouldn't have to do some form of conversion of existing objects

I'd have to write some code like the following or manually reconstruct an object

const values = { // some object I also want to pass to Flagsmith
    first_name: "Kyle",
    last_name: "Johnson",
};

const updatedValues = Object.entries(values).reduce((acc, [key, value]) => {
    acc[key] = { value };
    return acc;
}, {});

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just so we're on the same page, the old interfaces, including setTraits and setTrait are meant to continue supporting this.

For init and setContext/updateContext, I propose to expose toTraitEvaluationContext adapter function so users can continue to provide a simple object for traits.

So your example snippet will look like:

import { createFlagsmithInstance, toTraitEvaluationContext } from 'flagsmith';


const values = { // some object I also want to pass to Flagsmith
    first_name: "Kyle",
    last_name: "Johnson",
};

const flagsmith = createFlagsmithInstance();

await flagsmith.init(...)

await flagsmith.setContext({ identity: { traits: toTraitEvaluationContext(values) } });

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I'm I fan of this, it would add an export that would need to be documented / is not immediately clear what it does.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If toTraitEvaluationContext is always a safe conversion, we may as well hide this complexity away and let the SDK deal with it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, essentially, we want an option 2 then:

Add a ClientEvaluationContext type with the union value that will be used in all public interfaces. Envelope the simple trait values internally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this sort of pattern feels quite familiar having used lots of SDKs in JS / keeps a basic implementation as terse as possible

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, this is done.

types.d.ts Show resolved Hide resolved
@khvn26 khvn26 requested a review from kyle-ssg August 28, 2024 15:26
package.json Outdated
"test": "jest --env=jsdom"
"build": "npm run generatetypes && rollup -c && node ./move-react.js",
"test": "jest --env=jsdom",
"generatetypes": "npm exec quicktype https://raw.githubusercontent.com/Flagsmith/flagsmith/feat/evaluation-context-schema/sdk/evaluation-context.json -- -o evaluation-context.ts --src-lang schema --just-types --prefer-types --nice-property-names"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't need npm exec since it's a depedency, regardless, this errors for me - same error mentioned here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't get it to work without npm exec. I'm running npm install --include=dev. Is there something I'm missing?

@kyle-ssg kyle-ssg self-requested a review September 17, 2024 16:50
@khvn26 khvn26 force-pushed the feat/transient-identities-and-traits branch from f79543d to bf76b25 Compare September 20, 2024 13:35
@khvn26 khvn26 force-pushed the feat/transient-identities-and-traits branch from 5c71d8c to e915b58 Compare October 1, 2024 13:03
@kyle-ssg kyle-ssg merged commit 3d0e8b8 into main Oct 2, 2024
1 check passed
@kyle-ssg kyle-ssg deleted the feat/transient-identities-and-traits branch October 2, 2024 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support transient identities and traits
3 participants