Skip to content

Commit 508b7d8

Browse files
SpeedyCodermiraan
andauthored
feat: use latest hypertune version (#944)
### Description Use latest Hypertune sdk version and small tweaks to the recommended setup. ### Demo URL https://feature-flag-hypertune-alpha.vercel.app/ ### Type of Change - [ ] New Example - [ X ] Example updates (Bug fixes, new features, etc.) - [ ] Other (changes to the codebase, but not to examples) --------- Co-authored-by: Miraan Tabrez <[email protected]>
1 parent 49821a0 commit 508b7d8

File tree

7 files changed

+138
-111
lines changed

7 files changed

+138
-111
lines changed

edge-middleware/feature-flag-hypertune/app/layout.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type { ReactNode } from 'react'
22
import { Layout, getMetadata } from '@vercel/examples-ui'
33
import { VercelToolbar } from '@vercel/toolbar/next'
4-
import { HypertuneSourceProvider } from '../generated/hypertune.react'
4+
import { HypertuneProvider } from '../generated/hypertune.react'
55
import '@vercel/examples-ui/globals.css'
6+
import getHypertune from '../lib/getHypertune'
67

78
export const metadata = getMetadata({
89
title: 'feature-flag-hypertune',
@@ -14,9 +15,18 @@ export const runtime = 'edge'
1415
export default async function RootLayout({
1516
children,
1617
}: Readonly<{ children: ReactNode }>) {
18+
const hypertune = await getHypertune()
19+
20+
const serverDehydratedState = hypertune.dehydrate()
21+
const serverRootArgs = hypertune.getRootArgs()
22+
1723
return (
18-
<HypertuneSourceProvider
19-
createSourceOptions={{ token: process.env.NEXT_PUBLIC_HYPERTUNE_TOKEN! }}
24+
<HypertuneProvider
25+
createSourceOptions={{
26+
token: process.env.NEXT_PUBLIC_HYPERTUNE_TOKEN!,
27+
}}
28+
dehydratedState={serverDehydratedState}
29+
rootArgs={serverRootArgs}
2030
>
2131
<html lang="en">
2232
<body>
@@ -32,6 +42,6 @@ export default async function RootLayout({
3242
</Layout>
3343
</body>
3444
</html>
35-
</HypertuneSourceProvider>
45+
</HypertuneProvider>
3646
)
3747
}

edge-middleware/feature-flag-hypertune/app/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react'
22
import { Text, Page, Link, List } from '@vercel/examples-ui'
3+
import ClientComponent from '../components/ClientComponent'
34
import ServerComponent from '../components/ServerComponent'
4-
import ClientComponentWrapper from '../components/ClientComponentWrapper'
55

66
export const metadata = {
77
title: 'Vercel x Hypertune example',
@@ -37,7 +37,7 @@ export default async function Home() {
3737

3838
<section className="flex flex-col gap-4">
3939
<ServerComponent />
40-
<ClientComponentWrapper />
40+
<ClientComponent />
4141
<Text>
4242
Once you&apos;ve deployed this project, open the{' '}
4343
<Link href="https://app.hypertune.com/" target="_blank">

edge-middleware/feature-flag-hypertune/components/ClientComponentWrapper.tsx

Lines changed: 0 additions & 28 deletions
This file was deleted.

edge-middleware/feature-flag-hypertune/generated/hypertune.react.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export function HypertuneSourceProvider({
5252
remoteLogging: {
5353
mode: typeof window === 'undefined' ? 'off' : undefined,
5454
},
55+
// eslint-disable-next-line @typescript-eslint/no-empty-function
56+
localLogger: typeof window === 'undefined' ? () => {} : undefined,
5557
...createSourceOptions,
5658
}),
5759
// Don't recreate the source even if createSourceOptions changes
@@ -129,14 +131,23 @@ export function HypertuneRootProvider({
129131
}
130132

131133
export function useHypertune(): hypertune.RootNode {
132-
return React.useContext(HypertuneRootContext)
134+
const hypertuneRoot = React.useContext(HypertuneRootContext)
135+
136+
if (!hypertuneRoot.props.context) {
137+
console.warn(
138+
'[Hypertune] Calling `useHypertune` hook outside of the `HypertuneProvider`. Fallback values will be used.'
139+
)
140+
}
141+
return hypertuneRoot
133142
}
134143

135144
export function HypertuneHydrator({
136145
dehydratedState,
146+
rootArgs,
137147
children,
138148
}: {
139149
dehydratedState?: hypertune.DehydratedState | null
150+
rootArgs?: hypertune.RootArgs
140151
children: React.ReactElement | null
141152
}): React.ReactElement | null {
142153
const hypertuneSource = useHypertuneSource()
@@ -145,5 +156,13 @@ export function HypertuneHydrator({
145156
hypertuneSource.hydrate(dehydratedState)
146157
}
147158

159+
if (rootArgs) {
160+
return (
161+
<HypertuneRootProvider rootArgs={rootArgs}>
162+
{children}
163+
</HypertuneRootProvider>
164+
)
165+
}
166+
148167
return children
149168
}

edge-middleware/feature-flag-hypertune/generated/hypertune.ts

Lines changed: 30 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@ import * as sdk from 'hypertune'
44

55
export const queryCode = `query FullQuery{root{exampleFlag}}`
66

7-
export const query = {
8-
Query: {
9-
objectTypeName: 'Query',
10-
selection: {
11-
root: {
12-
fieldArguments: { __isPartialObject__: true },
13-
fieldQuery: {
14-
Root: {
15-
objectTypeName: 'Root',
16-
selection: {
17-
exampleFlag: { fieldArguments: {}, fieldQuery: null },
7+
export const query: sdk.Query<sdk.ObjectValueWithVariables> = {
8+
variableDefinitions: {},
9+
fragmentDefinitions: {},
10+
fieldQuery: {
11+
Query: {
12+
type: 'InlineFragment',
13+
objectTypeName: 'Query',
14+
selection: {
15+
root: {
16+
fieldArguments: { __isPartialObject__: true },
17+
fieldQuery: {
18+
Root: {
19+
type: 'InlineFragment',
20+
objectTypeName: 'Root',
21+
selection: {
22+
exampleFlag: { fieldArguments: {}, fieldQuery: null },
23+
},
1824
},
1925
},
2026
},
@@ -23,57 +29,6 @@ export const query = {
2329
},
2430
}
2531

26-
function mergeQueryAndArgs(
27-
query: sdk.Query<sdk.ObjectValueWithVariables>,
28-
queryArgs: sdk.ObjectValueWithVariables | null,
29-
unwrapObjectArgs = false
30-
): sdk.Query<sdk.ObjectValueWithVariables> {
31-
return Object.fromEntries(
32-
Object.entries(query).map(([objectTypeName, fragment]) => {
33-
const objectArgs = unwrapObjectArgs
34-
? queryArgs &&
35-
queryArgs[objectTypeName] &&
36-
queryArgs[objectTypeName] instanceof Object
37-
? (queryArgs[objectTypeName] as sdk.ObjectValueWithVariables)
38-
: null
39-
: queryArgs
40-
41-
return [
42-
objectTypeName,
43-
{
44-
objectTypeName,
45-
selection: Object.fromEntries(
46-
Object.entries(fragment.selection).map(
47-
([fieldName, { fieldQuery }]) => {
48-
const fieldArgs =
49-
objectArgs &&
50-
objectArgs[fieldName] &&
51-
objectArgs[fieldName] instanceof Object
52-
? (objectArgs[fieldName] as sdk.ObjectValueWithVariables)
53-
: null
54-
55-
return [
56-
fieldName,
57-
{
58-
fieldArguments: {
59-
...(fieldArgs && fieldArgs.args
60-
? (fieldArgs.args as sdk.ObjectValueWithVariables)
61-
: {}),
62-
},
63-
fieldQuery: fieldQuery
64-
? mergeQueryAndArgs(fieldQuery, fieldArgs, true)
65-
: null,
66-
},
67-
]
68-
}
69-
)
70-
),
71-
},
72-
]
73-
})
74-
)
75-
}
76-
7732
/**
7833
* @deprecated use '@vercel/flags/providers/hypertune' package instead.
7934
*/
@@ -123,7 +78,7 @@ export type Root = {
12378
const rootFallback = { exampleFlag: false }
12479

12580
export class RootNode extends sdk.Node {
126-
typeName = 'Root' as const
81+
override typeName = 'Root' as const
12782

12883
getRootArgs(): RootArgs {
12984
const { step } = this.props
@@ -134,7 +89,7 @@ export class RootNode extends sdk.Node {
13489

13590
get({ fallback = rootFallback as Root }: { fallback?: Root } = {}): Root {
13691
const getQuery = null
137-
return this.evaluate(getQuery, fallback) as Root
92+
return this.getValue({ query: getQuery, fallback }) as Root
13893
}
13994

14095
/**
@@ -148,7 +103,9 @@ export class RootNode extends sdk.Node {
148103
args?: Rec
149104
fallback: boolean
150105
}): boolean {
151-
const props0 = this.getField('exampleFlag', args)
106+
const props0 = this.getFieldNodeProps('exampleFlag', {
107+
fieldArguments: args,
108+
})
152109
const expression0 = props0.expression
153110

154111
if (expression0 && expression0.type === 'BooleanExpression') {
@@ -177,7 +134,7 @@ export type Rec4 = {
177134
}
178135

179136
export class SourceNode extends sdk.Node {
180-
typeName = 'Query' as const
137+
override typeName = 'Query' as const
181138

182139
get({
183140
args,
@@ -186,12 +143,16 @@ export class SourceNode extends sdk.Node {
186143
args: Rec4
187144
fallback?: Source
188145
}): Source {
189-
const getQuery = mergeQueryAndArgs(query, args)
190-
return this.evaluate(getQuery, fallback) as Source
146+
const getQuery = sdk.mergeFieldQueryAndArgs(
147+
query.fragmentDefinitions,
148+
sdk.getFieldQueryForPath(query.fragmentDefinitions, query.fieldQuery, []),
149+
args
150+
)
151+
return this.getValue({ query: getQuery, fallback }) as Source
191152
}
192153

193154
root({ args }: { args: RootArgs }): RootNode {
194-
const props0 = this.getField('root', args)
155+
const props0 = this.getFieldNodeProps('root', { fieldArguments: args })
195156
const expression0 = props0.expression
196157

197158
if (

edge-middleware/feature-flag-hypertune/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"@vercel/examples-ui": "^2.0.3",
1616
"@vercel/flags": "2.5.1",
1717
"@vercel/toolbar": "^0.1.15",
18-
"hypertune": "2.3.3",
18+
"hypertune": "2.4.0",
1919
"next": "^14.1.4",
2020
"react": "latest",
2121
"react-dom": "latest",
@@ -32,6 +32,7 @@
3232
"eslint-plugin-prettier": "^5.1.3",
3333
"postcss": "^8.4.38",
3434
"prettier": "^3.2.5",
35-
"tailwindcss": "^3.4.3"
35+
"tailwindcss": "^3.4.3",
36+
"turbo": "1.13.4"
3637
}
3738
}

0 commit comments

Comments
 (0)