Skip to content

Commit 408b794

Browse files
authored
Merge branch 'main' into update-plug-sdk-methods
2 parents 2099d32 + 9d1659b commit 408b794

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+5290
-300
lines changed

.cursorrules

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
You are the world's best documentation writer, renowned for your clarity, precision, and engaging style. Every piece of documentation you produce is:
2+
3+
1. Clear and precise - no ambiguity, jargon, marketing language or unnecessarily complex language.
4+
2. Concise—short, direct sentences and paragraphs.
5+
3. Scientifically structured—organized like a research paper or technical white paper, with a logical flow and strict attention to detail.
6+
4. Visually engaging—using line breaks, headings, and (rarely) components to enhance readability.
7+
5. Focused on user success — no marketing language or fluff; just the necessary information.
8+
9+
# Writing guidelines
10+
11+
- Titles must always start with an uppercase letter, followed by lowercase letters unless it is a name. Examples: Getting started, Text to speech, Conversational AI...
12+
- No emojis or icons unless absolutely necessary.
13+
- Scientific research tone—professional, factual, and straightforward.
14+
- Avoid long text blocks. Use short paragraphs and line breaks.
15+
- Do not use marketing/promotional language.
16+
- Be concise, direct, and avoid wordiness.
17+
- Ensure there are well-designed links (if applicable) to take the technical or non-technical reader to the relevant page.
18+
19+
# Page structure
20+
21+
## Components
22+
23+
Use the following components if possible, don't overuse them.
24+
25+
### Accordions
26+
27+
````
28+
<AccordionGroup>
29+
<Accordion title="Option 1">
30+
You can put other components inside Accordions.
31+
```ts
32+
export function generateRandomNumber() {
33+
return Math.random();
34+
}
35+
```
36+
</Accordion>
37+
<Accordion title="Option 2">
38+
This is a second option.
39+
</Accordion>
40+
41+
<Accordion title="Option 3">
42+
This is a third option.
43+
</Accordion>
44+
</AccordionGroup>
45+
````
46+
47+
### Callouts (Tips, Notes, Warnings, etc.)
48+
49+
```
50+
<Tip title="Example Callout" icon="leaf">
51+
This Callout uses a title and a custom icon.
52+
</Tip>
53+
<Note>This adds a note in the content</Note>
54+
<Warning>This raises a warning to watch out for</Warning>
55+
<Error>This indicates a potential error</Error>
56+
<Info>This draws attention to important information</Info>
57+
<Tip>This suggests a helpful tip</Tip>
58+
<Check>This brings us a checked status</Check>
59+
```
60+
61+
### Cards & Card Groups
62+
63+
```
64+
<Card
65+
title='Python'
66+
icon='brands python'
67+
href='https://github.com/fern-api/fern/tree/main/generators/python'
68+
>
69+
View Fern's Python SDK generator.
70+
</Card>
71+
<CardGroup cols={2}>
72+
<Card title="First Card" icon="circle-1">
73+
This is the first card.
74+
</Card>
75+
<Card title="Second Card" icon="circle-2">
76+
This is the second card.
77+
</Card>
78+
<Card title="Third Card" icon="circle-3">
79+
This is the third card.
80+
</Card>
81+
<Card title="Fourth Card" icon="circle-4">
82+
This is the fourth and final card.
83+
</Card>
84+
</CardGroup>
85+
```
86+
87+
### Code snippets
88+
89+
- Always use the focus attribute to highlight the code you want to highlight.
90+
- `maxLines` is optional if it's long.
91+
- `wordWrap` is optional if the full text should wrap and be visible.
92+
93+
```javascript focus={2-4} maxLines=10 wordWrap
94+
console.log('Line 1');
95+
console.log('Line 2');
96+
console.log('Line 3');
97+
console.log('Line 4');
98+
console.log('Line 5');
99+
```
100+
101+
### Code blocks
102+
103+
- Use code blocks for groups of code, especially if there are multiple languages or if it's a code example. Always start with Python as the default.
104+
105+
````
106+
<CodeBlocks>
107+
```javascript title="helloWorld.js"
108+
console.log("Hello World");
109+
````
110+
111+
```python title="hello_world.py"
112+
print('Hello World!')
113+
```
114+
115+
```java title="HelloWorld.java"
116+
class HelloWorld {
117+
public static void main(String[] args) {
118+
System.out.println("Hello, World!");
119+
}
120+
}
121+
```
122+
123+
</CodeBlocks>
124+
```
125+
126+
### Steps (for step-by-step guides)
127+
128+
```
129+
<Steps>
130+
### First Step
131+
Initial instructions.
132+
133+
### Second Step
134+
More instructions.
135+
136+
### Third Step
137+
Final Instructions
138+
</Steps>
139+
140+
```
141+
142+
### Frames
143+
144+
- You must wrap every single image in a frame.
145+
- Every frame must have `background="subtle"`
146+
- Use captions only if the image is not self-explanatory.
147+
- Use ![alt-title](image-url) as opposed to HTML `<img>` tags unless styling.
148+
149+
```
150+
<Frame
151+
caption="Beautiful mountains"
152+
background="subtle"
153+
>
154+
<img src="https://images.pexels.com/photos/1867601.jpeg" alt="Sample photo of mountains" />
155+
</Frame>
156+
157+
```
158+
159+
### Tabs (split up content into different sections)
160+
161+
```
162+
<Tabs>
163+
<Tab title="First Tab">
164+
☝️ Welcome to the content that you can only see inside the first Tab.
165+
</Tab>
166+
<Tab title="Second Tab">
167+
✌️ Here's content that's only inside the second Tab.
168+
</Tab>
169+
<Tab title="Third Tab">
170+
💪 Here's content that's only inside the third Tab.
171+
</Tab>
172+
</Tabs>
173+
174+
```

