@cosmoops/connect-sdk 0.1.0
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/LICENSE +34 -0
- package/README.md +446 -0
- package/dist/cjs/cli/bin.js +16 -0
- package/dist/cjs/cli/init.js +179 -0
- package/dist/cjs/client/components/account-sessions.js +112 -0
- package/dist/cjs/client/components/apps-grid.js +46 -0
- package/dist/cjs/client/components/auth-buttons.js +42 -0
- package/dist/cjs/client/components/feature-gate.js +61 -0
- package/dist/cjs/client/components/link-button.js +24 -0
- package/dist/cjs/client/components/logo.js +27 -0
- package/dist/cjs/client/components/plan-pricing.js +166 -0
- package/dist/cjs/client/components/plans-page.js +39 -0
- package/dist/cjs/client/components/plans.js +212 -0
- package/dist/cjs/client/components/readiness.js +117 -0
- package/dist/cjs/client/components/subscribe-dialog.js +60 -0
- package/dist/cjs/client/components/subscription.js +189 -0
- package/dist/cjs/client/components/usage-meter.js +68 -0
- package/dist/cjs/client/components/user-menu.js +172 -0
- package/dist/cjs/client/index.js +99 -0
- package/dist/cjs/client/mark.js +16 -0
- package/dist/cjs/client/provider.js +259 -0
- package/dist/cjs/client/use-checkout.js +173 -0
- package/dist/cjs/errors.js +74 -0
- package/dist/cjs/format-relative-time.js +18 -0
- package/dist/cjs/helpers.js +30 -0
- package/dist/cjs/index.js +22 -0
- package/dist/cjs/next/index.js +311 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/server/client.js +114 -0
- package/dist/cjs/server/handler.js +333 -0
- package/dist/cjs/server/http.js +160 -0
- package/dist/cjs/server/index.js +18 -0
- package/dist/cjs/server/resources/access.js +28 -0
- package/dist/cjs/server/resources/ai.js +36 -0
- package/dist/cjs/server/resources/apps.js +30 -0
- package/dist/cjs/server/resources/billing.js +71 -0
- package/dist/cjs/server/resources/drive.js +39 -0
- package/dist/cjs/server/resources/entitlements.js +49 -0
- package/dist/cjs/server/resources/identity.js +194 -0
- package/dist/cjs/server/resources/logs.js +41 -0
- package/dist/cjs/server/resources/otp.js +29 -0
- package/dist/cjs/server/resources/sessions.js +82 -0
- package/dist/cjs/types.js +15 -0
- package/dist/esm/cli/bin.js +13 -0
- package/dist/esm/cli/init.js +174 -0
- package/dist/esm/client/components/account-sessions.js +109 -0
- package/dist/esm/client/components/apps-grid.js +43 -0
- package/dist/esm/client/components/auth-buttons.js +38 -0
- package/dist/esm/client/components/feature-gate.js +57 -0
- package/dist/esm/client/components/link-button.js +21 -0
- package/dist/esm/client/components/logo.js +24 -0
- package/dist/esm/client/components/plan-pricing.js +156 -0
- package/dist/esm/client/components/plans-page.js +36 -0
- package/dist/esm/client/components/plans.js +209 -0
- package/dist/esm/client/components/readiness.js +113 -0
- package/dist/esm/client/components/subscribe-dialog.js +57 -0
- package/dist/esm/client/components/subscription.js +181 -0
- package/dist/esm/client/components/usage-meter.js +65 -0
- package/dist/esm/client/components/user-menu.js +164 -0
- package/dist/esm/client/index.js +47 -0
- package/dist/esm/client/mark.js +13 -0
- package/dist/esm/client/provider.js +247 -0
- package/dist/esm/client/use-checkout.js +168 -0
- package/dist/esm/errors.js +69 -0
- package/dist/esm/format-relative-time.js +15 -0
- package/dist/esm/helpers.js +26 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/next/index.js +279 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/server/client.js +110 -0
- package/dist/esm/server/handler.js +330 -0
- package/dist/esm/server/http.js +156 -0
- package/dist/esm/server/index.js +10 -0
- package/dist/esm/server/resources/access.js +24 -0
- package/dist/esm/server/resources/ai.js +32 -0
- package/dist/esm/server/resources/apps.js +26 -0
- package/dist/esm/server/resources/billing.js +67 -0
- package/dist/esm/server/resources/drive.js +35 -0
- package/dist/esm/server/resources/entitlements.js +45 -0
- package/dist/esm/server/resources/identity.js +189 -0
- package/dist/esm/server/resources/logs.js +37 -0
- package/dist/esm/server/resources/otp.js +25 -0
- package/dist/esm/server/resources/sessions.js +78 -0
- package/dist/esm/types.js +14 -0
- package/dist/theme.css +84 -0
- package/dist/types/cli/bin.d.ts +1 -0
- package/dist/types/cli/init.d.ts +34 -0
- package/dist/types/client/components/account-sessions.d.ts +25 -0
- package/dist/types/client/components/apps-grid.d.ts +20 -0
- package/dist/types/client/components/auth-buttons.d.ts +31 -0
- package/dist/types/client/components/feature-gate.d.ts +57 -0
- package/dist/types/client/components/link-button.d.ts +20 -0
- package/dist/types/client/components/logo.d.ts +35 -0
- package/dist/types/client/components/plan-pricing.d.ts +96 -0
- package/dist/types/client/components/plans-page.d.ts +36 -0
- package/dist/types/client/components/plans.d.ts +34 -0
- package/dist/types/client/components/readiness.d.ts +52 -0
- package/dist/types/client/components/subscribe-dialog.d.ts +34 -0
- package/dist/types/client/components/subscription.d.ts +123 -0
- package/dist/types/client/components/usage-meter.d.ts +24 -0
- package/dist/types/client/components/user-menu.d.ts +86 -0
- package/dist/types/client/index.d.ts +47 -0
- package/dist/types/client/mark.d.ts +11 -0
- package/dist/types/client/provider.d.ts +209 -0
- package/dist/types/client/use-checkout.d.ts +93 -0
- package/dist/types/errors.d.ts +62 -0
- package/dist/types/format-relative-time.d.ts +2 -0
- package/dist/types/helpers.d.ts +33 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/next/index.d.ts +136 -0
- package/dist/types/server/client.d.ts +83 -0
- package/dist/types/server/handler.d.ts +67 -0
- package/dist/types/server/http.d.ts +52 -0
- package/dist/types/server/index.d.ts +15 -0
- package/dist/types/server/resources/access.d.ts +17 -0
- package/dist/types/server/resources/ai.d.ts +24 -0
- package/dist/types/server/resources/apps.d.ts +12 -0
- package/dist/types/server/resources/billing.d.ts +41 -0
- package/dist/types/server/resources/drive.d.ts +26 -0
- package/dist/types/server/resources/entitlements.d.ts +31 -0
- package/dist/types/server/resources/identity.d.ts +76 -0
- package/dist/types/server/resources/logs.d.ts +20 -0
- package/dist/types/server/resources/otp.d.ts +17 -0
- package/dist/types/server/resources/sessions.d.ts +37 -0
- package/dist/types/types.d.ts +434 -0
- package/package.json +102 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ConnectAppsGridProps {
|
|
2
|
+
/** Extra classes on the trigger button. */
|
|
3
|
+
className?: string;
|
|
4
|
+
/** Trigger label for screen readers. */
|
|
5
|
+
label?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The Google-style app launcher: a grid icon in your top bar that opens a
|
|
9
|
+
* modal of every Connect service this organization can actually open.
|
|
10
|
+
*
|
|
11
|
+
* Only launchable apps appear, so no tile is a dead end - a paused
|
|
12
|
+
* subscription still shows, badged, because a dunning cycle should not make a
|
|
13
|
+
* product look deleted. The current app is pinned first and marked, rather
|
|
14
|
+
* than filtered out, so the grid never has a hole where "you are here" should
|
|
15
|
+
* be.
|
|
16
|
+
*
|
|
17
|
+
* Renders nothing when signed out: a launcher with nothing to launch is just a
|
|
18
|
+
* button that opens an empty box.
|
|
19
|
+
*/
|
|
20
|
+
export declare function ConnectAppsGrid({ className, label }: ConnectAppsGridProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Button } from "@heroui/react";
|
|
2
|
+
import type { ComponentProps, ReactNode } from "react";
|
|
3
|
+
type ButtonProps = ComponentProps<typeof Button>;
|
|
4
|
+
export interface ConnectAuthButtonProps extends Omit<ButtonProps, "onPress" | "children"> {
|
|
5
|
+
/** Defaults to "Continue with Connect" / "Sign up with Connect". */
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* "Continue with Connect" - the federated sign-in button, in the shape people
|
|
10
|
+
* already know from Google and GitHub: neutral surface, brand mark on the
|
|
11
|
+
* left, one line of text.
|
|
12
|
+
*
|
|
13
|
+
* `variant="secondary"` by default rather than `primary`, on purpose. A
|
|
14
|
+
* federated button that outshouts the host app's own primary action reads as
|
|
15
|
+
* an ad; every mature identity button is quiet. Pass `variant` to override if
|
|
16
|
+
* Connect *is* the primary path in your flow.
|
|
17
|
+
*
|
|
18
|
+
* Hidden while a session is still loading, so a signed-in user never sees a
|
|
19
|
+
* Login button flash before their avatar resolves.
|
|
20
|
+
*/
|
|
21
|
+
export declare function ConnectLoginButton({ children, ...props }: ConnectAuthButtonProps): import("react").JSX.Element | null;
|
|
22
|
+
/**
|
|
23
|
+
* The same button pointed at registration (`prompt=create`).
|
|
24
|
+
*
|
|
25
|
+
* Only the starting screen differs - each screen links to the other carrying
|
|
26
|
+
* the same in-flight request, and anyone who already has a Connect session
|
|
27
|
+
* skips straight to consent either way. So shipping both buttons costs nothing
|
|
28
|
+
* and matches what users expect from a "Sign up" / "Log in" pair.
|
|
29
|
+
*/
|
|
30
|
+
export declare function ConnectRegisterButton({ children, ...props }: ConnectAuthButtonProps): import("react").JSX.Element | null;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Whether the live subscription unlocks a plan feature.
|
|
4
|
+
*
|
|
5
|
+
* The browser twin of `client.entitlements.hasFeature` on the server, and the
|
|
6
|
+
* same posture: `false` rather than a throw when there is no subscription at
|
|
7
|
+
* all, because "not entitled" is the same answer either way and a feature check
|
|
8
|
+
* should not need a try/catch around it.
|
|
9
|
+
*
|
|
10
|
+
* `isLoading` is returned separately and matters: `false` while the first read
|
|
11
|
+
* is in flight means "we don't know yet", not "no". Gate on `isEntitled` for
|
|
12
|
+
* what to render and on `isLoading` for whether to render anything at all -
|
|
13
|
+
* `ConnectFeatureGate` does exactly that.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useConnectFeature(feature: string): {
|
|
16
|
+
isEntitled: boolean;
|
|
17
|
+
isLoading: boolean;
|
|
18
|
+
/** Every feature key the current plan unlocks - for a settings page listing what's included. */
|
|
19
|
+
features: string[];
|
|
20
|
+
};
|
|
21
|
+
export interface ConnectFeatureGateProps {
|
|
22
|
+
/** The feature key, as it appears in `plan.features`. */
|
|
23
|
+
feature: string;
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
/**
|
|
26
|
+
* Rendered when the plan does not include `feature`. Defaults to an upsell
|
|
27
|
+
* card pointing at your plans page - pass `null` to hide the module silently
|
|
28
|
+
* instead.
|
|
29
|
+
*/
|
|
30
|
+
fallback?: ReactNode;
|
|
31
|
+
/** Shown while the first read is in flight. Defaults to nothing. */
|
|
32
|
+
loading?: ReactNode;
|
|
33
|
+
/** Where your plan catalogue is mounted, for the default upsell. */
|
|
34
|
+
plansHref?: string;
|
|
35
|
+
/** Headline for the default upsell - name the feature, not the plan. */
|
|
36
|
+
title?: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Renders `children` only when the workspace's plan includes `feature`.
|
|
42
|
+
*
|
|
43
|
+
* ```tsx
|
|
44
|
+
* <ConnectFeatureGate feature="advanced_reports" title="Reports are on Growth">
|
|
45
|
+
* <Reports />
|
|
46
|
+
* </ConnectFeatureGate>
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* Like every gate in this package, it is a **UX gate, not a security
|
|
50
|
+
* boundary**: the entitlement is read through your own origin and the browser
|
|
51
|
+
* can ignore it. Check `client.entitlements.hasFeature(orgId, feature)` on the
|
|
52
|
+
* server before doing the thing the feature unlocks.
|
|
53
|
+
*
|
|
54
|
+
* Renders `loading` - not `fallback` - while the answer is unknown, so a paying
|
|
55
|
+
* customer never sees an upsell for something they already have.
|
|
56
|
+
*/
|
|
57
|
+
export declare function ConnectFeatureGate({ feature, children, fallback, loading, plansHref, title, description, className, }: ConnectFeatureGateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ButtonProps } from "@heroui/react";
|
|
2
|
+
export type ConnectLinkButtonProps = Omit<ButtonProps, "render"> & {
|
|
3
|
+
href: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* A HeroUI `Button` that renders a real `<a>`.
|
|
7
|
+
*
|
|
8
|
+
* A plain anchor, deliberately not a router link: this package imports nothing
|
|
9
|
+
* from `next` (see the `./next` entry's doc comment for why that is a hard
|
|
10
|
+
* rule), so it cannot know which router - if any - the host app uses. An
|
|
11
|
+
* `<a href>` navigates under all of them, and a host that wants client-side
|
|
12
|
+
* routing can pass its own element via `render` on the underlying `Button`.
|
|
13
|
+
*
|
|
14
|
+
* The cast is the same one HeroUI's own "Render Function" example needs:
|
|
15
|
+
* `render` types its argument as the props of the element `Button` would have
|
|
16
|
+
* emitted, which is a `<button>` - including a `ref` typed to
|
|
17
|
+
* `HTMLButtonElement`. Spreading that onto an anchor is sound at runtime and
|
|
18
|
+
* unrepresentable in the type, which is exactly what a cast is for.
|
|
19
|
+
*/
|
|
20
|
+
export declare function ConnectLinkButton({ href, ...props }: Readonly<ConnectLinkButtonProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ConnectLogoProps {
|
|
3
|
+
/**
|
|
4
|
+
* This service's name - rendered as the sub-brand beneath the `cosmo·ops`
|
|
5
|
+
* wordmark, in the house `cosmo·ops VOICE` treatment.
|
|
6
|
+
*/
|
|
7
|
+
name: string;
|
|
8
|
+
/**
|
|
9
|
+
* This service's own glyph, drawn inside the accent badge. Any node - a
|
|
10
|
+
* `lucide-react` icon, an `<img>`, an inline `<svg>`. Paint it with
|
|
11
|
+
* `currentColor` and it inherits `--accent-foreground` from the badge, so it
|
|
12
|
+
* stays legible when a host app changes the accent.
|
|
13
|
+
*
|
|
14
|
+
* Falls back to the Connect rings when omitted.
|
|
15
|
+
*/
|
|
16
|
+
icon?: ReactNode;
|
|
17
|
+
/** Mark only, no wordmark - for a collapsed sidebar or a favicon-sized slot. */
|
|
18
|
+
collapsed?: boolean;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The shared platform lockup: a service's own glyph on the CosmoOps badge,
|
|
23
|
+
* `cosmo·ops` beside it, and the service name underneath.
|
|
24
|
+
*
|
|
25
|
+
* This is what makes a family of service platforms look like one product. Each
|
|
26
|
+
* platform passes only what differs - its `name` and its `icon` - and inherits
|
|
27
|
+
* the mark geometry, the wordmark treatment, the separator, and the accent from
|
|
28
|
+
* one place. Change the lockup here and every platform follows.
|
|
29
|
+
*
|
|
30
|
+
* Sizes are `em`-based throughout, so the whole lockup scales from the
|
|
31
|
+
* wrapper's font size: `className="text-base"` renders it half again as large
|
|
32
|
+
* as `text-sm`, with the badge, gap and tracking all in proportion. That is
|
|
33
|
+
* why there is no `size` prop.
|
|
34
|
+
*/
|
|
35
|
+
export declare function ConnectLogo({ name, icon, collapsed, className }: ConnectLogoProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pricing arithmetic the plan grid and its confirmation dialog have to
|
|
3
|
+
* agree on. Extracted so they cannot drift: a dialog that called an upgrade
|
|
4
|
+
* an upgrade while the card behind it said downgrade would be worse than
|
|
5
|
+
* either label being wrong on its own.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors `packages/data/src/services/catalog.ts` and
|
|
8
|
+
* `packages/data/src/payments/plan-change.ts`, which are the copies Connect's
|
|
9
|
+
* own UI uses and which decide which use-case actually runs. The duplication
|
|
10
|
+
* is deliberate and load-bearing: this package carries no dependency on
|
|
11
|
+
* `@connect/data` so a partner's bundle never pulls Connect's internals, and
|
|
12
|
+
* `conformance.test.ts` type-checks the wire shapes against the server DTOs so
|
|
13
|
+
* the two can't drift silently.
|
|
14
|
+
*
|
|
15
|
+
* No React here - it is imported by both a client component and its dialog,
|
|
16
|
+
* and nothing in it needs to be.
|
|
17
|
+
*/
|
|
18
|
+
import type { AppliedDiscount, Plan, SubscriptionResponse } from "../../types.js";
|
|
19
|
+
/** Paise are the wire unit everywhere in Connect; rupees are the display unit. */
|
|
20
|
+
export declare function formatPrice(paise: number): string;
|
|
21
|
+
/**
|
|
22
|
+
* An annual plan's price is 12 cycles of the same product, so any comparison
|
|
23
|
+
* across billing intervals has to normalise first - otherwise every annual
|
|
24
|
+
* plan reads as an upgrade over every monthly one.
|
|
25
|
+
*/
|
|
26
|
+
export declare function monthlyOf(price: number, billingInterval: Plan["billingInterval"]): number;
|
|
27
|
+
export declare function discountLabel(discount: AppliedDiscount): string;
|
|
28
|
+
/**
|
|
29
|
+
* The minimum a plan-like object has to expose to be grouped or compared -
|
|
30
|
+
* lets the dialog pass a `SubscribedPlan` (which carries no add-ons or
|
|
31
|
+
* features) wherever a comparison is wanted.
|
|
32
|
+
*/
|
|
33
|
+
export interface ComparablePlan {
|
|
34
|
+
name: string;
|
|
35
|
+
price: number;
|
|
36
|
+
billingInterval: Plan["billingInterval"];
|
|
37
|
+
planGroup?: string | null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Falls back to a slug of the name for a Connect deployment predating
|
|
41
|
+
* `planGroup` on the wire, mirroring `resolvePlanGroup` server-side. Kept so
|
|
42
|
+
* an SDK upgrade doesn't require the partner's Connect instance to be
|
|
43
|
+
* upgraded in lockstep - an older server simply omits the field and the grid
|
|
44
|
+
* groups the way it always did.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolvePlanGroup(plan: ComparablePlan): string;
|
|
47
|
+
/** One tier of the catalog: the product, and whichever cadences it is sold at. */
|
|
48
|
+
export interface PlanTier {
|
|
49
|
+
planGroup: string;
|
|
50
|
+
name: string;
|
|
51
|
+
description: string;
|
|
52
|
+
monthly: Plan | null;
|
|
53
|
+
annual: Plan | null;
|
|
54
|
+
/** Whole-percent saving from paying annually, or `null` when this tier has no pair to compare. */
|
|
55
|
+
annualSavingPercent: number | null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Collapses a flat plan list into one card per tier.
|
|
59
|
+
*
|
|
60
|
+
* This is the shape the grid wants and the old one didn't have. It used to
|
|
61
|
+
* filter the whole list down to the toggled interval, which meant a tier sold
|
|
62
|
+
* monthly-only simply vanished when a customer looked at annual pricing, and a
|
|
63
|
+
* catalog with no monthly plans at all rendered an empty grid on first paint.
|
|
64
|
+
* Grouping first means the toggle picks a *price inside a card*, and a card
|
|
65
|
+
* with only one cadence still shows.
|
|
66
|
+
*
|
|
67
|
+
* Ordered by the tier's cheapest monthly-equivalent price, so the grid reads
|
|
68
|
+
* left-to-right cheapest-first regardless of what order the API returned.
|
|
69
|
+
*/
|
|
70
|
+
export declare function groupPlansByTier(plans: readonly Plan[]): PlanTier[];
|
|
71
|
+
/**
|
|
72
|
+
* Annual is quoted per year on the wire (`billingInterval: "annual"`), so a
|
|
73
|
+
* side-by-side grid has to normalise before it can compare. Showing the saving
|
|
74
|
+
* against 12x the monthly plan is the comparison a customer is actually making.
|
|
75
|
+
*
|
|
76
|
+
* **Call this with a matched pair from one tier.** It used to be handed the
|
|
77
|
+
* first monthly and the first annual plan in the whole response - two plans
|
|
78
|
+
* that were the same tier only by the accident of document order, and that
|
|
79
|
+
* produced one badge for a catalog where each tier discounts differently.
|
|
80
|
+
* `groupPlansByTier` now does the pairing.
|
|
81
|
+
*/
|
|
82
|
+
export declare function annualSaving(monthly: Plan | null | undefined, annual: Plan | null | undefined): number | null;
|
|
83
|
+
/**
|
|
84
|
+
* What moving to `plan` would be, given what the org is on today.
|
|
85
|
+
*
|
|
86
|
+
* `switch-to-annual`/`switch-to-monthly` exist because a change of *cadence*
|
|
87
|
+
* is neither an upgrade nor a downgrade, and calling it one is not a wording
|
|
88
|
+
* problem. Connect picks the use-case that runs from the same classification
|
|
89
|
+
* (`classifyPlanChange` in `packages/data`), and a same-tier move to annual
|
|
90
|
+
* compares *cheaper* per month - so it used to be sent down the downgrade
|
|
91
|
+
* path, where the price delta across cadences is negative, floors to zero,
|
|
92
|
+
* and settles the whole switch for no money at all.
|
|
93
|
+
*/
|
|
94
|
+
export type PlanAction = "current" | "upgrade" | "downgrade" | "switch-to-annual" | "switch-to-monthly" | "subscribe";
|
|
95
|
+
export declare function resolveAction(plan: Plan, current: SubscriptionResponse | null): PlanAction;
|
|
96
|
+
export declare const ACTION_LABEL: Record<PlanAction, string>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ConnectPlansProps } from "./plans.js";
|
|
2
|
+
export interface ConnectPlansPageProps extends ConnectPlansProps {
|
|
3
|
+
title?: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
/**
|
|
6
|
+
* Show the current subscription above the grid. On by default - someone
|
|
7
|
+
* arriving at a pricing page while already subscribed is usually here to
|
|
8
|
+
* change something, and the first thing they need is what they are on now.
|
|
9
|
+
*/
|
|
10
|
+
showCurrentSubscription?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A complete `/plans` page, assembled from the pieces so the host app's route
|
|
14
|
+
* file is one line:
|
|
15
|
+
*
|
|
16
|
+
* ```tsx
|
|
17
|
+
* // app/plans/page.tsx
|
|
18
|
+
* "use client";
|
|
19
|
+
* export { ConnectPlansPage as default } from "@cosmoops/connect-sdk/client";
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* The assembly is the value here, not the layout. Three things have to be on
|
|
23
|
+
* this page and are easy to leave off:
|
|
24
|
+
*
|
|
25
|
+
* 1. **The readiness banner, above the grid.** A workspace that still needs
|
|
26
|
+
* KYC can press Subscribe all day and be refused at the last step. Saying so
|
|
27
|
+
* before they pick is the difference between a page that works and one that
|
|
28
|
+
* ends in a rejected charge.
|
|
29
|
+
* 2. **What they're on now**, so "Upgrade" on a card has something to mean.
|
|
30
|
+
* 3. **A signed-out state that is a login button**, not an empty grid - the
|
|
31
|
+
* catalogue reads through the bridge, which needs a session.
|
|
32
|
+
*
|
|
33
|
+
* Every prop `ConnectPlans` takes passes straight through, and each piece is
|
|
34
|
+
* exported on its own for an app that wants a different arrangement.
|
|
35
|
+
*/
|
|
36
|
+
export declare function ConnectPlansPage({ title, description, showCurrentSubscription, ...plansProps }: ConnectPlansPageProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface ConnectPlansProps {
|
|
2
|
+
/** Restrict the grid to these plan ids, in this order. Defaults to every active plan. */
|
|
3
|
+
planIds?: string[];
|
|
4
|
+
/** Hide the coupon field. */
|
|
5
|
+
hideCoupon?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The plan table: monthly/annual toggle, features, add-ons, the discount
|
|
10
|
+
* actually in effect, and the subscribe / upgrade / downgrade flows.
|
|
11
|
+
*
|
|
12
|
+
* ## Where the flow runs, and where it finishes
|
|
13
|
+
*
|
|
14
|
+
* The *flow* is here: picking a plan, seeing what it costs with GST, being
|
|
15
|
+
* told what happens to the cycle you are part-way through, and confirming.
|
|
16
|
+
* The *payment* is not, and that is deliberate. A plan change is not one
|
|
17
|
+
* write - it re-runs the readiness gates, prices proration against
|
|
18
|
+
* accumulated credit, re-checks the RBI mandate ceiling for the new amount,
|
|
19
|
+
* and issues a GST invoice. Connect owns that sequence end to end; a
|
|
20
|
+
* partner-side "change plan" call would be a second implementation of it
|
|
21
|
+
* that drifts. It would also mean a browser holding the partner's
|
|
22
|
+
* credentials could move money, which is the one thing the bridge exists to
|
|
23
|
+
* prevent.
|
|
24
|
+
*
|
|
25
|
+
* So confirming opens Connect - on the *exact* confirmation screen for the
|
|
26
|
+
* plan just picked, via an intercepted parallel route, not a catalogue the
|
|
27
|
+
* customer has to search again - and this component watches `/entitlements`
|
|
28
|
+
* until the change lands, then repaints itself. See `useConnectCheckout`.
|
|
29
|
+
*
|
|
30
|
+
* Coupon codes work the same way: the field carries the code into Connect's
|
|
31
|
+
* checkout, where it is validated and applied against the real cart. Anything
|
|
32
|
+
* this component claimed about a code would be a guess it cannot honour.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ConnectPlans({ planIds, hideCoupon, className }: ConnectPlansProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export interface ConnectReadinessBannerProps {
|
|
2
|
+
/** Show advisory blockers too. Off by default - they are not a reason to interrupt anyone mid-task. */
|
|
3
|
+
includeAdvisory?: boolean;
|
|
4
|
+
/** Render nothing at all once the workspace is ready. On by default. */
|
|
5
|
+
hideWhenReady?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Every gate between this workspace and your service, with the way out of each.
|
|
10
|
+
*
|
|
11
|
+
* This is the component that keeps a blocked customer from staring at a broken
|
|
12
|
+
* app. `getReadiness` resolves subscription state, KYC/KYB, a chargeable
|
|
13
|
+
* payment method and seat headroom in one call, and **each blocker carries a
|
|
14
|
+
* `resolveUrl` into the exact Connect screen that fixes it** - so being blocked
|
|
15
|
+
* comes with somewhere to go rather than a refusal.
|
|
16
|
+
*
|
|
17
|
+
* Render it high on any page your service gates. It draws nothing at all when
|
|
18
|
+
* the workspace is ready, so it is safe to leave mounted permanently.
|
|
19
|
+
*
|
|
20
|
+
* Two deliberate refusals:
|
|
21
|
+
*
|
|
22
|
+
* - **Unrecognised codes are still shown, and still treated as blocking.**
|
|
23
|
+
* Connect adds codes without a major version (see `ReadinessBlockerCode`), so
|
|
24
|
+
* a switch that only knew today's codes would silently drop tomorrow's - the
|
|
25
|
+
* one failure mode where a customer is locked out with no explanation.
|
|
26
|
+
* - **`message` is rendered, never parsed.** It is human-facing and subject to
|
|
27
|
+
* rewording; branching on its text would break on a copy edit.
|
|
28
|
+
*/
|
|
29
|
+
export declare function ConnectReadinessBanner({ includeAdvisory, hideWhenReady, className, }: ConnectReadinessBannerProps): import("react").JSX.Element | null;
|
|
30
|
+
export interface ConnectReadinessGateProps {
|
|
31
|
+
children: React.ReactNode;
|
|
32
|
+
/** Rendered instead of `children` while blocked. Defaults to the banner in a card. */
|
|
33
|
+
fallback?: React.ReactNode;
|
|
34
|
+
/** Shown while the first readiness read is in flight. */
|
|
35
|
+
loading?: React.ReactNode;
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Renders `children` only once the workspace clears every blocking gate.
|
|
40
|
+
*
|
|
41
|
+
* The hard version of `ConnectReadinessBanner`, for a route that genuinely
|
|
42
|
+
* cannot function while blocked. Prefer the banner where the page still does
|
|
43
|
+
* something useful - a gate that hides a whole screen behind a verification
|
|
44
|
+
* notice is a worse experience than one that lets people look around while
|
|
45
|
+
* they sort it out.
|
|
46
|
+
*
|
|
47
|
+
* **This is a UX gate, not a security boundary.** The readiness read reaches
|
|
48
|
+
* your own origin and a determined browser can ignore whatever it says. The
|
|
49
|
+
* authoritative check is `client.entitlements.getReadiness` on your server,
|
|
50
|
+
* before you do the thing.
|
|
51
|
+
*/
|
|
52
|
+
export declare function ConnectReadinessGate({ children, fallback, loading, className, }: ConnectReadinessGateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type PlanAction } from "./plan-pricing.js";
|
|
2
|
+
import type { Plan, SubscriptionResponse } from "../../types.js";
|
|
3
|
+
export interface ConnectSubscribeDialogProps {
|
|
4
|
+
/** `null` closes it. The plan being subscribed to or moved to. */
|
|
5
|
+
plan: Plan | null;
|
|
6
|
+
/** Which of subscribe / upgrade / downgrade this is - decides the headline and what the notice says about money. */
|
|
7
|
+
action: PlanAction;
|
|
8
|
+
/** The org's live subscription, for the "from" side of a plan change. */
|
|
9
|
+
current: SubscriptionResponse | null;
|
|
10
|
+
/** Coupon typed into the plan grid, echoed here so it is visible before the hand-off carries it. */
|
|
11
|
+
coupon?: string;
|
|
12
|
+
/** Whether this org's `plan.trialDays` still applies is Connect's call, not this component's - see the notice below. */
|
|
13
|
+
onClose(): void;
|
|
14
|
+
onConfirm(): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The review step before a customer is sent to Connect.
|
|
18
|
+
*
|
|
19
|
+
* It exists because the hand-off is a context switch, and a context switch
|
|
20
|
+
* the customer did not expect reads as being dumped somewhere. So this says
|
|
21
|
+
* what they are about to buy, what it costs with GST, what happens to the
|
|
22
|
+
* cycle they are part-way through, and - plainly - that the payment itself
|
|
23
|
+
* happens on Connect. Then one button, which opens it.
|
|
24
|
+
*
|
|
25
|
+
* **Every number here is a preview, and deliberately never the last word.**
|
|
26
|
+
* The authoritative price is computed by Connect against the real cart:
|
|
27
|
+
* proration is priced against the actual cycle, a coupon is validated
|
|
28
|
+
* against the plan it is being applied to, trial eligibility depends on
|
|
29
|
+
* whether this organization has ever subscribed to this service before, and
|
|
30
|
+
* an accumulated credit is deducted. None of that is knowable from the
|
|
31
|
+
* partner's origin, so this component states the list price and says where
|
|
32
|
+
* the final figure comes from rather than quietly guessing at one.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ConnectSubscribeDialog({ plan, action, current, coupon, onClose, onConfirm, }: Readonly<ConnectSubscribeDialogProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { SubscribedPlan, SubscriptionDetail, SubscriptionResponse } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* What a subscription is actually doing, collapsed to the five cases worth
|
|
5
|
+
* rendering differently.
|
|
6
|
+
*
|
|
7
|
+
* `status` alone cannot answer this. `"active"` covers both a paying customer
|
|
8
|
+
* and one still in a trial (`isTrialing` on the session block is what splits
|
|
9
|
+
* them), and it says nothing about a subscription winding down -
|
|
10
|
+
* `cancelAtPeriodEnd` is a separate field precisely so a cancelling
|
|
11
|
+
* subscription is not mistaken for a renewing one.
|
|
12
|
+
*/
|
|
13
|
+
export type ConnectSubscriptionState = "none" | "trialing" | "active" | "cancelling"
|
|
14
|
+
/** `"created"`/`"authenticated"` - subscribed, but the first debit has not confirmed yet. */
|
|
15
|
+
| "pending"
|
|
16
|
+
/** `"paused"` (dunning exhausted) or `"cancelled"` - access is gone or going. */
|
|
17
|
+
| "problem";
|
|
18
|
+
export declare function resolveSubscriptionState(subscription: SubscriptionResponse | null, isTrialing: boolean): ConnectSubscriptionState;
|
|
19
|
+
export interface ConnectNoSubscriptionCardProps {
|
|
20
|
+
/** Where your plan catalogue is mounted. Defaults to `/plans`. */
|
|
21
|
+
plansHref?: string;
|
|
22
|
+
/** Override the headline - "Upgrade to unlock reports", say, rather than the generic one. */
|
|
23
|
+
title?: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The "you are not on a plan yet" card.
|
|
29
|
+
*
|
|
30
|
+
* Points at your **own** `/plans` page rather than opening Connect, and that is
|
|
31
|
+
* the deliberate part: choosing a plan is browsing, it belongs in your product
|
|
32
|
+
* where your pricing story is, and only the final confirmation needs to happen
|
|
33
|
+
* on Connect. Sending someone straight out of the app to pick is a context
|
|
34
|
+
* switch two steps too early.
|
|
35
|
+
*
|
|
36
|
+
* Rendered on its own it is just a card; `ConnectSubscriptionGate` is the usual
|
|
37
|
+
* way in, since it picks this only when there is genuinely nothing to show.
|
|
38
|
+
*/
|
|
39
|
+
export declare function ConnectNoSubscriptionCard({ plansHref, title, description, className, }: ConnectNoSubscriptionCardProps): import("react").JSX.Element;
|
|
40
|
+
export interface ConnectSubscriptionCardProps {
|
|
41
|
+
plansHref?: string;
|
|
42
|
+
className?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The current subscription at a glance: plan, what it costs, what happens next,
|
|
46
|
+
* and one way into Connect to change it.
|
|
47
|
+
*
|
|
48
|
+
* The counterpart to `ConnectNoSubscriptionCard` - the same slot in the
|
|
49
|
+
* signed-up state - so an account or settings page can render this and get the
|
|
50
|
+
* right thing either way.
|
|
51
|
+
*
|
|
52
|
+
* Dates are formatted, never computed. "Renews on 3 Mar" is a fact from the
|
|
53
|
+
* wire; "renews in 12 days" would be a clock read during render, which is
|
|
54
|
+
* impure and re-renders wrong.
|
|
55
|
+
*/
|
|
56
|
+
export declare function ConnectSubscriptionCard({ plansHref, className }: ConnectSubscriptionCardProps): import("react").JSX.Element;
|
|
57
|
+
/**
|
|
58
|
+
* Seats used against what the plan includes.
|
|
59
|
+
*
|
|
60
|
+
* Only meaningful for `"fixed"` and `"per-seat"` - `"unlimited"` has nothing to
|
|
61
|
+
* count against, so it renders nothing rather than a meter that is always
|
|
62
|
+
* empty. Under `"per-seat"` going over is billable rather than blocked, so it
|
|
63
|
+
* says what the extra costs instead of warning.
|
|
64
|
+
*/
|
|
65
|
+
export declare function ConnectSeatUsage({ plan, detail, className, }: Readonly<{
|
|
66
|
+
plan: SubscribedPlan;
|
|
67
|
+
detail: SubscriptionDetail;
|
|
68
|
+
className?: string;
|
|
69
|
+
}>): import("react").JSX.Element | null;
|
|
70
|
+
export interface ConnectTrialBannerProps {
|
|
71
|
+
plansHref?: string;
|
|
72
|
+
className?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A trial that is running, and when it converts.
|
|
76
|
+
*
|
|
77
|
+
* Renders only while trialing, so it can live permanently in a layout. It says
|
|
78
|
+
* the charge date rather than a countdown for the same reason
|
|
79
|
+
* `ConnectSubscriptionCard` does - a countdown means reading the clock while
|
|
80
|
+
* rendering.
|
|
81
|
+
*
|
|
82
|
+
* The wire carries `isTrialing` but no trial *end* date; `nextBillingDate` on a
|
|
83
|
+
* trialing subscription is the first charge, which is the date a customer
|
|
84
|
+
* actually cares about anyway.
|
|
85
|
+
*/
|
|
86
|
+
export declare function ConnectTrialBanner({ plansHref, className }: ConnectTrialBannerProps): import("react").JSX.Element | null;
|
|
87
|
+
export interface ConnectSubscriptionGateProps {
|
|
88
|
+
children: ReactNode;
|
|
89
|
+
/** Where your plan catalogue is mounted. Defaults to `/plans`. */
|
|
90
|
+
plansHref?: string;
|
|
91
|
+
/** Replaces the default "not on a plan yet" card. */
|
|
92
|
+
fallback?: ReactNode;
|
|
93
|
+
/** Shown while the first read is in flight. Defaults to a skeleton, never a fallback - see below. */
|
|
94
|
+
loading?: ReactNode;
|
|
95
|
+
/**
|
|
96
|
+
* Let a trialing subscription through. On by default: a trial is a
|
|
97
|
+
* subscription, and gating it out is how a customer gets sold a trial and
|
|
98
|
+
* then locked out of it.
|
|
99
|
+
*/
|
|
100
|
+
allowTrialing?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Let a subscription whose first debit hasn't confirmed through. On by
|
|
103
|
+
* default - the charge settles on a webhook and can take minutes, and the
|
|
104
|
+
* alternative is telling someone who just paid that they haven't.
|
|
105
|
+
*/
|
|
106
|
+
allowPending?: boolean;
|
|
107
|
+
className?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Renders `children` for a subscribed workspace, and the "pick a plan" card for
|
|
111
|
+
* everyone else.
|
|
112
|
+
*
|
|
113
|
+
* **Never renders the fallback while loading.** That flash - "you're not
|
|
114
|
+
* subscribed" for 200ms, then the real content - is the specific bug this
|
|
115
|
+
* component exists to make impossible, and it is what hand-rolled versions of
|
|
116
|
+
* it get wrong: the honest states are "still asking" and "asked, and the answer
|
|
117
|
+
* is no", and only the second one is a sales pitch.
|
|
118
|
+
*
|
|
119
|
+
* **This is a UX gate, not a security boundary** - same caveat as
|
|
120
|
+
* `ConnectReadinessGate`. Anything that must not happen without a subscription
|
|
121
|
+
* is checked on your server with `client.entitlements.hasFeature`.
|
|
122
|
+
*/
|
|
123
|
+
export declare function ConnectSubscriptionGate({ children, plansHref, fallback, loading, allowTrialing, allowPending, className, }: ConnectSubscriptionGateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ConnectUsageMeterProps {
|
|
2
|
+
/** Restrict to these add-on ids, in this order. Defaults to every metered add-on. */
|
|
3
|
+
addonIds?: string[];
|
|
4
|
+
/** Render nothing when there is nothing to meter, instead of an empty-state card. On by default. */
|
|
5
|
+
hideWhenEmpty?: boolean;
|
|
6
|
+
title?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* How much of each consumable add-on this workspace has left.
|
|
11
|
+
*
|
|
12
|
+
* Reads the balance Connect actually debits, so the number here and the number
|
|
13
|
+
* `consumeAddon` enforces cannot disagree. Before the `addons:read` endpoint
|
|
14
|
+
* existed this component was impossible to write honestly: a service could
|
|
15
|
+
* spend an allowance down on every request and the only thing the API exposed
|
|
16
|
+
* was the list of add-on *ids* on the subscription.
|
|
17
|
+
*
|
|
18
|
+
* **It shows `balance` against `includedPerCycle`, and never a "used" figure.**
|
|
19
|
+
* With `carryForward` an unspent balance survives the cycle boundary, so
|
|
20
|
+
* `included - balance` can go negative - a meter that runs backwards. Real
|
|
21
|
+
* consumption for a cycle is a ledger question, and computing it from a
|
|
22
|
+
* balance would be a guess rendered as a fact.
|
|
23
|
+
*/
|
|
24
|
+
export declare function ConnectUsageMeter({ addonIds, hideWhenEmpty, title, className, }: ConnectUsageMeterProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { ThemeMode } from "../../types.js";
|
|
2
|
+
export interface ConnectUserMenuProps {
|
|
3
|
+
/** Hide the name beside the avatar - for a dense top bar. */
|
|
4
|
+
compact?: boolean;
|
|
5
|
+
/** Called after sign-out completes, e.g. to route home. */
|
|
6
|
+
onSignOut?: () => void;
|
|
7
|
+
className?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Current theme, and where to send a change - the SDK has no theme
|
|
10
|
+
* provider of its own (no `next-themes` dependency), so this is entirely
|
|
11
|
+
* host-controlled. The Appearance section only renders when both are
|
|
12
|
+
* supplied; omit either to leave theme control out of the modal.
|
|
13
|
+
*/
|
|
14
|
+
theme?: ThemeMode;
|
|
15
|
+
onThemeChange?: (theme: ThemeMode) => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Avatar and name in the trigger; an identity card, the three Connect
|
|
19
|
+
* destinations (Profile, Billing, Connect), an optional appearance control,
|
|
20
|
+
* this account's active sessions, and sign-out in the modal it opens.
|
|
21
|
+
*
|
|
22
|
+
* Profile/Billing/Connect open in a **new tab**, each marked with an
|
|
23
|
+
* external-link icon. They are a different application at a different
|
|
24
|
+
* origin, and navigating the host app away to reach them would lose
|
|
25
|
+
* whatever the user was doing here. Sign out is the only action that acts
|
|
26
|
+
* in place, which is why it sits alone in the footer rather than as a fourth
|
|
27
|
+
* item in the same list as three navigations.
|
|
28
|
+
*
|
|
29
|
+
* The session list is account-wide, not scoped to this service - see
|
|
30
|
+
* `ConnectUserSession`'s doc comment in `types.ts`. Appearance only renders
|
|
31
|
+
* when both `theme` and `onThemeChange` are supplied.
|
|
32
|
+
*
|
|
33
|
+
* Renders nothing when signed out - pair it with `<ConnectLoginButton>`, which
|
|
34
|
+
* renders nothing when signed *in*, and the two swap cleanly with no branch in
|
|
35
|
+
* your own layout.
|
|
36
|
+
*
|
|
37
|
+
* On the HeroUI shape: the trigger is a plain `<Button>` as a **direct child**
|
|
38
|
+
* of `<Modal>`, not wrapped in `<Modal.Trigger>`. `Dropdown.Trigger` (and by
|
|
39
|
+
* the same construction, `Modal.Trigger`) is itself a React Aria `Button`, so
|
|
40
|
+
* wrapping one produces a button inside a button - invalid markup, and press
|
|
41
|
+
* handling stops working. Kept uncontrolled (no `isOpen`/`onOpenChange`),
|
|
42
|
+
* matching `<ConnectAppsGrid>`'s own `<Modal>` - nothing here needs to close
|
|
43
|
+
* the modal programmatically; sign-out uses `slot="close"` instead.
|
|
44
|
+
*/
|
|
45
|
+
export declare function ConnectUserMenu({ compact, onSignOut, className, theme, onThemeChange, }: ConnectUserMenuProps): import("react").JSX.Element | null;
|
|
46
|
+
/**
|
|
47
|
+
* The "Manage subscription" action on its own, for layouts that want it
|
|
48
|
+
* visible rather than buried in the account menu - a billing banner, an empty
|
|
49
|
+
* state, a settings page.
|
|
50
|
+
*/
|
|
51
|
+
export declare function ConnectManageSubscriptionButton({ className }: Readonly<{
|
|
52
|
+
className?: string;
|
|
53
|
+
}>): import("react").JSX.Element;
|
|
54
|
+
/**
|
|
55
|
+
* Invoices and payment history, on Connect.
|
|
56
|
+
*
|
|
57
|
+
* A deep link rather than a component that lists them, and that is not a
|
|
58
|
+
* placeholder: nothing in `/api/v1/service/*` exposes invoices, so an SDK-side
|
|
59
|
+
* list would have nothing to read. It is also the right answer regardless -
|
|
60
|
+
* a GST tax invoice is a legal document with a fixed format, downloadable and
|
|
61
|
+
* emailed from one place, and a partner-rendered copy of one would be a second
|
|
62
|
+
* version of a record that must have exactly one.
|
|
63
|
+
*/
|
|
64
|
+
export declare function ConnectInvoicesButton({ className }: Readonly<{
|
|
65
|
+
className?: string;
|
|
66
|
+
}>): import("react").JSX.Element | null;
|
|
67
|
+
/**
|
|
68
|
+
* The "Profile" action on its own - the third of the three Connect
|
|
69
|
+
* destinations, alongside `ConnectManageSubscriptionButton` (Billing) and
|
|
70
|
+
* `ConnectHomeButton`.
|
|
71
|
+
*
|
|
72
|
+
* It was reachable only from inside `ConnectUserMenu`, which meant an app that
|
|
73
|
+
* builds its own account menu had to hardcode `${appUrl}/profile` to offer it.
|
|
74
|
+
*/
|
|
75
|
+
export declare function ConnectProfileButton({ className }: Readonly<{
|
|
76
|
+
className?: string;
|
|
77
|
+
}>): import("react").JSX.Element | null;
|
|
78
|
+
/** A plain "Open Connect" button, for a footer or a help menu. */
|
|
79
|
+
export declare function ConnectHomeButton({ className }: Readonly<{
|
|
80
|
+
className?: string;
|
|
81
|
+
}>): import("react").JSX.Element;
|
|
82
|
+
/** Sign out on its own, for a settings page that wants it as a destructive row. */
|
|
83
|
+
export declare function ConnectSignOutButton({ onSignOut, className, }: Readonly<{
|
|
84
|
+
onSignOut?: () => void;
|
|
85
|
+
className?: string;
|
|
86
|
+
}>): import("react").JSX.Element | null;
|