Skip to content

Commit 9886804

Browse files
authored
Add new reflag integration - bucket rebrand (#977)
* Add new reflag integration - bucket rebrand * Add bun.lock * Add changeset
1 parent a83d1d5 commit 9886804

File tree

12 files changed

+466
-0
lines changed

12 files changed

+466
-0
lines changed

.changeset/happy-cases-guess.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@gitbook/integration-reflag': minor
3+
---
4+
5+
Publish reflag integration (fka bucketco)

bun.lock

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,19 @@
467467
"@gitbook/tsconfig": "workspace:*",
468468
},
469469
},
470+
"integrations/reflag": {
471+
"name": "@gitbook/integration-reflag",
472+
"version": "0.3.3",
473+
"dependencies": {
474+
"@gitbook/runtime": "*",
475+
"itty-router": "^5.0.18",
476+
},
477+
"devDependencies": {
478+
"@cloudflare/workers-types": "*",
479+
"@gitbook/cli": "workspace:*",
480+
"@gitbook/tsconfig": "workspace:*",
481+
},
482+
},
470483
"integrations/reo": {
471484
"name": "@gitbook/integration-reo.dev",
472485
"version": "0.5.0",
@@ -1059,6 +1072,8 @@
10591072

10601073
"@gitbook/integration-posthog": ["@gitbook/integration-posthog@workspace:integrations/posthog"],
10611074

1075+
"@gitbook/integration-reflag": ["@gitbook/integration-reflag@workspace:integrations/reflag"],
1076+
10621077
"@gitbook/integration-reo.dev": ["@gitbook/integration-reo.dev@workspace:integrations/reo"],
10631078

10641079
"@gitbook/integration-runkit": ["@gitbook/integration-runkit@workspace:integrations/runkit"],
9.39 KB
Loading
273 KB
Loading
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: reflag
2+
title: Reflag
3+
script: src/index.ts
4+
description: Sync your GitBook site’s schema with Reflag to deliver adaptive experiences to users.
5+
summary: |
6+
# Overview
7+
8+
This integration allows you to sync your GitBook site’s schema with feature flags from Reflag in order to bring user data into content allowing you to create adaptive content experiences.
9+
10+
# How it works
11+
12+
The integration automatically synchronizes your GitBook site schema with the feature flags defined in Reflag. Any changes made in Reflag will be reflected in your site's schema.
13+
14+
# Configure
15+
16+
To configure the integration, you need to connect your GitBook site to your Reflag account by providing your Reflag secret key. Once connected, you can manage your feature flags in Reflag, and they will be automatically reflected in your GitBook site schema.
17+
icon: ./assets/icon.png
18+
previewImages:
19+
- ./assets/preview.png
20+
scopes:
21+
- site:metadata:read
22+
- site:views:read
23+
- site:adaptive:read
24+
- site:adaptive:write
25+
visibility: public
26+
organization: gitbook
27+
configurations:
28+
site:
29+
componentId: config
30+
secrets: {}
31+
target: site

integrations/reflag/package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "@gitbook/integration-reflag",
3+
"version": "0.3.3",
4+
"private": true,
5+
"scripts": {
6+
"typecheck": "tsc --noEmit",
7+
"publish-integrations-staging": "gitbook publish .",
8+
"check": "gitbook check",
9+
"publish-integrations": "gitbook publish ."
10+
},
11+
"dependencies": {
12+
"@gitbook/runtime": "*",
13+
"itty-router": "^5.0.18"
14+
},
15+
"devDependencies": {
16+
"@gitbook/cli": "workspace:*",
17+
"@gitbook/tsconfig": "workspace:*",
18+
"@cloudflare/workers-types": "*"
19+
}
20+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { createComponent, ExposableError } from '@gitbook/runtime';
2+
import {
3+
ReflagAction,
4+
ReflagProps,
5+
ReflagRuntimeContext,
6+
ReflagSiteInstallationConfiguration,
7+
ReflagState,
8+
} from './types';
9+
import { assertInstallation, assertSiteInstallation } from './utils';
10+
import { GitBookAPI } from '@gitbook/api';
11+
12+
export const configBlock = createComponent<
13+
ReflagProps,
14+
ReflagState,
15+
ReflagAction,
16+
ReflagRuntimeContext
17+
>({
18+
componentId: 'config',
19+
initialState: (props) => {
20+
const siteInstallation = props.siteInstallation;
21+
return {
22+
secret_key: siteInstallation.configuration?.secret_key || '',
23+
};
24+
},
25+
action: async (element, action, context) => {
26+
switch (action.action) {
27+
case 'save.config':
28+
const { api, environment } = context;
29+
30+
const siteInstallation = assertSiteInstallation(environment);
31+
32+
const secretKey = element.state.secret_key;
33+
if (typeof secretKey !== 'string' || !secretKey) {
34+
throw new ExposableError(
35+
'Incomplete configuration: missing Reflag environment secret key',
36+
);
37+
}
38+
39+
const configurationBody: ReflagSiteInstallationConfiguration = {
40+
secret_key: secretKey,
41+
};
42+
43+
await api.integrations.updateIntegrationSiteInstallation(
44+
siteInstallation.integration,
45+
siteInstallation.installation,
46+
siteInstallation.site,
47+
{
48+
configuration: {
49+
...configurationBody,
50+
},
51+
},
52+
);
53+
54+
return { type: 'complete' };
55+
}
56+
},
57+
render: async (element, context) => {
58+
const installation = assertInstallation(context.environment);
59+
const siteInstallation = assertSiteInstallation(context.environment);
60+
const installationAPIToken = context.environment.apiTokens.installation;
61+
62+
if (!installationAPIToken) {
63+
throw new Error(`Expected installation API token to be set in the environment`);
64+
}
65+
66+
const api = new GitBookAPI({
67+
userAgent: context.api.userAgent,
68+
endpoint: context.environment.apiEndpoint,
69+
authToken: installationAPIToken,
70+
});
71+
72+
const { data: site } = await api.orgs.getSiteById(
73+
installation.target.organization,
74+
siteInstallation.site,
75+
);
76+
const isAdaptiveContentEnabled = Boolean(site.adaptiveContent?.enabled);
77+
78+
return (
79+
<configuration>
80+
{isAdaptiveContentEnabled ? (
81+
<box>
82+
<vstack>
83+
<input
84+
label="Secret key"
85+
hint={
86+
<text>
87+
The secret key from your Reflag{' '}
88+
<link
89+
target={{
90+
url: 'https://app.reflag.com/envs/current/settings/app-environments',
91+
}}
92+
>
93+
environment settings.
94+
</link>
95+
</text>
96+
}
97+
element={<textinput state="secret_key" placeholder="Secret key" />}
98+
/>
99+
<input
100+
label=""
101+
hint=""
102+
element={
103+
<button
104+
style="primary"
105+
disabled={false}
106+
label="Save"
107+
tooltip="Save configuration"
108+
onPress={{
109+
action: 'save.config',
110+
}}
111+
/>
112+
}
113+
/>
114+
</vstack>
115+
</box>
116+
) : (
117+
<input
118+
label="Enable Adaptive Content"
119+
hint="To use the Reflag integration, you need to enable Adaptive Content in your site audience settings."
120+
element={
121+
<button
122+
label="Enable"
123+
onPress={{
124+
action: '@ui.url.open',
125+
url: `${site.urls.app}/settings/audience`,
126+
}}
127+
/>
128+
}
129+
/>
130+
)}
131+
</configuration>
132+
);
133+
},
134+
});

integrations/reflag/src/index.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { createIntegration } from '@gitbook/runtime';
2+
import { assertInstallation, assertSiteInstallation } from './utils';
3+
4+
import { handleSyncAdaptiveSchema, SYNC_ADAPTIVE_SCHEMA_SCHEDULE_SECONDS } from './schema';
5+
import { configBlock } from './components';
6+
7+
export default createIntegration({
8+
components: [configBlock],
9+
events: {
10+
site_view: async (event, context) => {
11+
const installation = assertInstallation(context.environment);
12+
const siteInstallation = assertSiteInstallation(context.environment);
13+
14+
// If the last sync attempt was more than an hour ago, we try to sync the adaptive schema
15+
const shouldSyncAdaptiveSchema =
16+
siteInstallation.configuration.lastSyncAttemptAt &&
17+
siteInstallation.configuration.lastSyncAttemptAt <
18+
Date.now() - SYNC_ADAPTIVE_SCHEMA_SCHEDULE_SECONDS * 1000;
19+
20+
if (shouldSyncAdaptiveSchema) {
21+
await handleSyncAdaptiveSchema(context, installation, siteInstallation);
22+
}
23+
},
24+
site_installation_setup: async (event, context) => {
25+
const installation = assertInstallation(context.environment);
26+
const siteInstallation = assertSiteInstallation(context.environment);
27+
28+
if (!siteInstallation.configuration.lastSyncAttemptAt) {
29+
// If this is the first setup, we sync the adaptive schema immediately
30+
await handleSyncAdaptiveSchema(context, installation, siteInstallation);
31+
}
32+
},
33+
},
34+
});

0 commit comments

Comments
 (0)