@soba-so/react 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,7 +32,7 @@ export async function POST() {
32
32
  authorization: `Bearer ${process.env.SOBA_KEY}`,
33
33
  "content-type": "application/json",
34
34
  },
35
- body: JSON.stringify({ user: session.user.id }),
35
+ body: JSON.stringify({ user: sobaUserId(session.user.username) }),
36
36
  })
37
37
  return Response.json(await res.json())
38
38
  }
@@ -42,6 +42,12 @@ That is the whole integration. `user` is the same id you pass on a run, which is
42
42
  what makes the person whose machine this is and the person a run is attributed to
43
43
  the same row.
44
44
 
45
+ It also has to outlive your database. `session.user.id` is usually a key minted
46
+ at sign-up, so a reset or a move turns one person into two — holding the machine
47
+ under the old id, on metered compute under the new one. `sobaUserId`, from the
48
+ server-only subpath `@soba-so/sdk/identity`, derives a stable id from something
49
+ that survives: see [Identifying users](https://soba.so/docs/identity).
50
+
45
51
  The session lives ten minutes. A settings page left open for an hour is the
46
52
  ordinary case, so the provider refreshes it before it expires **and** heals a
47
53
  request that meets a dead one: a 401 mints a new session and retries once, for
@@ -106,11 +112,12 @@ Point the provider at a route that does it, and the hook will read the stream:
106
112
  ```ts
107
113
  // app/api/soba/run/route.ts
108
114
  import { Soba } from "@soba-so/sdk"
115
+ import { sobaUserId } from "@soba-so/sdk/identity"
109
116
 
110
117
  export async function POST(request: Request) {
111
118
  const session = await auth()
112
119
  const soba = new Soba({ apiKey: process.env.SOBA_KEY })
113
- const run = await soba.run({ user: session.user.id, ...(await request.json()) })
120
+ const run = await soba.run({ user: sobaUserId(session.user.username), ...(await request.json()) })
114
121
  return new Response(toSSE(run), { headers: { "content-type": "text/event-stream" } })
115
122
  }
116
123
  ```
@@ -15,14 +15,17 @@ export interface SobaProviderProps {
15
15
  * const res = await fetch("https://www.soba.so/v1/end_users/session", {
16
16
  * method: "POST",
17
17
  * headers: { authorization: `Bearer ${process.env.SOBA_KEY}` },
18
- * body: JSON.stringify({ user: session.user.id }),
18
+ * body: JSON.stringify({ user: sobaUserId(session.user.username) }),
19
19
  * })
20
20
  * return Response.json(await res.json())
21
21
  * ```
22
22
  */
23
23
  sessionEndpoint?: string;
24
24
  /** The same id you pass as `user` on a run. It is what makes the person whose
25
- * machine this is and the person a run is attributed to the same row. */
25
+ * machine this is and the person a run is attributed to the same row — and
26
+ * it has to outlive your database, or a reset splits that person in two.
27
+ * `sobaUserId` from `@soba-so/sdk/identity` derives one; the reasoning is at
28
+ * https://soba.so/docs/identity. */
26
29
  user?: string;
27
30
  /** Your route that starts a run with `@soba-so/sdk` and forwards the stream. */
28
31
  runEndpoint?: string;
package/dist/context.d.ts CHANGED
@@ -20,9 +20,16 @@ export interface ComputeState {
20
20
  error: Error | null;
21
21
  refresh(): Promise<void>;
22
22
  }
23
- /** Why the flow was opened, carried into the panel's opening words. A person
24
- * whose laptop went to sleep should not be sold the idea from scratch. */
25
- export type ConnectReason = "payment_required" | "no_compute" | "manual";
23
+ /**
24
+ * Why the flow was opened, carried into the panel's opening words. A person
25
+ * whose laptop went to sleep should not be sold the idea from scratch.
26
+ *
27
+ * `pair` is the one that is not about words: it says the caller is ALREADY
28
+ * showing the steady state — the panel under `<ConnectButton />` — so the
29
+ * sheet must open on the chooser rather than repeating it. The other three
30
+ * leave where it opens to the panel.
31
+ */
32
+ export type ConnectReason = "payment_required" | "no_compute" | "manual" | "pair";
26
33
  export interface ConnectState {
27
34
  /** Your app's name, as the person connecting will see it. */
28
35
  app: {