@soba-so/react 0.0.10 → 0.0.12

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.
@@ -13,3 +13,24 @@ export interface ComputeStatusProps {
13
13
  * these on one page is still one request.
14
14
  */
15
15
  export declare function ComputeStatus({ className }: ComputeStatusProps): import("react").JSX.Element;
16
+ /**
17
+ * THE THREE ANSWERS A COMPUTE SECTION HAS, IN ONE PLACE.
18
+ *
19
+ * "Nothing connected yet." is a claim about somebody's account, and it is only
20
+ * true once the account has been read. While the first poll is in flight, or
21
+ * after it has failed, the honest answer is that we do not know — and saying
22
+ * the empty thing instead tells a person with a paired laptop that it has
23
+ * vanished, during an outage they cannot see and did not cause.
24
+ *
25
+ * SHARED BECAUSE THE BUG WAS THE COPY. Two components drew the same list and
26
+ * only one of them knew about these two states: `<ComputeStatus />` had the
27
+ * rule, `<ConnectCompute />` — the one most apps actually place, because it
28
+ * brings the control with it — did not, so the whole product's most important
29
+ * status line was the one that lied when the network was down. Not exported
30
+ * from the package: it is how our own two surfaces agree, not a third surface.
31
+ *
32
+ * MACHINES IN HAND BEAT BOTH FLAGS. The provider polls, so `loading` and
33
+ * `error` come back around; a poll that fails on its fourth round must not
34
+ * blank a list somebody is already reading.
35
+ */
36
+ export declare function MachineList(): import("react").JSX.Element;
@@ -4,8 +4,16 @@ export interface ConnectButtonProps {
4
4
  /** Override the label. Defaults to "Connect compute", or to what they have. */
5
5
  children?: ReactNode;
6
6
  /**
7
- * `outline` is the same control at lower volume, for a settings row that
8
- * already has a primary action on it. The design shows both.
7
+ * WHICH WEIGHT, AND WHY THE DEFAULT IS THE QUIET ONE.
8
+ *
9
+ * This button hands somebody to a flow that is not the host app's: nine
10
+ * steps, a download, and a sheet with our name at the foot of it. Drawn as a
11
+ * filled black control it was the loudest thing on whatever settings page it
12
+ * landed on — louder than Save, louder than the app's own primary action —
13
+ * which is a component deciding what somebody else's page is mainly about.
14
+ *
15
+ * `primary` is still one prop away, for a page whose whole purpose is this
16
+ * (an empty state, an onboarding step, a wall).
9
17
  */
10
18
  variant?: "primary" | "outline";
11
19
  className?: string;
@@ -8,6 +8,14 @@ export interface ConnectModalProps {
8
8
  onConnected?: (machines: Machine[]) => void;
9
9
  /** Whether the panel draws the machines they already have, or the app does. */
10
10
  showStatus?: boolean;
11
+ /**
12
+ * Why this was opened, when it was opened by a run that could not land.
13
+ *
14
+ * Changes the opening words and nothing else. Somebody who arrived here
15
+ * because their laptop is asleep has already bought the idea; being sold it
16
+ * again is the screen telling them it did not read its own error.
17
+ */
18
+ reason?: "payment_required" | "no_compute";
11
19
  }
12
20
  /**
13
21
  * THE CONNECT FLOW, IN A DIALOG.
@@ -20,4 +28,4 @@ export interface ConnectModalProps {
20
28
  * was, which is now where the button is: an error that replaces the thing you
21
29
  * were about to press is worse than one inside the thing you just opened.
22
30
  */
23
- export declare function ConnectModal({ open, onOpenChange, initialCode, onConnected, showStatus, }: ConnectModalProps): import("react").JSX.Element;
31
+ export declare function ConnectModal({ open, onOpenChange, initialCode, onConnected, showStatus, reason, }: ConnectModalProps): import("react").JSX.Element;
@@ -0,0 +1,120 @@
1
+ import { type ReactNode } from "react";
2
+ export interface ConnectNudgeProps {
3
+ /**
4
+ * How little has to be left before this says anything. A fraction of the
5
+ * allowance rather than a count, so it means the same on a plan of 20 and a
6
+ * plan of 2,000. Only consulted in the standing form.
7
+ */
8
+ at?: number;
9
+ /**
10
+ * WHAT THE LAST RUN CAME BACK WITH, and passing it at all changes which of
11
+ * the two integrations this is. See the note on the component.
12
+ *
13
+ * Anything your catch block caught: the parsed body, a `Response`, or an
14
+ * `Error` carrying either. Read through `sobaErrorCode`, so an unrelated
15
+ * failure is silence here and still renders however your app renders errors.
16
+ */
17
+ error?: unknown;
18
+ /**
19
+ * Both halves at once — what is already in the way, AND what refused the run
20
+ * once one has been tried. True exactly when `error` is not passed.
21
+ */
22
+ predict?: boolean;
23
+ /**
24
+ * THE CEILING THE RUN WAS SENT UNDER, when your app narrows `route.allow`
25
+ * per run rather than leaving the question to the plan.
26
+ *
27
+ * Without it this reads the PLAN's ceiling, which is right for an app that
28
+ * sends `POST /v1/runs` and lets the plan decide where a run may land. It is
29
+ * wrong, and silently so, for one that narrows per run: a surface that sends
30
+ * `route: { allow: ["user-hardware", "user-subscription"] }` because it needs
31
+ * the user's own files in front of the agent cannot run anywhere else — and
32
+ * on a plan that would happily have bought the run, nothing in `plan` says
33
+ * that. The `no_compute` came back, this had no reason to speak, and the
34
+ * person was told to go and find a screen.
35
+ *
36
+ * Same shape as the run's own field, so it is the value you already have: an
37
+ * explicit `null` is no ceiling, an empty array is a ceiling of nothing, and
38
+ * `undefined` — absent, or the value an optional variable happens to hold —
39
+ * falls back to the plan rather than claiming anything.
40
+ *
41
+ * It narrows what this card SAYS, never what a run may do — the gateway owns
42
+ * that — so a value that disagrees with the run costs a wrong sentence and
43
+ * nothing else.
44
+ */
45
+ allow?: string[] | null;
46
+ /**
47
+ * WHAT TO DRAW WHEN THIS HAS NOTHING TO OFFER — your own error UI, usually.
48
+ *
49
+ * For the attempted form, and it is the piece that makes that form safe to
50
+ * put in place of a message rather than above one. `<ConnectNudge error={e}/>`
51
+ * renders nothing for a failure connecting cannot fix, and nothing while the
52
+ * plan is still loading, and nothing when the machine came back between the
53
+ * run failing and this rendering — so a host that replaced its error line
54
+ * with this card had a run fail and say nothing at all.
55
+ *
56
+ * Passing the line you would otherwise have drawn means the card speaks when
57
+ * it can and your app speaks when it cannot, and the failure is never
58
+ * swallowed by either.
59
+ *
60
+ * Ignored in spirit by the standing form: a nudge with nothing to offer
61
+ * should be silent, and an app that has not failed at anything has no error
62
+ * line to pass.
63
+ */
64
+ fallback?: ReactNode;
65
+ className?: string;
66
+ }
67
+ /**
68
+ * THE SAME OFFER, EARLIER, AND MUCH QUIETER.
69
+ *
70
+ * A wall converts because the person has no choice, which is also why it is a
71
+ * bad first introduction: the only two moments they have heard of connecting
72
+ * are the moment it was demanded of them and the moment it was demanded again.
73
+ * This is the version that arrives while they still have a choice, so the wall
74
+ * lands on somebody who has already been told what it is.
75
+ *
76
+ * TWO REASONS TO SPEAK, and it says nothing at all otherwise, because a nudge
77
+ * that shows up when it cannot help is an advertisement.
78
+ *
79
+ * **Nothing can run until a machine is attached.** A "Bring your own" plan,
80
+ * free and unlimited on nothing but compute the user owns, is not running low
81
+ * on anything: it is not running at all. That state is permanent until somebody
82
+ * attaches a machine, and without this the only thing that would ever mention
83
+ * it is the `no_compute` on their first attempt. Said as a fact rather than an
84
+ * offer, because there is no bonus here, only a prerequisite.
85
+ *
86
+ * The plan is not the only thing that can impose that. A surface which needs
87
+ * the user's own files in front of the agent sends its runs under a narrower
88
+ * ceiling than the plan's, and then the plan is no evidence at all — see
89
+ * `allow`, which is how such a host says so, and `fallback`, which is how it
90
+ * keeps a failure from going unsaid when even this has nothing to offer.
91
+ *
92
+ * **The allowance is running out and connecting would lift it.** Needs all of:
93
+ * a reward felt as ALLOWANCE (`unlimited` or `included`, never `credit`, which
94
+ * is settled at renewal and changes nothing today), nothing connected, and an
95
+ * allowance that is real and nearly gone.
96
+ *
97
+ * Either way it disappears the moment something is connected. Somebody who has
98
+ * a machine attached has taken the offer, and repeating it reads as the app not
99
+ * knowing.
100
+ *
101
+ * TWO INTEGRATIONS, AND THE HOST PICKS BY WHETHER IT PASSES AN ERROR — the same
102
+ * pair `<RunLimit />` has, said the same way, because an app that learned one
103
+ * has learned the other:
104
+ *
105
+ * **Standing** — `<ConnectNudge />`. It watches the plan and stands above the
106
+ * composer for as long as the offer is real. The right shape when connecting is
107
+ * the point of the plan, and the wrong one for an app that would rather its
108
+ * chat opened empty: on a bring-your-own plan this is on screen from the first
109
+ * session, before anybody has typed anything.
110
+ *
111
+ * **On a run that failed** — `<ConnectNudge error={err} />`. Silent until
112
+ * something is actually refused, and silent then for anything but the two
113
+ * failures connecting fixes. An empty slot is not an invitation to predict:
114
+ * `error={null}` is a chat that has not failed yet, and it says nothing.
115
+ *
116
+ * `predict` takes both — what is already in the way and what refused the run —
117
+ * for an app that wants the offer standing AND wants it to answer the failure
118
+ * when one comes.
119
+ */
120
+ export declare function ConnectNudge(props: ConnectNudgeProps): import("react").JSX.Element;
@@ -0,0 +1,55 @@
1
+ export interface RunLimitProps {
2
+ /**
3
+ * Whatever your catch block caught. Anything that is not an answerable
4
+ * failure renders nothing, so this can sit permanently in your tree — and
5
+ * `null`, the value every app holds before the first failure, renders nothing
6
+ * too. Passing the prop says "report what failed"; holding an empty slot is
7
+ * not a request to talk about a run nobody has started.
8
+ *
9
+ * OMIT IT to have the card watch the state instead, and appear BEFORE a run
10
+ * is attempted rather than after one failed. In a chat that is the form you
11
+ * want: a plan that can only reach compute the user owns, with nothing
12
+ * connected, has nowhere to send a message, and the card belongs in the
13
+ * stream above the composer rather than in the wreckage of a request.
14
+ */
15
+ error?: unknown;
16
+ /**
17
+ * Both halves at once: watch the state AND report the failure. Defaults to
18
+ * true exactly when `error` is not passed.
19
+ *
20
+ * A chat wants this with `error`, because the message has nowhere to land
21
+ * before it is typed. A button does not: there, "nothing connected" before
22
+ * anybody has pressed anything is a card about a run that has not happened.
23
+ */
24
+ predict?: boolean;
25
+ /**
26
+ * `card` sits in the flow of the page, where the failed run is. `dialog`
27
+ * covers it. Same content either way — the container is the only difference,
28
+ * which is why "a card or a modal" is one decision and not two components.
29
+ */
30
+ variant?: "card" | "dialog";
31
+ /** Dismissing. A card without one is a card that cannot be got rid of, and
32
+ * the run underneath it may be one the person no longer wants to retry. */
33
+ onDismiss?: () => void;
34
+ className?: string;
35
+ }
36
+ /**
37
+ * THE WALL, AND THE WAY THROUGH IT, WHERE THE WALL IS.
38
+ *
39
+ * A run failed for one of the two reasons a person can do something about, and
40
+ * this is the thing that says so and offers the two doors: run it on compute
41
+ * you own, or buy more. Both examples in this repo used to end that moment with
42
+ * a red paragraph and a pointer at a settings page in another route, which is
43
+ * the pattern this exists to replace.
44
+ *
45
+ * It draws two buttons at most. Connecting is primary wherever the plan
46
+ * actually rewards it, because it is the cheaper door for the person and the
47
+ * free one for the app, and putting the paid door first on a product whose
48
+ * argument is "use the AI you already pay for" would be arguing against
49
+ * ourselves.
50
+ *
51
+ * `useRunLimit` is underneath and is exported: an app whose cards have their
52
+ * own structure should call that and draw this itself. Ours will never match
53
+ * the card sitting above it in somebody else's chat.
54
+ */
55
+ export declare function RunLimit(props: RunLimitProps): import("react").JSX.Element | null;
@@ -0,0 +1,41 @@
1
+ import { type SobaPlansProps } from "./SobaPlans.js";
2
+ export interface SobaBillingProps extends Omit<SobaPlansProps, "className" | "showConnect"> {
3
+ /** The current-plan card's own heading. Empty string draws none, for an app
4
+ * that has already titled the card it is putting this in. */
5
+ heading?: string;
6
+ /**
7
+ * The grid's heading. Defaults to what is true of the person reading it:
8
+ * "Change plan" for somebody on one, "Choose a plan" for somebody on none.
9
+ * Empty string draws none.
10
+ */
11
+ plansHeading?: string;
12
+ /** Hide the usage panel on the card above, for an app that draws its own
13
+ * meter. The plans below are unaffected. */
14
+ showUsage?: boolean;
15
+ /**
16
+ * Draw the plan's name and description on the card above. On by default;
17
+ * pass `false` for an app that has already titled the card itself.
18
+ */
19
+ showName?: boolean;
20
+ className?: string;
21
+ }
22
+ /**
23
+ * THE WHOLE BILLING PAGE, IN THE ORDER SOMEBODY READS ONE.
24
+ *
25
+ * `<SobaCurrentPlan />` and `<SobaPlans />` are halves of one page — what they
26
+ * are on, then what else there is — and every app that used both was writing
27
+ * the same wrapper: the two in that order, a heading over the grid, and the
28
+ * decision about where the connect offer goes.
29
+ *
30
+ * THAT LAST ONE IS THE REASON THIS EXISTS RATHER THAN A SNIPPET IN THE DOCS.
31
+ * Both components can draw the connect offer, from the same rule, so an app
32
+ * assembling them itself gets the same button twice and no error to tell it so.
33
+ * Here the answer is structural: the offer sits on the card that reports the
34
+ * state it changes, and the grid under it keeps "Your plan" on the plan that is
35
+ * already theirs. `<SobaPlans showConnect />` is for the other page — a pricing
36
+ * page standing alone, with no current-plan card on it at all.
37
+ *
38
+ * Everything else is passed straight through, because a billing page's grid is
39
+ * the same grid: `variant`, `featured`, `showCompute`, the checkout props.
40
+ */
41
+ export declare function SobaBilling({ heading, plansHeading, showUsage, showName, className, ...plans }: SobaBillingProps): import("react").JSX.Element;
@@ -0,0 +1,29 @@
1
+ export interface SobaCurrentPlanProps {
2
+ /** The section's own heading. Empty string draws none, for an app that has
3
+ * already titled the card it is putting this in. */
4
+ heading?: string;
5
+ /** Hide the usage panel, for a card that only names the plan. */
6
+ showUsage?: boolean;
7
+ /**
8
+ * Draw the plan's name and description. Off when something else on the page
9
+ * already names it — `<SobaBilling />` turns it off, because the grid
10
+ * directly beneath marks the same plan "Current" and repeats both lines.
11
+ *
12
+ * The trial clock is NOT part of this: it is the one thing on the card the
13
+ * grid never shows, so it survives with the name hidden.
14
+ */
15
+ showName?: boolean;
16
+ className?: string;
17
+ }
18
+ /**
19
+ * WHAT THEY ARE ON, AND HOW MUCH OF IT IS LEFT.
20
+ *
21
+ * The other half of a billing page: `<SobaPlans />` answers "what could I be
22
+ * on", this answers "what am I on, and what happens next". The plan's name at
23
+ * display size, a trial clock when there is one, and a usage panel beside it.
24
+ *
25
+ * Every decision it draws — which ceiling applies, whether past the line is a
26
+ * bill or a wall, which single sentence is true — belongs to `useCurrentPlan`,
27
+ * which is exported and documented. This file is markup over it.
28
+ */
29
+ export declare function SobaCurrentPlan({ heading, showUsage, showName, className, }: SobaCurrentPlanProps): import("react").JSX.Element;
@@ -15,6 +15,61 @@ export interface SobaPlansProps {
15
15
  /** Hide the compute row. It is shown by default because on this product the
16
16
  * plan decides which compute a run reaches, which is the differentiator. */
17
17
  showCompute?: boolean;
18
+ /**
19
+ * OFFER THE CONNECT FLOW FROM THE CURRENT CARD. OFF, AND DELIBERATELY.
20
+ *
21
+ * A card in a price list answers one question — what is this plan, and how do
22
+ * I get on it — and the card for the plan somebody is already on answers it
23
+ * with "Your plan". Putting `Connect compute` in that slot instead makes the
24
+ * one card that is NOT a choice carry the loudest control on the page, and
25
+ * takes away the only thing that said, plainly, which plan is theirs.
26
+ *
27
+ * Connecting is a fact about the plan they hold rather than about the
28
+ * catalogue, so the offer belongs on the surface that reports what they hold:
29
+ * `<SobaCurrentPlan />` draws it from the same rule (`useCurrentPlan`'s
30
+ * `reward.actionable` is `usePlans`' `connect.actionable`), and
31
+ * `<SobaBilling />` puts that card above this grid for exactly this reason.
32
+ *
33
+ * Turn it on for a pricing page that stands alone — no current-plan card
34
+ * anywhere on it — where a Bring-your-own plan would otherwise state a
35
+ * requirement with no way to meet it. Then the current card's slot carries
36
+ * the offer instead of the dead button.
37
+ *
38
+ * The connect LINE is not affected either way. "10,000 runs a month when you
39
+ * connect your own AI" is part of what a plan IS, and somebody comparing
40
+ * plans should read it on every card whether or not they can act on it here.
41
+ */
42
+ showConnect?: boolean;
43
+ /**
44
+ * THE SHAPE OF THE PAGE, WHICH IS NOT THE SAME DECISION AS THE CONTENT.
45
+ *
46
+ * Every layout here draws the same facts from the same plan objects — what it
47
+ * costs, what is included, what happens past the allowance, which compute it
48
+ * may reach, what connecting earns. What changes is the reading order, and
49
+ * that follows the page rather than the product:
50
+ *
51
+ * - `cards` is a choice being made. Each plan whole and side by side, for a
52
+ * pricing page or an upgrade screen where nobody has decided yet.
53
+ * - `rows` is a choice being reviewed. One line per plan, price and control
54
+ * on the right, which is how a settings page lists things you can switch
55
+ * between — and it survives a narrow column, where a grid of cards cannot.
56
+ * - `table` is a choice being argued. Facts as rows and plans as columns, so
57
+ * two plans can actually be compared on the dimension that separates them,
58
+ * which on this product is usually the compute row rather than the price.
59
+ *
60
+ * The default stays `cards`, because it is what every caller already has.
61
+ */
62
+ variant?: "cards" | "rows" | "table";
63
+ /**
64
+ * THE PLAN THE APP IS PUSHING, by id. Drawn with emphasis in every layout.
65
+ *
66
+ * A prop rather than something derived, because nothing on a plan says
67
+ * "recommended" and inventing the claim from the price would be this
68
+ * component making a business decision on the app's behalf. A plan somebody
69
+ * is already ON is never featured: "Current" is the more useful of the two
70
+ * things to say, and two badges on one card is a page shouting.
71
+ */
72
+ featured?: string;
18
73
  className?: string;
19
74
  }
20
75
  /**
@@ -32,4 +87,4 @@ export interface SobaPlansProps {
32
87
  * would have to hand-maintain in a second place, and get wrong the first time
33
88
  * the plan changed.
34
89
  */
35
- export declare function SobaPlans({ onSelect, successUrl, cancelUrl, showCompute, className, }: SobaPlansProps): import("react").JSX.Element;
90
+ export declare function SobaPlans({ onSelect, successUrl, cancelUrl, showCompute, showConnect, variant, featured, className, }: SobaPlansProps): import("react").JSX.Element;
@@ -61,6 +61,15 @@ export interface SobaProviderProps {
61
61
  pollMs?: number;
62
62
  /** The stylesheet injects itself once. Turn it off to ship your own. */
63
63
  injectStyles?: boolean;
64
+ /**
65
+ * Whether the provider mounts the one shared `<ConnectModal />`.
66
+ *
67
+ * Left true, `connect.open()` works from anywhere in the tree and there is
68
+ * exactly one flow on screen however many things can raise it. False for an
69
+ * app that places `<ConnectModal />` itself and drives `open` from its own
70
+ * state: a drawer, a route, a step in a wizard.
71
+ */
72
+ modal?: boolean;
64
73
  fetchImpl?: typeof fetch;
65
74
  onError?: (error: Error) => void;
66
75
  }
package/dist/context.d.ts CHANGED
@@ -20,6 +20,9 @@ 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
26
  export interface ConnectState {
24
27
  /** Your app's name, as the person connecting will see it. */
25
28
  app: {
@@ -27,9 +30,35 @@ export interface ConnectState {
27
30
  } | null;
28
31
  /** The exact command to run on the machine being paired. */
29
32
  command: string | null;
33
+ /**
34
+ * Where this app's connect flow lives, which is also the only thing in the
35
+ * context that names OUR host — so a component that needs to offer a build
36
+ * derives the origin from it rather than hard-coding one. See
37
+ * `downloadOrigin` in connect-ui.
38
+ */
39
+ connectUrl: string | null;
30
40
  publishableKey: string | null;
31
41
  loading: boolean;
32
42
  error: Error | null;
43
+ /**
44
+ * OPEN THE FLOW FROM ANYWHERE, and there is exactly one of it.
45
+ *
46
+ * The provider mounts a single `<ConnectModal />` and this raises it. Before
47
+ * this, every trigger owned its own, so an app with a card in its chat, a
48
+ * row on its pricing page and a wall at the end of a run mounted three
49
+ * copies of a nine-phase flow and could have two of them on screen at once,
50
+ * each polling, each with its own half-finished pairing.
51
+ *
52
+ * Pass `modal={false}` to <SobaProvider> to place the modal yourself; these
53
+ * then do nothing, which is the honest behaviour for a control with nothing
54
+ * to control.
55
+ */
56
+ open(reason?: ConnectReason): void;
57
+ close(): void;
58
+ isOpen: boolean;
59
+ /** Whether the provider mounted the shared modal, so `open` does something.
60
+ * False under `modal={false}`, where the app places its own. */
61
+ hasModal: boolean;
33
62
  }
34
63
  /**
35
64
  * The plans this app sells, and the one this user is on.
@@ -46,6 +75,23 @@ export interface PlanState {
46
75
  current: CurrentPlan | null;
47
76
  /** The plan object behind `current`, resolved for convenience. */
48
77
  plan: Plan | null;
78
+ /**
79
+ * THE ALLOWANCE, DERIVED, because an app should not have to know that
80
+ * "remaining" is a subtraction across two objects in the same response.
81
+ *
82
+ * Both halves already arrive: `plans[].included_units` and
83
+ * `current.units_used`. What was missing was anyone putting them together,
84
+ * so every app that wanted to say "two left today" wrote the arithmetic
85
+ * itself, and wrote the null case (unlimited) wrong the first time,
86
+ * because `included_units: null` is unlimited and `0` is not, and a falsy
87
+ * check reads them identically.
88
+ *
89
+ * Null everywhere when there is no plan, which is no ceiling.
90
+ */
91
+ used: number | null;
92
+ included: number | null;
93
+ remaining: number | null;
94
+ unlimited: boolean;
49
95
  loading: boolean;
50
96
  error: Error | null;
51
97
  /** Take a plan. A priced one rejects with `payment_required`; send it to
package/dist/index.d.ts CHANGED
@@ -2,10 +2,17 @@ export { ComputeStatus, type ComputeStatusProps } from "./ComputeStatus.js";
2
2
  export { ConnectButton, type ConnectButtonProps } from "./ConnectButton.js";
3
3
  export { ConnectCompute, type ConnectComputeProps } from "./ConnectCompute.js";
4
4
  export { ConnectModal, type ConnectModalProps } from "./ConnectModal.js";
5
- export { type ComputeState, type ConnectState, type PlanState, type RunRequest, type SobaContextValue, useSoba, } from "./context.js";
5
+ export { ConnectNudge, type ConnectNudgeProps } from "./ConnectNudge.js";
6
+ export { type ComputeState, type ConnectReason, type ConnectState, type PlanState, type RunRequest, type SobaContextValue, useSoba, } from "./context.js";
6
7
  export { collectText, parseEvent, readEvents } from "./events.js";
8
+ export { RunLimit, type RunLimitProps } from "./RunLimit.js";
9
+ export { SobaBilling, type SobaBillingProps } from "./SobaBilling.js";
7
10
  export { SobaCheckout, type SobaCheckoutProps } from "./SobaCheckout.js";
11
+ export { SobaCurrentPlan, type SobaCurrentPlanProps } from "./SobaCurrentPlan.js";
8
12
  export { SobaPlans, type SobaPlansProps } from "./SobaPlans.js";
9
13
  export { SobaProvider, type SobaProviderProps } from "./SobaProvider.js";
10
14
  export { injectStyles } from "./styles.js";
11
15
  export type { AgentEvent, AgentEventType, ConnectApi, ConnectContext, CostClass, CurrentPlan, Machine, MachineState, Message, PendingCode, Plan, Runtime, RunUsage, } from "./types.js";
16
+ export { type AllowanceState, type CurrentPlanReward, type CurrentPlanView, useCurrentPlan, } from "./useCurrentPlan.js";
17
+ export { type PlanCompute, type PlanConnect, type PlanCta, type PlanOffer, type PlanPrice, type PlansOptions, type PlansView, usePlans, } from "./usePlans.js";
18
+ export { type LimitReason, type Offer, sobaErrorCode, useRunLimit } from "./useRunLimit.js";