Skip to content

Commit 32f2efb

Browse files
masnwilliamsclaude
andcommitted
Merge origin/main into fumadocs-migration
Brings in 11 commits from main (#479-#494): terraform integration page, durable MCP/resource contracts, viewport/kiosk updates, Aug 7 changelog, Claude directory connector, and an API-spec refresh. Two manual bits: main's new integrations/terraform.mdx placed at the migrated content/docs path (nav already references it); and main's committed specs/openapi.documented.yml dropped — the fumadocs setup fetches the spec live from Stainless (lib/openapi.ts), so a committed copy is an unused Mintlify-era artifact. The API reference already reflects the #486 spec refresh via that URL. Everything else auto-merged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2 parents 8f795ac + 94f398e commit 32f2efb

24 files changed

Lines changed: 453 additions & 267 deletions

‎content/docs/auth/credentials.mdx‎

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -311,17 +311,19 @@ const auth = await kernel.auth.connections.create({
311311

312312
const login = await kernel.auth.connections.login(auth.id);
313313

314-
// Poll until password is needed
315-
let state = await kernel.auth.connections.retrieve(auth.id);
316-
while (state.flow_status === 'IN_PROGRESS') {
317-
if (state.flow_step === 'AWAITING_INPUT' && state.discovered_fields?.length) {
314+
// Stream state changes and submit the missing password
315+
const authEvents = await kernel.auth.connections.follow(auth.id);
316+
for await (const event of authEvents) {
317+
if (
318+
event.event === 'managed_auth_state' &&
319+
event.flow_step === 'AWAITING_INPUT' &&
320+
event.discovered_fields?.length
321+
) {
318322
// Only password field will be pending (email auto-filled from credential)
319323
await kernel.auth.connections.submit(auth.id, {
320324
fields: { password: 'user-provided-password' }
321325
});
322326
}
323-
await new Promise(r => setTimeout(r, 2000));
324-
state = await kernel.auth.connections.retrieve(auth.id);
325327
}
326328
// TOTP auto-submitted from credential → SUCCESS
327329
```
@@ -342,17 +344,19 @@ auth = await kernel.auth.connections.create(
342344

343345
login = await kernel.auth.connections.login(auth.id)
344346

345-
# Poll until password is needed
346-
state = await kernel.auth.connections.retrieve(auth.id)
347-
while state.flow_status == "IN_PROGRESS":
348-
if state.flow_step == "AWAITING_INPUT" and state.discovered_fields:
347+
# Stream state changes and submit the missing password
348+
auth_events = await kernel.auth.connections.follow(auth.id)
349+
async for event in auth_events:
350+
if (
351+
event.event == "managed_auth_state"
352+
and event.flow_step == "AWAITING_INPUT"
353+
and event.discovered_fields
354+
):
349355
# Only password field will be pending (email auto-filled from credential)
350356
await kernel.auth.connections.submit(
351357
auth.id,
352358
fields={"password": "user-provided-password"},
353359
)
354-
await asyncio.sleep(2)
355-
state = await kernel.auth.connections.retrieve(auth.id)
356360
# TOTP auto-submitted from credential → SUCCESS
357361
```
358362

@@ -390,13 +394,11 @@ if err != nil {
390394
}
391395
_ = login
392396

393-
// Poll until password is needed
394-
state, err := client.Auth.Connections.Get(ctx, auth.ID)
395-
if err != nil {
396-
panic(err)
397-
}
398-
for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
399-
if state.FlowStep == kernel.ManagedAuthFlowStepAwaitingInput && len(state.DiscoveredFields) > 0 {
397+
// Stream state changes and submit the missing password
398+
authEvents := client.Auth.Connections.FollowStreaming(ctx, auth.ID)
399+
for authEvents.Next() {
400+
event := authEvents.Current()
401+
if event.Event == "managed_auth_state" && event.FlowStep == "AWAITING_INPUT" && len(event.DiscoveredFields) > 0 {
400402
// Only password field will be pending (email auto-filled from credential)
401403
_, err := client.Auth.Connections.Submit(ctx, auth.ID, kernel.AuthConnectionSubmitParams{
402404
SubmitFieldsRequest: kernel.SubmitFieldsRequestParam{
@@ -407,12 +409,9 @@ for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
407409
panic(err)
408410
}
409411
}
410-
411-
time.Sleep(2 * time.Second)
412-
state, err = client.Auth.Connections.Get(ctx, auth.ID)
413-
if err != nil {
414-
panic(err)
415-
}
412+
}
413+
if err := authEvents.Err(); err != nil {
414+
panic(err)
416415
}
417416
// TOTP auto-submitted from credential → SUCCESS
418417
```

‎content/docs/auth/hosted-ui.mdx‎

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -92,57 +92,60 @@ The user will:
9292
2. Enter their credentials
9393
3. Complete 2FA if needed
9494

95-
### 4. Poll for Completion
95+
### 4. Stream until completion
9696

97-
On your backend, poll until authentication completes:
97+
On your backend, follow the connection's SSE stream until authentication completes:
9898

9999
<CodeGroup>
100100
```typescript TypeScript
101-
let state = await kernel.auth.connections.retrieve(auth.id);
101+
const events = await kernel.auth.connections.follow(auth.id);
102+
let finalState;
102103

103-
while (state.flow_status === 'IN_PROGRESS') {
104-
await new Promise(r => setTimeout(r, 2000));
105-
state = await kernel.auth.connections.retrieve(auth.id);
104+
for await (const event of events) {
105+
if (event.event === 'managed_auth_state') {
106+
finalState = event;
107+
}
106108
}
107109

108-
if (state.status === 'AUTHENTICATED') {
110+
if (finalState?.flow_status === 'SUCCESS') {
109111
console.log('Authentication successful!');
110112
}
111113
```
112114

113115
```python Python
114-
state = await kernel.auth.connections.retrieve(auth.id)
116+
events = await kernel.auth.connections.follow(auth.id)
117+
final_state = None
115118

116-
while state.flow_status == "IN_PROGRESS":
117-
await asyncio.sleep(2)
118-
state = await kernel.auth.connections.retrieve(auth.id)
119+
async for event in events:
120+
if event.event == "managed_auth_state":
121+
final_state = event
119122

120-
if state.status == "AUTHENTICATED":
123+
if final_state and final_state.flow_status == "SUCCESS":
121124
print("Authentication successful!")
122125
```
123126

124127
```go Go
125-
state, err := client.Auth.Connections.Get(ctx, auth.ID)
126-
if err != nil {
127-
panic(err)
128-
}
128+
events := client.Auth.Connections.FollowStreaming(ctx, auth.ID)
129+
authenticated := false
129130

130-
for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
131-
time.Sleep(2 * time.Second)
132-
state, err = client.Auth.Connections.Get(ctx, auth.ID)
133-
if err != nil {
134-
panic(err)
131+
for events.Next() {
132+
event := events.Current()
133+
if event.Event == "managed_auth_state" && event.FlowStatus == "SUCCESS" {
134+
authenticated = true
135135
}
136136
}
137+
if err := events.Err(); err != nil {
138+
panic(err)
139+
}
137140

138-
if state.Status == kernel.ManagedAuthStatusAuthenticated {
141+
if authenticated {
139142
fmt.Println("Authentication successful!")
140143
}
141144
```
142145
</CodeGroup>
143146

144147
<Info>
145-
Poll every 2 seconds. The session expires after 20 minutes if not completed, and the flow times out after 10 minutes of waiting for user input.
148+
The SSE stream closes automatically when the flow succeeds, fails, expires, or is canceled. The session expires after 20 minutes if not completed, and the flow times out after 10 minutes of waiting for user input.
146149
</Info>
147150

148151
### 5. Use the Profile
@@ -216,14 +219,16 @@ const login = await kernel.auth.connections.login(auth.id);
216219
// Send user to hosted page
217220
console.log('Login URL:', login.hosted_url);
218221

219-
// Poll for completion
220-
let state = await kernel.auth.connections.retrieve(auth.id);
221-
while (state.flow_status === 'IN_PROGRESS') {
222-
await new Promise(r => setTimeout(r, 2000));
223-
state = await kernel.auth.connections.retrieve(auth.id);
222+
// Stream state changes until the flow completes
223+
const events = await kernel.auth.connections.follow(auth.id);
224+
let finalState;
225+
for await (const event of events) {
226+
if (event.event === 'managed_auth_state') {
227+
finalState = event;
228+
}
224229
}
225230

226-
if (state.status === 'AUTHENTICATED') {
231+
if (finalState?.flow_status === 'SUCCESS') {
227232
const browser = await kernel.browsers.create({
228233
profile: { name: 'doordash-user-123' },
229234
stealth: true,
@@ -235,10 +240,9 @@ if (state.status === 'AUTHENTICATED') {
235240
```
236241

237242
```python Python
238-
from kernel import Kernel
239-
import asyncio
243+
from kernel import AsyncKernel
240244

241-
kernel = Kernel()
245+
kernel = AsyncKernel()
242246

243247
# Create connection
244248
auth = await kernel.auth.connections.create(
@@ -252,13 +256,14 @@ login = await kernel.auth.connections.login(auth.id)
252256
# Send user to hosted page
253257
print(f"Login URL: {login.hosted_url}")
254258

255-
# Poll for completion
256-
state = await kernel.auth.connections.retrieve(auth.id)
257-
while state.flow_status == "IN_PROGRESS":
258-
await asyncio.sleep(2)
259-
state = await kernel.auth.connections.retrieve(auth.id)
259+
# Stream state changes until the flow completes
260+
events = await kernel.auth.connections.follow(auth.id)
261+
final_state = None
262+
async for event in events:
263+
if event.event == "managed_auth_state":
264+
final_state = event
260265

261-
if state.status == "AUTHENTICATED":
266+
if final_state and final_state.flow_status == "SUCCESS":
262267
browser = await kernel.browsers.create(
263268
profile={"name": "doordash-user-123"},
264269
stealth=True,
@@ -274,7 +279,6 @@ package main
274279
import (
275280
"context"
276281
"fmt"
277-
"time"
278282

279283
"github.com/kernel/kernel-go-sdk"
280284
"github.com/kernel/kernel-go-sdk/shared"
@@ -304,20 +308,20 @@ func main() {
304308
// Send user to hosted page
305309
fmt.Println("Login URL:", login.HostedURL)
306310

307-
// Poll for completion
308-
state, err := client.Auth.Connections.Get(ctx, auth.ID)
309-
if err != nil {
310-
panic(err)
311-
}
312-
for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
313-
time.Sleep(2 * time.Second)
314-
state, err = client.Auth.Connections.Get(ctx, auth.ID)
315-
if err != nil {
316-
panic(err)
311+
// Stream state changes until the flow completes
312+
events := client.Auth.Connections.FollowStreaming(ctx, auth.ID)
313+
authenticated := false
314+
for events.Next() {
315+
event := events.Current()
316+
if event.Event == "managed_auth_state" && event.FlowStatus == "SUCCESS" {
317+
authenticated = true
317318
}
318319
}
320+
if err := events.Err(); err != nil {
321+
panic(err)
322+
}
319323

320-
if state.Status == kernel.ManagedAuthStatusAuthenticated {
324+
if authenticated {
321325
browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
322326
Profile: shared.BrowserProfileParam{
323327
Name: kernel.String("doordash-user-123"),

‎content/docs/auth/overview.mdx‎

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,17 @@ const login = await kernel.auth.connections.login(auth.id);
5252
// Send user to login page
5353
console.log('Login URL:', login.hosted_url);
5454

55-
// Poll until complete
56-
let state = await kernel.auth.connections.retrieve(auth.id);
57-
while (state.flow_status === 'IN_PROGRESS') {
58-
await new Promise(r => setTimeout(r, 2000));
59-
state = await kernel.auth.connections.retrieve(auth.id);
55+
// Stream state changes until the flow completes
56+
const events = await kernel.auth.connections.follow(auth.id);
57+
let finalState;
58+
59+
for await (const event of events) {
60+
if (event.event === 'managed_auth_state') {
61+
finalState = event;
62+
}
6063
}
6164

62-
if (state.status === 'AUTHENTICATED') {
65+
if (finalState?.flow_status === 'SUCCESS') {
6366
console.log('Authenticated!');
6467
}
6568
```
@@ -70,13 +73,15 @@ login = await kernel.auth.connections.login(auth.id)
7073
# Send user to login page
7174
print(f"Login URL: {login.hosted_url}")
7275

73-
# Poll until complete
74-
state = await kernel.auth.connections.retrieve(auth.id)
75-
while state.flow_status == "IN_PROGRESS":
76-
await asyncio.sleep(2)
77-
state = await kernel.auth.connections.retrieve(auth.id)
76+
# Stream state changes until the flow completes
77+
events = await kernel.auth.connections.follow(auth.id)
78+
final_state = None
7879

79-
if state.status == "AUTHENTICATED":
80+
async for event in events:
81+
if event.event == "managed_auth_state":
82+
final_state = event
83+
84+
if final_state and final_state.flow_status == "SUCCESS":
8085
print("Authenticated!")
8186
```
8287

@@ -89,20 +94,21 @@ if err != nil {
8994
// Send user to login page
9095
fmt.Println("Login URL:", login.HostedURL)
9196

92-
// Poll until complete
93-
state, err := client.Auth.Connections.Get(ctx, auth.ID)
94-
if err != nil {
95-
panic(err)
96-
}
97-
for state.FlowStatus == kernel.ManagedAuthFlowStatusInProgress {
98-
time.Sleep(2 * time.Second)
99-
state, err = client.Auth.Connections.Get(ctx, auth.ID)
100-
if err != nil {
101-
panic(err)
97+
// Stream state changes until the flow completes
98+
events := client.Auth.Connections.FollowStreaming(ctx, auth.ID)
99+
authenticated := false
100+
101+
for events.Next() {
102+
event := events.Current()
103+
if event.Event == "managed_auth_state" && event.FlowStatus == "SUCCESS" {
104+
authenticated = true
102105
}
103106
}
107+
if err := events.Err(); err != nil {
108+
panic(err)
109+
}
104110

105-
if state.Status == kernel.ManagedAuthStatusAuthenticated {
111+
if authenticated {
106112
fmt.Println("Authenticated!")
107113
}
108114
```

‎content/docs/auth/profiles.mdx‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,26 @@ func main() {
6969
```
7070
</CodeGroup>
7171

72+
## Rename a profile
73+
74+
Profiles can be renamed without recreating their stored browser state. The new name must be unique within the project.
75+
76+
<CodeGroup>
77+
```typescript TypeScript
78+
await kernel.profiles.update('profiles-demo', { name: 'checkout-session' });
79+
```
80+
81+
```python Python
82+
kernel.profiles.update("profiles-demo", name="checkout-session")
83+
```
84+
85+
```go Go
86+
_, err := client.Profiles.Update(ctx, "profiles-demo", kernel.ProfileUpdateParams{
87+
Name: "checkout-session",
88+
})
89+
```
90+
</CodeGroup>
91+
7292
## 2. Start a browser session using the profile and save changes
7393

7494
After creating the profile, reference it by its `name` or `id` when creating a browser.

0 commit comments

Comments
 (0)