@soba-so/react 0.0.10 → 0.0.11
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/dist/ComputeStatus.d.ts +21 -0
- package/dist/ConnectButton.d.ts +10 -2
- package/dist/ConnectModal.d.ts +9 -1
- package/dist/ConnectNudge.d.ts +120 -0
- package/dist/RunLimit.d.ts +55 -0
- package/dist/SobaBilling.d.ts +41 -0
- package/dist/SobaCurrentPlan.d.ts +29 -0
- package/dist/SobaPlans.d.ts +56 -1
- package/dist/SobaProvider.d.ts +9 -0
- package/dist/context.d.ts +46 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.mjs +1929 -152
- package/dist/styles.css +1924 -147
- package/dist/types.d.ts +16 -1
- package/dist/useCurrentPlan.d.ts +98 -0
- package/dist/useOpenSobaConnect.d.ts +32 -0
- package/dist/usePlans.d.ts +115 -0
- package/dist/useRunLimit.d.ts +140 -0
- package/package.json +9 -8
package/dist/ComputeStatus.d.ts
CHANGED
|
@@ -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;
|
package/dist/ConnectButton.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
8
|
-
*
|
|
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;
|
package/dist/ConnectModal.d.ts
CHANGED
|
@@ -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;
|
package/dist/SobaPlans.d.ts
CHANGED
|
@@ -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;
|
package/dist/SobaProvider.d.ts
CHANGED
|
@@ -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 {
|
|
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";
|