.github/workflows/changelog.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ jobs:
1111
steps:
1212
- name: Get current date
1313
id: date
14+
env:
15+
GH_TOKEN: ${{ github.token }}
16+
PR_NUMBER: ${{ github.event.number }}
1417
run: |
15-
echo "DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
18+
DATE=$(gh pr view --repo https://github.com/devrev/fern-api-docs ${{ env.PR_NUMBER }} --json createdAt --jq .[] | cut -d 'T' -f 1)
19+
echo "DATE=$DATE" >> $GITHUB_ENV
20+
echo "Date PR opened is ${{ env.DATE }}"
1621
- name: Check out repository content
1722
uses: actions/checkout@v2
1823
with:

.github/workflows/fern-check.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jobs:
2020
registry-url: https://npm.pkg.github.com/
2121
env:
2222
NODE_AUTH_TOKEN: ${{secrets.AUTH_TOKEN}}
23+
2324

2425
- name: Build Navigation
2526
run: |

.github/workflows/preview-docs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jobs:
2222
registry-url: https://npm.pkg.github.com/
2323
env:
2424
NODE_AUTH_TOKEN: ${{secrets.AUTH_TOKEN}}
25+
2526

2627
- name: Install Fern
2728
run: npm install -g fern-api

.github/workflows/publish-docs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
registry-url: https://npm.pkg.github.com/
2222
env:
2323
NODE_AUTH_TOKEN: ${{secrets.AUTH_TOKEN}}
24+
2425

2526
- name: Download Fern
2627
run: npm install -g fern-api

.github/workflows/publish-typescript.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ jobs:
2828
registry-url: https://npm.pkg.github.com/
2929
env:
3030
NODE_AUTH_TOKEN: ${{secrets.AUTH_TOKEN}}
31+
3132

3233
- name: Build Navigation
3334
run: |

changelog.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ def main(vrn, d):
1515
outfile.write(p)
1616
print(f"Wrote prompt to {pr_file}.")
1717

18+
print('Sending request to LLM.')
1819
l = llm_client.get_response(p)
19-
2020
log_file = f"./fern/apis/{vrn}/changelog/{d}.md"
21-
if (l):
21+
if (l) and 'Error' not in l.partition('\n')[0]:
2222
with open(log_file, 'w', encoding="utf-8") as outfile:
23-
outfile.write(l)
23+
outfile.write(llm_client.get_lines_between_tags(l, 'changelog'))
2424
print(f"Wrote log to {log_file}.")
2525
else:
26-
print(f"Failed to generate {log_file}.")
26+
print(f"Failed to generate {log_file}. No response from LLM.")
2727

2828

2929

@@ -32,7 +32,7 @@ def gen_prompt(oasdiff, links, version):
3232
oasdiff = infile.read()
3333

3434
prompt = f"""
35-
Please provide an API changelog for the {version} API from the following OASDiff of OpenAPI spec changes. The output should be in markdown format grouping endpoints by use case/object type. For cases where some schema is modified, please also tell what endpoints it affects. Wherever an endpoint, property, or enum value is mentioned, surround it with backticks (`). Wherever an API is mentioned, include a hyperlink to the corresponding path from `<api_links>` section.
35+
Please provide an API changelog for the {version} API from the following OASDiff of OpenAPI spec changes. The output should be in markdown format grouping endpoints by use case/object type. For cases where some schema is modified, please also tell what endpoints it affects. Wherever an endpoint, property, or enum value is mentioned, surround it with backticks (`). Use only H2 and H3 headings. Wherever an API is mentioned, include a hyperlink to the corresponding path from `<api_links>` section. Place the changelog in a `<changelog>` element in your response so I can parse it out.
3636
3737
<oasdiff>
3838
{oasdiff}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export const Search = () => {
2+
return (
3+
<button
4+
id="fern-search-button"
5+
className="fern-search-bar w-full"
6+
style={{ marginBottom: '8px' }}
7+
onClick={() => {
8+
if ((window as any).plugSDK) {
9+
(window as any).plugSDK.toggleSearchAgent()
10+
}
11+
}}>
12+
<span className="search-placeholder">
13+
<svg
14+
width="1.5em"
15+
height="1.5em"
16+
viewBox="0 0 24 24"
17+
strokeWidth="1.5"
18+
fill="none"
19+
xmlns="http://www.w3.org/2000/svg"
20+
color="currentColor"
21+
className="size-icon-md">
22+
<path
23+
d="M17 17L21 21"
24+
stroke="currentColor"
25+
strokeLinecap="round"
26+
strokeLinejoin="round"></path>
27+
<path
28+
d="M3 11C3 15.4183 6.58172 19 11 19C13.213 19 15.2161 18.1015 16.6644 16.6493C18.1077 15.2022 19 13.2053 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11Z"
29+
stroke="currentColor"
30+
strokeLinecap="round"
31+
strokeLinejoin="round"></path>
32+
</svg>
33+
<span>Search...</span>
34+
</span>
35+
<kbd className="keyboard-shortcut-hint">/</kbd>
36+
</button>
37+
)
38+
}

custom-implementation/src/main.tsx

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import React from 'react'
77

88
import Header from './components/header'
99
import Footer from './components/footer'
10+
11+
import { Search } from './components/search'
1012
import { ThemeSwitch } from './components/theme-switch'
1113

1214
import { getPageData } from './modules/sanity/utils'
@@ -22,16 +24,28 @@ const render = async () => {
2224
*/
2325

2426
const data = await getPageData()
27+
2528
const sidenav = document.querySelector('button.fern-search-bar')
2629
?.parentElement as HTMLElement
2730

2831
const theme = document.getElementsByTagName('html')[0].getAttribute('class')
2932

30-
if (!document.getElementById('theme-switch')) {
33+
if (!document.getElementById('sidenav-header-wrapper')) {
34+
const sidenavHeaderWrapper = document.createElement('div')
35+
sidenavHeaderWrapper.setAttribute('id', 'sidenav-header-wrapper')
36+
sidenav.appendChild(sidenavHeaderWrapper)
37+
38+
const search = document.createElement('div')
39+
search.setAttribute('id', 'search-component')
40+
sidenavHeaderWrapper.appendChild(search)
41+
ReactDOM.render(React.createElement(Search), search)
42+
3143
const wrapper = document.createElement('div')
3244
wrapper.setAttribute('id', 'theme-switch')
33-
sidenav.appendChild(wrapper)
45+
sidenavHeaderWrapper.appendChild(wrapper)
3446
ReactDOM.render(React.createElement(ThemeSwitch), wrapper)
47+
48+
sidenav.replaceWith(sidenavHeaderWrapper)
3549
}
3650

3751
const fernHeaderId = document.getElementById(FERN_CONTENT_WRAPPER_ID)
@@ -92,11 +106,46 @@ const render = async () => {
92106
if (footer) footer.style.display = 'block'
93107
},
94108
)
109+
110+
// Add Plug component directly to body
111+
if (!document.getElementById('plug-platform')) {
112+
const plugScript = document.createElement('script')
113+
plugScript.setAttribute('type', 'text/javascript')
114+
plugScript.setAttribute('id', 'plug-platform')
115+
plugScript.setAttribute('src', 'https://plug-platform.devrev.ai/static/plug.js')
116+
document.body.appendChild(plugScript)
117+
118+
// Initialize Plug SDK after script loads
119+
plugScript.onload = () => {
120+
if ((window as any).plugSDK) {
121+
(window as any).plugSDK?.init?.({
122+
app_id: data?.plug?.id,
123+
enable_session_recording: true,
124+
});
125+
126+
// Wait for the widget to be ready before adding event listeners
127+
(window as any).plugSDK.onEvent((payload: any) => {
128+
if(payload.type === "ON_PLUG_WIDGET_READY") {
129+
// Initialize search agent after widget is ready
130+
(window as any).plugSDK.initSearchAgent();
131+
132+
// Add keyboard shortcut for search agent
133+
document.addEventListener("keydown", function(event) {
134+
// Check if event.key is defined before accessing it
135+
if (event && event.key === "/") {
136+
event.preventDefault();
137+
(window as any).plugSDK.toggleSearchAgent();
138+
}
139+
});
140+
}
141+
});
142+
}
143+
}
144+
}
95145
}
96146

97147
let observations = 0
98148
document.addEventListener('DOMContentLoaded', async () => {
99-
console.log('DOMContentLoaded')
100149
await render()
101150
new MutationObserver(async (e, o) => {
102151
await render()

custom-implementation/src/modules/sanity/utils.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const SANITY_TYPES = {
1515
export const getPageData = async (): Promise<{
1616
header: object
1717
footer: object
18+
plug: { id: string }
1819
}> => {
1920
const header = await CLIENT.fetch(
2021
`*[_type == 'headerV2' && slug.current == 'developer']{
@@ -28,5 +29,11 @@ export const getPageData = async (): Promise<{
2829
}[0]`,
2930
)
3031

31-
return { header, footer }
32+
const plug = await CLIENT.fetch(
33+
`*[_type == 'externalLink' && slug.current == 'devrev-plug-app-id']{
34+
"id": href
35+
}[0]`,
36+
)
37+
38+
return { header, footer, plug }
3239
}

0 commit comments

Comments
 (0)