@cosmoops/connect-sdk 0.3.0 → 0.7.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/CHANGELOG.md +125 -0
- package/README.md +215 -6
- package/dist/cjs/cli/doctor.js +3 -3
- package/dist/cjs/cli/init.js +3 -3
- package/dist/cjs/client/components/access-gate.js +162 -0
- package/dist/cjs/client/components/account-sessions.js +24 -22
- package/dist/cjs/client/components/app-shell.js +157 -0
- package/dist/cjs/client/components/apps-grid.js +4 -3
- package/dist/cjs/client/components/feature-gate.js +2 -2
- package/dist/cjs/client/components/integrations-modal.js +95 -0
- package/dist/cjs/client/components/logo.js +3 -3
- package/dist/cjs/client/components/motion.js +27 -0
- package/dist/cjs/client/components/nav.js +97 -0
- package/dist/cjs/client/components/plan-pricing.js +1 -1
- package/dist/cjs/client/components/plans.js +42 -40
- package/dist/cjs/client/components/readiness.js +6 -4
- package/dist/cjs/client/components/side-nav.js +58 -0
- package/dist/cjs/client/components/subscribe-dialog.js +2 -2
- package/dist/cjs/client/components/subscription.js +3 -2
- package/dist/cjs/client/components/surfaces.js +54 -0
- package/dist/cjs/client/components/usage-meter.js +4 -3
- package/dist/cjs/client/components/user-menu.js +33 -6
- package/dist/cjs/client/index.js +30 -2
- package/dist/cjs/client/mark.js +1 -1
- package/dist/cjs/client/provider.js +60 -8
- package/dist/cjs/client/use-active-path.js +77 -0
- package/dist/cjs/client/use-checkout.js +3 -3
- package/dist/cjs/errors.js +4 -4
- package/dist/cjs/helpers.js +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/next/index.js +96 -15
- package/dist/cjs/server/client.js +22 -14
- package/dist/cjs/server/handler.js +99 -16
- package/dist/cjs/server/http.js +1 -1
- package/dist/cjs/server/index.js +8 -1
- package/dist/cjs/server/resources/access.js +3 -3
- package/dist/cjs/server/resources/ai.js +1 -1
- package/dist/cjs/server/resources/analytics.js +66 -0
- package/dist/cjs/server/resources/apps.js +4 -4
- package/dist/cjs/server/resources/billing.js +5 -5
- package/dist/cjs/server/resources/drive.js +4 -4
- package/dist/cjs/server/resources/entitlements.js +7 -7
- package/dist/cjs/server/resources/identity.js +4 -4
- package/dist/cjs/server/resources/integrations.js +66 -0
- package/dist/cjs/server/resources/logs.js +3 -3
- package/dist/cjs/server/resources/sessions.js +6 -6
- package/dist/cjs/server/webhooks.js +127 -0
- package/dist/cjs/types.js +1 -1
- package/dist/esm/cli/doctor.js +3 -3
- package/dist/esm/cli/init.js +3 -3
- package/dist/esm/client/components/access-gate.js +158 -0
- package/dist/esm/client/components/account-sessions.js +24 -22
- package/dist/esm/client/components/app-shell.js +154 -0
- package/dist/esm/client/components/apps-grid.js +4 -3
- package/dist/esm/client/components/feature-gate.js +2 -2
- package/dist/esm/client/components/integrations-modal.js +92 -0
- package/dist/esm/client/components/logo.js +3 -3
- package/dist/esm/client/components/motion.js +21 -0
- package/dist/esm/client/components/nav.js +89 -0
- package/dist/esm/client/components/plan-pricing.js +1 -1
- package/dist/esm/client/components/plans.js +42 -40
- package/dist/esm/client/components/readiness.js +6 -4
- package/dist/esm/client/components/side-nav.js +53 -0
- package/dist/esm/client/components/subscribe-dialog.js +2 -2
- package/dist/esm/client/components/subscription.js +3 -2
- package/dist/esm/client/components/surfaces.js +51 -0
- package/dist/esm/client/components/usage-meter.js +4 -3
- package/dist/esm/client/components/user-menu.js +34 -7
- package/dist/esm/client/index.js +16 -2
- package/dist/esm/client/mark.js +1 -1
- package/dist/esm/client/provider.js +59 -8
- package/dist/esm/client/use-active-path.js +74 -0
- package/dist/esm/client/use-checkout.js +3 -3
- package/dist/esm/errors.js +4 -4
- package/dist/esm/helpers.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/next/index.js +95 -15
- package/dist/esm/server/client.js +22 -14
- package/dist/esm/server/handler.js +99 -16
- package/dist/esm/server/http.js +1 -1
- package/dist/esm/server/index.js +5 -0
- package/dist/esm/server/resources/access.js +3 -3
- package/dist/esm/server/resources/ai.js +1 -1
- package/dist/esm/server/resources/analytics.js +62 -0
- package/dist/esm/server/resources/apps.js +4 -4
- package/dist/esm/server/resources/billing.js +5 -5
- package/dist/esm/server/resources/drive.js +4 -4
- package/dist/esm/server/resources/entitlements.js +7 -7
- package/dist/esm/server/resources/identity.js +4 -4
- package/dist/esm/server/resources/integrations.js +62 -0
- package/dist/esm/server/resources/logs.js +3 -3
- package/dist/esm/server/resources/sessions.js +6 -6
- package/dist/esm/server/webhooks.js +123 -0
- package/dist/esm/types.js +1 -1
- package/dist/theme.css +28 -0
- package/dist/types/client/components/access-gate.d.ts +79 -0
- package/dist/types/client/components/account-sessions.d.ts +1 -1
- package/dist/types/client/components/app-shell.d.ts +115 -0
- package/dist/types/client/components/apps-grid.d.ts +1 -1
- package/dist/types/client/components/feature-gate.d.ts +1 -1
- package/dist/types/client/components/integrations-modal.d.ts +21 -0
- package/dist/types/client/components/logo.d.ts +5 -5
- package/dist/types/client/components/motion.d.ts +22 -0
- package/dist/types/client/components/nav.d.ts +110 -0
- package/dist/types/client/components/plan-pricing.d.ts +2 -2
- package/dist/types/client/components/readiness.d.ts +2 -2
- package/dist/types/client/components/side-nav.d.ts +31 -0
- package/dist/types/client/components/subscribe-dialog.d.ts +3 -3
- package/dist/types/client/components/surfaces.d.ts +51 -0
- package/dist/types/client/components/usage-meter.d.ts +1 -1
- package/dist/types/client/components/user-menu.d.ts +2 -2
- package/dist/types/client/index.d.ts +13 -2
- package/dist/types/client/mark.d.ts +1 -1
- package/dist/types/client/provider.d.ts +44 -9
- package/dist/types/client/use-active-path.d.ts +8 -0
- package/dist/types/client/use-checkout.d.ts +3 -3
- package/dist/types/errors.d.ts +4 -4
- package/dist/types/helpers.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/next/index.d.ts +40 -0
- package/dist/types/server/client.d.ts +17 -11
- package/dist/types/server/handler.d.ts +2 -2
- package/dist/types/server/index.d.ts +7 -0
- package/dist/types/server/resources/access.d.ts +3 -3
- package/dist/types/server/resources/ai.d.ts +2 -2
- package/dist/types/server/resources/analytics.d.ts +31 -0
- package/dist/types/server/resources/apps.d.ts +4 -4
- package/dist/types/server/resources/billing.d.ts +4 -4
- package/dist/types/server/resources/drive.d.ts +4 -4
- package/dist/types/server/resources/entitlements.d.ts +4 -4
- package/dist/types/server/resources/identity.d.ts +14 -4
- package/dist/types/server/resources/integrations.d.ts +40 -0
- package/dist/types/server/resources/logs.d.ts +3 -3
- package/dist/types/server/resources/sessions.d.ts +5 -5
- package/dist/types/server/webhooks.d.ts +67 -0
- package/dist/types/types.d.ts +220 -39
- package/package.json +10 -4
package/dist/cjs/client/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
4
|
+
exports.ConnectFeatureGate = exports.useConnectAccessGate = exports.ConnectAccessGate = exports.ConnectReadinessGate = exports.ConnectReadinessBanner = exports.resolveSubscriptionState = exports.ConnectSeatUsage = exports.ConnectTrialBanner = exports.ConnectSubscriptionCard = exports.ConnectNoSubscriptionCard = exports.ConnectSubscriptionGate = exports.ConnectSubscribeDialog = exports.ConnectPlans = exports.ConnectIntegrationsModal = exports.ConnectAppsGrid = exports.gateExemptPaths = exports.isNavItemActive = exports.resolveActivePath = exports.normalizePath = exports.flattenNav = exports.normalizeNav = exports.useActivePath = exports.ConnectSideNav = exports.ConnectAppShell = exports.ConnectAccountSessions = exports.ConnectSignOutButton = exports.ConnectHomeButton = exports.ConnectProfileButton = exports.ConnectInvoicesButton = exports.ConnectManageSubscriptionButton = exports.ConnectUserMenu = exports.ConnectRegisterButton = exports.ConnectLoginButton = exports.ConnectLogo = exports.ConnectMark = exports.isConnectError = exports.ConnectError = exports.normalizePlanFeatures = exports.blockingBlockers = exports.CONNECT_APP_URL = exports.useConnectResource = exports.useConnectIntegrations = exports.useConnectSessions = exports.useConnectAddonUsage = exports.useConnectApps = exports.useConnectPlans = exports.useConnectEntitlements = exports.useConnectUser = exports.useConnect = exports.ConnectProvider = void 0;
|
|
5
|
+
exports.resolvePlanGroup = exports.groupPlansByTier = exports.ACTION_LABEL = exports.discountLabel = exports.annualSaving = exports.resolveAction = exports.monthlyOf = exports.formatPrice = exports.buildCheckoutUrl = exports.useConnectCheckout = exports.ConnectPlansPage = exports.ConnectUsageMeter = exports.useConnectFeature = void 0;
|
|
5
6
|
/**
|
|
6
7
|
* Browser half of `@cosmoops/connect-sdk` - React components and hooks.
|
|
7
8
|
*
|
|
@@ -11,7 +12,7 @@ exports.resolvePlanGroup = exports.groupPlansByTier = exports.ACTION_LABEL = exp
|
|
|
11
12
|
*
|
|
12
13
|
* Styling is HeroUI v3 semantic tokens only (`accent`, `muted`, `surface`,
|
|
13
14
|
* `separator`, ...), never a hardcoded colour - so these components inherit
|
|
14
|
-
* whatever theme the host
|
|
15
|
+
* whatever theme the host application platform already configured, and one theme
|
|
15
16
|
* change lands identically in all of them.
|
|
16
17
|
*/
|
|
17
18
|
var provider_js_1 = require("./provider.js");
|
|
@@ -23,6 +24,7 @@ Object.defineProperty(exports, "useConnectPlans", { enumerable: true, get: funct
|
|
|
23
24
|
Object.defineProperty(exports, "useConnectApps", { enumerable: true, get: function () { return provider_js_1.useConnectApps; } });
|
|
24
25
|
Object.defineProperty(exports, "useConnectAddonUsage", { enumerable: true, get: function () { return provider_js_1.useConnectAddonUsage; } });
|
|
25
26
|
Object.defineProperty(exports, "useConnectSessions", { enumerable: true, get: function () { return provider_js_1.useConnectSessions; } });
|
|
27
|
+
Object.defineProperty(exports, "useConnectIntegrations", { enumerable: true, get: function () { return provider_js_1.useConnectIntegrations; } });
|
|
26
28
|
Object.defineProperty(exports, "useConnectResource", { enumerable: true, get: function () { return provider_js_1.useConnectResource; } });
|
|
27
29
|
Object.defineProperty(exports, "CONNECT_APP_URL", { enumerable: true, get: function () { return provider_js_1.CONNECT_APP_URL; } });
|
|
28
30
|
// Re-exported from the root entry rather than kept there alone: it is a pure
|
|
@@ -52,8 +54,31 @@ Object.defineProperty(exports, "ConnectSignOutButton", { enumerable: true, get:
|
|
|
52
54
|
// `ConnectUserMenu` was the only thing that could render it.
|
|
53
55
|
var account_sessions_js_1 = require("./components/account-sessions.js");
|
|
54
56
|
Object.defineProperty(exports, "ConnectAccountSessions", { enumerable: true, get: function () { return account_sessions_js_1.ConnectAccountSessions; } });
|
|
57
|
+
// The frame the rest of these components live inside. Exported next to the
|
|
58
|
+
// pieces it composes rather than in a section of its own - an integration
|
|
59
|
+
// reaching for a sidebar wants to find the launcher and the account menu in
|
|
60
|
+
// the same breath, since the shell already mounts both.
|
|
61
|
+
var app_shell_js_1 = require("./components/app-shell.js");
|
|
62
|
+
Object.defineProperty(exports, "ConnectAppShell", { enumerable: true, get: function () { return app_shell_js_1.ConnectAppShell; } });
|
|
63
|
+
var side_nav_js_1 = require("./components/side-nav.js");
|
|
64
|
+
Object.defineProperty(exports, "ConnectSideNav", { enumerable: true, get: function () { return side_nav_js_1.ConnectSideNav; } });
|
|
65
|
+
var use_active_path_js_1 = require("./use-active-path.js");
|
|
66
|
+
Object.defineProperty(exports, "useActivePath", { enumerable: true, get: function () { return use_active_path_js_1.useActivePath; } });
|
|
67
|
+
// The nav model is plain data and pure functions - a host generating its nav
|
|
68
|
+
// from its own route table needs the types, and `resolveActivePath` is the
|
|
69
|
+
// same longest-prefix rule the sidebar highlights with, so a breadcrumb or a
|
|
70
|
+
// page title derived from it cannot disagree with the rail.
|
|
71
|
+
var nav_js_1 = require("./components/nav.js");
|
|
72
|
+
Object.defineProperty(exports, "normalizeNav", { enumerable: true, get: function () { return nav_js_1.normalizeNav; } });
|
|
73
|
+
Object.defineProperty(exports, "flattenNav", { enumerable: true, get: function () { return nav_js_1.flattenNav; } });
|
|
74
|
+
Object.defineProperty(exports, "normalizePath", { enumerable: true, get: function () { return nav_js_1.normalizePath; } });
|
|
75
|
+
Object.defineProperty(exports, "resolveActivePath", { enumerable: true, get: function () { return nav_js_1.resolveActivePath; } });
|
|
76
|
+
Object.defineProperty(exports, "isNavItemActive", { enumerable: true, get: function () { return nav_js_1.isNavItemActive; } });
|
|
77
|
+
Object.defineProperty(exports, "gateExemptPaths", { enumerable: true, get: function () { return nav_js_1.gateExemptPaths; } });
|
|
55
78
|
var apps_grid_js_1 = require("./components/apps-grid.js");
|
|
56
79
|
Object.defineProperty(exports, "ConnectAppsGrid", { enumerable: true, get: function () { return apps_grid_js_1.ConnectAppsGrid; } });
|
|
80
|
+
var integrations_modal_js_1 = require("./components/integrations-modal.js");
|
|
81
|
+
Object.defineProperty(exports, "ConnectIntegrationsModal", { enumerable: true, get: function () { return integrations_modal_js_1.ConnectIntegrationsModal; } });
|
|
57
82
|
var plans_js_1 = require("./components/plans.js");
|
|
58
83
|
Object.defineProperty(exports, "ConnectPlans", { enumerable: true, get: function () { return plans_js_1.ConnectPlans; } });
|
|
59
84
|
var subscribe_dialog_js_1 = require("./components/subscribe-dialog.js");
|
|
@@ -73,6 +98,9 @@ Object.defineProperty(exports, "resolveSubscriptionState", { enumerable: true, g
|
|
|
73
98
|
var readiness_js_1 = require("./components/readiness.js");
|
|
74
99
|
Object.defineProperty(exports, "ConnectReadinessBanner", { enumerable: true, get: function () { return readiness_js_1.ConnectReadinessBanner; } });
|
|
75
100
|
Object.defineProperty(exports, "ConnectReadinessGate", { enumerable: true, get: function () { return readiness_js_1.ConnectReadinessGate; } });
|
|
101
|
+
var access_gate_js_1 = require("./components/access-gate.js");
|
|
102
|
+
Object.defineProperty(exports, "ConnectAccessGate", { enumerable: true, get: function () { return access_gate_js_1.ConnectAccessGate; } });
|
|
103
|
+
Object.defineProperty(exports, "useConnectAccessGate", { enumerable: true, get: function () { return access_gate_js_1.useConnectAccessGate; } });
|
|
76
104
|
var feature_gate_js_1 = require("./components/feature-gate.js");
|
|
77
105
|
Object.defineProperty(exports, "ConnectFeatureGate", { enumerable: true, get: function () { return feature_gate_js_1.ConnectFeatureGate; } });
|
|
78
106
|
Object.defineProperty(exports, "useConnectFeature", { enumerable: true, get: function () { return feature_gate_js_1.useConnectFeature; } });
|
package/dist/cjs/client/mark.js
CHANGED
|
@@ -7,7 +7,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
7
7
|
* The Connect mark - concentric rings on a solid accent badge.
|
|
8
8
|
*
|
|
9
9
|
* Painted from `--accent` / `--accent-foreground`, the same HeroUI tokens the
|
|
10
|
-
* host app themes, so the badge tracks whatever palette
|
|
10
|
+
* host app themes, so the badge tracks whatever palette an application platform has
|
|
11
11
|
* configured rather than carrying a hardcoded CosmoOps green into someone
|
|
12
12
|
* else's brand.
|
|
13
13
|
*/
|
|
@@ -9,12 +9,15 @@ exports.useConnectEntitlements = useConnectEntitlements;
|
|
|
9
9
|
exports.useConnectAddonUsage = useConnectAddonUsage;
|
|
10
10
|
exports.useConnectPlans = useConnectPlans;
|
|
11
11
|
exports.useConnectApps = useConnectApps;
|
|
12
|
+
exports.useConnectIntegrations = useConnectIntegrations;
|
|
12
13
|
exports.useConnectSessions = useConnectSessions;
|
|
13
14
|
exports.useConnectResource = useConnectResource;
|
|
14
15
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
15
16
|
const react_1 = require("react");
|
|
16
17
|
exports.CONNECT_APP_URL = "https://connect.cosmoops.com";
|
|
17
18
|
const ConnectContext = (0, react_1.createContext)(null);
|
|
19
|
+
/** Marks that this tab has already spent its one silent attempt - see `ConnectProviderProps.silentSignIn`. */
|
|
20
|
+
const SILENT_ATTEMPT_KEY = "connect_silent_attempted";
|
|
18
21
|
/**
|
|
19
22
|
* Wraps the part of your app that shows Connect UI.
|
|
20
23
|
*
|
|
@@ -29,14 +32,44 @@ const ConnectContext = (0, react_1.createContext)(null);
|
|
|
29
32
|
* </ConnectProvider>
|
|
30
33
|
* ```
|
|
31
34
|
*/
|
|
32
|
-
function ConnectProvider({ clientId = "", basePath = "/api/connect", redirectUri, appUrl = exports.CONNECT_APP_URL, fetch: fetchImpl, children, }) {
|
|
35
|
+
function ConnectProvider({ clientId = "", basePath = "/api/connect", redirectUri, appUrl = exports.CONNECT_APP_URL, fetch: fetchImpl, silentSignIn = false, children, }) {
|
|
33
36
|
// One state cell, not three. `isLoading` is *derived* from "no result yet"
|
|
34
37
|
// rather than set - a `setIsLoading(true)` at the top of an effect is a
|
|
35
38
|
// synchronous setState inside that effect, which cascades an extra render
|
|
36
39
|
// and is what `react-hooks/set-state-in-effect` flags. Everything below
|
|
37
40
|
// writes state only from an async callback.
|
|
38
41
|
const [result, setResult] = (0, react_1.useState)(null);
|
|
39
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Whether this tab has already spent its one silent attempt, sampled once
|
|
44
|
+
* at mount.
|
|
45
|
+
*
|
|
46
|
+
* A lazy `useState` initializer rather than a read inside the render body:
|
|
47
|
+
* `sessionStorage` is external mutable state, and reading it during render
|
|
48
|
+
* is impure - with the React Compiler on, that is exactly the kind of thing
|
|
49
|
+
* that can be hoisted or memoized into the wrong answer. An initializer
|
|
50
|
+
* runs once, which is all this needs; the value only ever changes as this
|
|
51
|
+
* component navigates the page away.
|
|
52
|
+
*
|
|
53
|
+
* Safe on the server, where it reads `false`: `result` is `null` during SSR
|
|
54
|
+
* and first client render alike, so `isLoading` below is `true` on both
|
|
55
|
+
* regardless of this value, and hydration cannot diverge on it.
|
|
56
|
+
*/
|
|
57
|
+
const [silentAttemptSpent] = (0, react_1.useState)(() => typeof window !== "undefined" && window.sessionStorage.getItem(SILENT_ATTEMPT_KEY) === "1");
|
|
58
|
+
/**
|
|
59
|
+
* A silent attempt is settled-signed-out *and* about to redirect. Reported
|
|
60
|
+
* as still-loading, which is the honest answer: the question "is this
|
|
61
|
+
* visitor signed in" has not been finally answered yet, and there is a
|
|
62
|
+
* navigation already on its way.
|
|
63
|
+
*
|
|
64
|
+
* Without this the provider publishes `signed out` for the one frame before
|
|
65
|
+
* the effect below fires, so every consumer paints its signed-out state -
|
|
66
|
+
* a "Sign in" button, the plan-picker gate - and then the page vanishes
|
|
67
|
+
* underneath it. Flashing a sales pitch at someone who is about to be
|
|
68
|
+
* silently signed in is the same bug `ConnectSubscriptionGate` exists to
|
|
69
|
+
* prevent, one layer down.
|
|
70
|
+
*/
|
|
71
|
+
const silentPending = silentSignIn && !silentAttemptSpent && result !== null && !result.session.user && !result.error;
|
|
72
|
+
const isLoading = result === null || silentPending;
|
|
40
73
|
const session = result?.session ?? null;
|
|
41
74
|
const error = result?.error ?? null;
|
|
42
75
|
// One entry per path. Held in a ref, not state, because a cache write must
|
|
@@ -102,7 +135,7 @@ function ConnectProvider({ clientId = "", basePath = "/api/connect", redirectUri
|
|
|
102
135
|
// error, so a Login button still renders rather than the UI hanging on
|
|
103
136
|
// skeletons forever.
|
|
104
137
|
setResult({
|
|
105
|
-
session: { user: null, subscription: null,
|
|
138
|
+
session: { user: null, subscription: null, applicationRole: null },
|
|
106
139
|
error: cause instanceof Error ? cause.message : "Could not reach Connect",
|
|
107
140
|
});
|
|
108
141
|
}
|
|
@@ -116,6 +149,21 @@ function ConnectProvider({ clientId = "", basePath = "/api/connect", redirectUri
|
|
|
116
149
|
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
117
150
|
void refresh();
|
|
118
151
|
}, [refresh]);
|
|
152
|
+
(0, react_1.useEffect)(() => {
|
|
153
|
+
// `silentPending` already encodes settled-and-signed-out, no prior
|
|
154
|
+
// attempt, and no bridge error - a failed bridge read says nothing about
|
|
155
|
+
// whether Connect has a session, and bouncing the browser on a transient
|
|
156
|
+
// network failure would turn a recoverable error into a navigation nobody
|
|
157
|
+
// asked for.
|
|
158
|
+
if (!silentPending || typeof window === "undefined")
|
|
159
|
+
return;
|
|
160
|
+
// Written before navigating, not after: a navigation that begins before
|
|
161
|
+
// the marker lands leaves the tab unmarked and free to probe again on the
|
|
162
|
+
// way back, which is the loop this bounds.
|
|
163
|
+
window.sessionStorage.setItem(SILENT_ATTEMPT_KEY, "1");
|
|
164
|
+
const next = `${window.location.pathname}${window.location.search}`;
|
|
165
|
+
window.location.href = `${basePath}/signin?prompt=none&next=${encodeURIComponent(next)}`;
|
|
166
|
+
}, [silentPending, basePath]);
|
|
119
167
|
const signIn = (0, react_1.useCallback)((options = {}) => {
|
|
120
168
|
const url = new URL("/sso/authorize", appUrl);
|
|
121
169
|
url.searchParams.set("client_id", clientId);
|
|
@@ -136,7 +184,7 @@ function ConnectProvider({ clientId = "", basePath = "/api/connect", redirectUri
|
|
|
136
184
|
credentials: "same-origin",
|
|
137
185
|
}).catch(() => { });
|
|
138
186
|
cache.current.clear();
|
|
139
|
-
setResult({ session: { user: null, subscription: null,
|
|
187
|
+
setResult({ session: { user: null, subscription: null, applicationRole: null }, error: null });
|
|
140
188
|
}, [basePath, fetchImpl]);
|
|
141
189
|
const value = (0, react_1.useMemo)(() => ({
|
|
142
190
|
clientId,
|
|
@@ -183,24 +231,28 @@ function useConnectEntitlements() {
|
|
|
183
231
|
/**
|
|
184
232
|
* What is left of every consumable add-on on this workspace's subscription.
|
|
185
233
|
*
|
|
186
|
-
* The read half of `client.billing.consumeAddon` -
|
|
234
|
+
* The read half of `client.billing.consumeAddon` - an application that meters its
|
|
187
235
|
* own end users had no way to show them what remained until this existed.
|
|
188
236
|
* Empty `addons` means there is nothing to meter, which is not an error.
|
|
189
237
|
*/
|
|
190
238
|
function useConnectAddonUsage() {
|
|
191
239
|
return useConnectResource("/addons");
|
|
192
240
|
}
|
|
193
|
-
/** This
|
|
241
|
+
/** This application's plan catalog. */
|
|
194
242
|
function useConnectPlans() {
|
|
195
243
|
return useConnectResource("/plans");
|
|
196
244
|
}
|
|
197
|
-
/** The apps this
|
|
245
|
+
/** The apps this workspace can open. */
|
|
198
246
|
function useConnectApps() {
|
|
199
247
|
return useConnectResource("/apps");
|
|
200
248
|
}
|
|
249
|
+
/** Enabled Composio-hosted toolkits and this workspace's connection status for each. */
|
|
250
|
+
function useConnectIntegrations() {
|
|
251
|
+
return useConnectResource("/integrations");
|
|
252
|
+
}
|
|
201
253
|
/**
|
|
202
254
|
* This Connect account's own login sessions - account-wide, not scoped to
|
|
203
|
-
* this
|
|
255
|
+
* this application, see `SessionsListResponse`'s doc comment. The component
|
|
204
256
|
* that calls this is also the one that must own any revoke actions and call
|
|
205
257
|
* the returned `refetch()` afterward - see `mutateResource`'s doc comment
|
|
206
258
|
* for why nothing does that automatically.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.useActivePath = useActivePath;
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const LOCATION_CHANGE = "connect:locationchange";
|
|
7
|
+
let patched = false;
|
|
8
|
+
/**
|
|
9
|
+
* Make `history.pushState`/`replaceState` announce themselves.
|
|
10
|
+
*
|
|
11
|
+
* Neither fires an event - `popstate` covers Back and Forward only - so a
|
|
12
|
+
* client-side router that pushes a new URL moves the address bar and tells
|
|
13
|
+
* nothing outside itself. Without this, a sidebar reading `location.pathname`
|
|
14
|
+
* highlights whatever route the page first loaded on and then never moves
|
|
15
|
+
* again.
|
|
16
|
+
*
|
|
17
|
+
* Both wrappers call through to the original first and return its result, so
|
|
18
|
+
* the patch is transparent to whatever router installed the navigation; it is
|
|
19
|
+
* applied at most once per document, and only when a `ConnectSideNav` is
|
|
20
|
+
* actually mounted without an `activePath`. Pass `activePath` (Next:
|
|
21
|
+
* `usePathname()`) and none of this runs at all - which is the recommended
|
|
22
|
+
* path for any app that has a router to ask.
|
|
23
|
+
*/
|
|
24
|
+
function patchHistory() {
|
|
25
|
+
if (patched || typeof window === "undefined" || typeof window.history === "undefined")
|
|
26
|
+
return;
|
|
27
|
+
patched = true;
|
|
28
|
+
for (const method of ["pushState", "replaceState"]) {
|
|
29
|
+
const original = window.history[method];
|
|
30
|
+
window.history[method] = function patchedHistoryMethod(...args) {
|
|
31
|
+
const result = original.apply(this, args);
|
|
32
|
+
window.dispatchEvent(new Event(LOCATION_CHANGE));
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function subscribe(onStoreChange) {
|
|
38
|
+
patchHistory();
|
|
39
|
+
window.addEventListener("popstate", onStoreChange);
|
|
40
|
+
window.addEventListener(LOCATION_CHANGE, onStoreChange);
|
|
41
|
+
return () => {
|
|
42
|
+
window.removeEventListener("popstate", onStoreChange);
|
|
43
|
+
window.removeEventListener(LOCATION_CHANGE, onStoreChange);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function getSnapshot() {
|
|
47
|
+
return window.location.pathname;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The server never has a location, and guessing one is worse than having
|
|
51
|
+
* none: a guess that misses renders a *different* item highlighted on the
|
|
52
|
+
* server than on the client, which is a hydration mismatch. `""` matches no
|
|
53
|
+
* nav item, so the first paint has no highlight and the client's first commit
|
|
54
|
+
* adds it.
|
|
55
|
+
*
|
|
56
|
+
* Doubles as the snapshot when `activePath` *was* supplied - the value is
|
|
57
|
+
* discarded either way, and pairing it with `noopSubscribe` is what keeps a
|
|
58
|
+
* controlled shell from ever touching `history` or `window.location`.
|
|
59
|
+
*/
|
|
60
|
+
function emptySnapshot() {
|
|
61
|
+
return "";
|
|
62
|
+
}
|
|
63
|
+
function noopSubscribe() {
|
|
64
|
+
return () => { };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The current path, from `activePath` when given and from the browser
|
|
68
|
+
* otherwise.
|
|
69
|
+
*
|
|
70
|
+
* Exported because a host building its own shell out of `ConnectSideNav`
|
|
71
|
+
* needs the same fallback the shell uses.
|
|
72
|
+
*/
|
|
73
|
+
function useActivePath(activePath) {
|
|
74
|
+
const controlled = activePath !== undefined;
|
|
75
|
+
const live = (0, react_1.useSyncExternalStore)(controlled ? noopSubscribe : subscribe, controlled ? emptySnapshot : getSnapshot, emptySnapshot);
|
|
76
|
+
return activePath ?? live;
|
|
77
|
+
}
|
|
@@ -157,15 +157,15 @@ function buildCancelUrl({ appUrl, subscriptionId }) {
|
|
|
157
157
|
* The Connect URL that completes a subscribe or a plan change.
|
|
158
158
|
*
|
|
159
159
|
* Both land on a modal Connect renders over the relevant page (an intercepted
|
|
160
|
-
* parallel route - `app/@modal/(.)
|
|
160
|
+
* parallel route - `app/@modal/(.)applications/...` and
|
|
161
161
|
* `app/@modal/(.)billing/...`), so the customer arrives already looking at the
|
|
162
162
|
* confirmation for the plan they picked here, not at a catalogue they have to
|
|
163
163
|
* find it in again.
|
|
164
164
|
*/
|
|
165
|
-
function buildCheckoutUrl({ appUrl,
|
|
165
|
+
function buildCheckoutUrl({ appUrl, applicationId, planId, subscriptionId, coupon, }) {
|
|
166
166
|
const path = subscriptionId
|
|
167
167
|
? `/billing/subscriptions/${encodeURIComponent(subscriptionId)}/change-plan/${encodeURIComponent(planId)}`
|
|
168
|
-
: `/
|
|
168
|
+
: `/applications/${encodeURIComponent(applicationId)}/subscribe/${encodeURIComponent(planId)}`;
|
|
169
169
|
const url = new URL(path, appUrl);
|
|
170
170
|
if (coupon?.trim())
|
|
171
171
|
url.searchParams.set("coupon", coupon.trim());
|
package/dist/cjs/errors.js
CHANGED
|
@@ -3,10 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ConnectError = void 0;
|
|
4
4
|
exports.isConnectError = isConnectError;
|
|
5
5
|
/**
|
|
6
|
-
* Every failure the Connect
|
|
6
|
+
* Every failure the Connect application API can report, as one class.
|
|
7
7
|
*
|
|
8
8
|
* The API speaks two error dialects and this collapses them: the
|
|
9
|
-
* `/api/v1/
|
|
9
|
+
* `/api/v1/application/*` endpoints use `{ error: { code, message } }`, while the
|
|
10
10
|
* three `/sso/*` ones use OAuth2's `{ error, error_description }` (RFC 6749
|
|
11
11
|
* §5.2). Both land here with `code` populated, so integrating code branches on
|
|
12
12
|
* one field either way.
|
|
@@ -45,7 +45,7 @@ class ConnectError extends Error {
|
|
|
45
45
|
* Whether the user's Connect sign-in is over and they need to go back
|
|
46
46
|
* through `identity.authorizeUrl()`. Collapses every session-side failure,
|
|
47
47
|
* matching how the API reports them - unknown, expired, revoked, or issued
|
|
48
|
-
* to a different
|
|
48
|
+
* to a different application all arrive as one `invalid_token`.
|
|
49
49
|
*/
|
|
50
50
|
get isSessionExpired() {
|
|
51
51
|
return this.code === "invalid_token";
|
|
@@ -59,7 +59,7 @@ class ConnectError extends Error {
|
|
|
59
59
|
* guessing keys. These two are the exception: reaching them required
|
|
60
60
|
* presenting a key whose hash matched, so you already hold it, and what you
|
|
61
61
|
* need to know is that no retry and no scope change will fix this - the key
|
|
62
|
-
* has to be reissued from the
|
|
62
|
+
* has to be reissued from the application's Integration tab.
|
|
63
63
|
*
|
|
64
64
|
* Worth alerting on. It is the one failure that will not resolve itself and
|
|
65
65
|
* takes down every call your integration makes.
|
package/dist/cjs/helpers.js
CHANGED
|
@@ -16,7 +16,7 @@ function blockingBlockers(readiness) {
|
|
|
16
16
|
* Coerces either wire shape into `PlanFeature[]`.
|
|
17
17
|
*
|
|
18
18
|
* A bare key becomes `{ key, name: key, description: "" }` - the same
|
|
19
|
-
* fallback the server applies for a plan older than its
|
|
19
|
+
* fallback the server applies for a plan older than its application's feature
|
|
20
20
|
* catalog, so an un-upgraded Connect renders exactly what it always did
|
|
21
21
|
* rather than a column of blanks.
|
|
22
22
|
*
|
package/dist/cjs/index.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.normalizePlanFeatures = exports.blockingBlockers = exports.isConnectError = exports.ConnectError = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* `@cosmoops/connect-sdk` - the official client for the CosmoOps Connect
|
|
6
|
-
* **
|
|
6
|
+
* **application-partner API** (`/api/v1/application/*`).
|
|
7
7
|
*
|
|
8
8
|
* This root entry is the isomorphic surface: wire types, the error class, and
|
|
9
9
|
* pure helpers. It pulls in neither Node-only code nor React, so it is safe to
|
package/dist/cjs/next/index.js
CHANGED
|
@@ -41,16 +41,22 @@ exports.createConnectHandlers = createConnectHandlers;
|
|
|
41
41
|
exports.GET = handle;
|
|
42
42
|
exports.POST = handle;
|
|
43
43
|
exports.getConnectSession = getConnectSession;
|
|
44
|
+
exports.requireConnectSession = requireConnectSession;
|
|
45
|
+
const react_1 = require("react");
|
|
44
46
|
const client_js_1 = require("../server/client.js");
|
|
45
47
|
const handler_js_1 = require("../server/handler.js");
|
|
46
48
|
/**
|
|
47
49
|
* Plug-and-play wiring for Next.js.
|
|
48
50
|
*
|
|
49
51
|
* Everything below is server-side. Nothing here is *statically* imported from
|
|
50
|
-
* `next
|
|
51
|
-
* and the edge runtime alike
|
|
52
|
-
* that does reach for `next/headers`
|
|
53
|
-
*
|
|
52
|
+
* `next` itself, so this module loads in App Router route handlers, the Node
|
|
53
|
+
* runtime and the edge runtime alike without a `next` peer dependency. The
|
|
54
|
+
* one place that does reach for `next/headers` (or, in `requireConnectSession`,
|
|
55
|
+
* `next/navigation`) does it behind a dynamic import, inside the function that
|
|
56
|
+
* needs it, and says so when it isn't there. `react` is a real, static
|
|
57
|
+
* dependency though - `getConnectSession`'s automatic per-request memoization
|
|
58
|
+
* (below) is built on its `cache()`, which every App Router project already
|
|
59
|
+
* has.
|
|
54
60
|
*
|
|
55
61
|
* The whole integration is two files:
|
|
56
62
|
*
|
|
@@ -76,7 +82,7 @@ const handler_js_1 = require("../server/handler.js");
|
|
|
76
82
|
* | `CONNECT_SESSION_COOKIE` | no | session cookie name |
|
|
77
83
|
*
|
|
78
84
|
* Register `{your origin}/api/connect/callback` as a redirect URI in the
|
|
79
|
-
*
|
|
85
|
+
* application's Integration tab. That is the only step this cannot do for you.
|
|
80
86
|
*
|
|
81
87
|
* No `next.config.ts` changes needed either, including `transpilePackages`:
|
|
82
88
|
* `dist/` is already ES2022 with `"use client"` hoisted to the top of every
|
|
@@ -227,6 +233,35 @@ async function requestFromHeaders() {
|
|
|
227
233
|
const proto = incoming.get("x-forwarded-proto") ?? (host.startsWith("localhost") ? "http" : "https");
|
|
228
234
|
return new Request(`${proto}://${host}/`, { headers: incoming });
|
|
229
235
|
}
|
|
236
|
+
async function readSession(request, options) {
|
|
237
|
+
const store = options.session ?? cookieSessionStore();
|
|
238
|
+
const token = await store.read(request);
|
|
239
|
+
if (!token)
|
|
240
|
+
return null;
|
|
241
|
+
try {
|
|
242
|
+
return await (options.client ?? connectClient()).identity.getUser(token);
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* The ambient case - no explicit `request`, default client, default cookie
|
|
250
|
+
* store - wrapped in React's `cache()` so every call in the same request
|
|
251
|
+
* shares one round trip to Connect. A layout reading the session for a nav
|
|
252
|
+
* avatar and the page beneath it reading it again for a role check hit this
|
|
253
|
+
* exact function; without the wrapper that's two live reads of the same
|
|
254
|
+
* answer.
|
|
255
|
+
*
|
|
256
|
+
* Deliberately its own zero-argument function rather than `cache()` wrapping
|
|
257
|
+
* `getConnectSession` directly - `cache()` keys on argument identity, and
|
|
258
|
+
* `getConnectSession`'s default `options = {}` is a fresh object on every
|
|
259
|
+
* call, so wrapping it as-is would never hit the cache for the very call
|
|
260
|
+
* pattern this exists to speed up.
|
|
261
|
+
*/
|
|
262
|
+
const cachedAmbientSession = (0, react_1.cache)(async () => {
|
|
263
|
+
return readSession(await requestFromHeaders(), {});
|
|
264
|
+
});
|
|
230
265
|
/**
|
|
231
266
|
* The signed-in user for a Server Component, Route Handler or Server Action,
|
|
232
267
|
* or `null`.
|
|
@@ -237,6 +272,9 @@ async function requestFromHeaders() {
|
|
|
237
272
|
* if (!session) redirect("/api/connect/signin?next=/dashboard");
|
|
238
273
|
* ```
|
|
239
274
|
*
|
|
275
|
+
* `requireConnectSession()` below is that exact check in one call, for the
|
|
276
|
+
* common case of "redirect if signed out."
|
|
277
|
+
*
|
|
240
278
|
* Pass a `Request` to use it somewhere `next/headers` does not exist - a
|
|
241
279
|
* framework-agnostic handler, a test, a custom server. Both forms take the
|
|
242
280
|
* same path afterwards; the argument is only how the cookie is found.
|
|
@@ -248,18 +286,61 @@ async function requestFromHeaders() {
|
|
|
248
286
|
*
|
|
249
287
|
* Returns `null` for every failure - an expired session and a missing one both
|
|
250
288
|
* mean "not signed in", and a page guard should not need a try/catch.
|
|
289
|
+
*
|
|
290
|
+
* **Memoized per request for the plain, zero-argument call** - the shape
|
|
291
|
+
* every page, layout and Server Action actually uses - via React's `cache()`.
|
|
292
|
+
* Passing an explicit `request`, `client` or `session` bypasses the cache
|
|
293
|
+
* and always makes a live call: those are for tests and non-ambient
|
|
294
|
+
* callers, where a fresh read every time is the point, not an oversight.
|
|
251
295
|
*/
|
|
252
296
|
async function getConnectSession(request, options = {}) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
297
|
+
if (!request && !options.client && !options.session)
|
|
298
|
+
return cachedAmbientSession();
|
|
299
|
+
return readSession(request ?? (await requestFromHeaders()), options);
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* `getConnectSession()`, minus the boilerplate of checking it and redirecting
|
|
303
|
+
* yourself:
|
|
304
|
+
*
|
|
305
|
+
* ```tsx
|
|
306
|
+
* // app/dashboard/page.tsx
|
|
307
|
+
* const session = await requireConnectSession();
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* Redirects to `/signin` under the same `basePath` as `getConnectSession`'s
|
|
311
|
+
* default (`/api/connect`) when signed out - pass `signInPath` if you mounted
|
|
312
|
+
* the bridge somewhere else, and `next` to send the visitor back to where
|
|
313
|
+
* they were once they're signed in. Only sensible in a Server Component,
|
|
314
|
+
* Route Handler or Server Action, the same three places `redirect()` from
|
|
315
|
+
* `next/navigation` itself works.
|
|
316
|
+
*
|
|
317
|
+
* A thin wrapper, not a framework of its own - reach for `getConnectSession`
|
|
318
|
+
* plus your own check when "not signed in" isn't "redirect to sign-in"
|
|
319
|
+
* (an API route returning 401, say). Role and entitlement checks stay
|
|
320
|
+
* outside this function on purpose: `session.applicationRole.granted` and
|
|
321
|
+
* `connect.entitlements.*` are one line each on top of the session this
|
|
322
|
+
* already gives you, and where that line redirects (a plans page, a
|
|
323
|
+
* "forbidden" screen) is a decision only your app can make - see
|
|
324
|
+
* "Authentication & authorization" for the pattern.
|
|
325
|
+
*/
|
|
326
|
+
async function requireConnectSession(request, options = {}) {
|
|
327
|
+
const session = await getConnectSession(request, options);
|
|
328
|
+
if (session)
|
|
329
|
+
return session;
|
|
330
|
+
const signIn = options.signInPath ?? "/api/connect/signin";
|
|
331
|
+
return redirectTo(options.next ? `${signIn}?next=${encodeURIComponent(options.next)}` : signIn);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* `next/navigation`'s `redirect()`, imported the same dynamic way as
|
|
335
|
+
* `next/headers` above and for the same reason: no static dependency on
|
|
336
|
+
* `next`'s own types at this package's build time. Typed by hand rather than
|
|
337
|
+
* imported, since that's the only way to erase them - `redirect()` itself is
|
|
338
|
+
* typed `never`, which is what lets `requireConnectSession` return here
|
|
339
|
+
* without its own `return` after the call.
|
|
340
|
+
*/
|
|
341
|
+
async function redirectTo(url) {
|
|
342
|
+
const { redirect } = (await Promise.resolve().then(() => __importStar(require("next/navigation"))));
|
|
343
|
+
return redirect(url);
|
|
263
344
|
}
|
|
264
345
|
var handler_js_2 = require("../server/handler.js");
|
|
265
346
|
Object.defineProperty(exports, "createConnectHandler", { enumerable: true, get: function () { return handler_js_2.createConnectHandler; } });
|
|
@@ -8,11 +8,13 @@ const billing_js_1 = require("./resources/billing.js");
|
|
|
8
8
|
const drive_js_1 = require("./resources/drive.js");
|
|
9
9
|
const entitlements_js_1 = require("./resources/entitlements.js");
|
|
10
10
|
const identity_js_1 = require("./resources/identity.js");
|
|
11
|
+
const integrations_js_1 = require("./resources/integrations.js");
|
|
11
12
|
const logs_js_1 = require("./resources/logs.js");
|
|
13
|
+
const analytics_js_1 = require("./resources/analytics.js");
|
|
12
14
|
const otp_js_1 = require("./resources/otp.js");
|
|
13
15
|
const sessions_js_1 = require("./resources/sessions.js");
|
|
14
16
|
exports.DEFAULT_BASE_URL = "https://connect.cosmoops.com";
|
|
15
|
-
const
|
|
17
|
+
const APPLICATION_API_PREFIX = "/api/v1/application";
|
|
16
18
|
/**
|
|
17
19
|
* Refuses to build a client in a browser.
|
|
18
20
|
*
|
|
@@ -41,9 +43,9 @@ function assertNotBrowser() {
|
|
|
41
43
|
"in browser code instead; it talks to your own origin and holds no credential.");
|
|
42
44
|
}
|
|
43
45
|
/**
|
|
44
|
-
* The CosmoOps Connect
|
|
46
|
+
* The CosmoOps Connect application-partner API.
|
|
45
47
|
*
|
|
46
|
-
* Covers `/api/v1/
|
|
48
|
+
* Covers `/api/v1/application/*` and nothing else - the surface an application platform
|
|
47
49
|
* integrates against. Connect's internal API is not part of this package and
|
|
48
50
|
* never will be.
|
|
49
51
|
*
|
|
@@ -54,7 +56,7 @@ function assertNotBrowser() {
|
|
|
54
56
|
* });
|
|
55
57
|
*
|
|
56
58
|
* const session = await connect.identity.exchangeCode({ code, redirectUri });
|
|
57
|
-
* const { ready } = await connect.entitlements.getReadiness(session.user.
|
|
59
|
+
* const { ready } = await connect.entitlements.getReadiness(session.user.workspaceId);
|
|
58
60
|
* ```
|
|
59
61
|
*
|
|
60
62
|
* Every failure throws a `ConnectError` carrying a stable `code`. Nothing here
|
|
@@ -63,32 +65,36 @@ function assertNotBrowser() {
|
|
|
63
65
|
class ConnectClient {
|
|
64
66
|
/** "Login with Connect" - the OAuth2 handshake and the session after it. */
|
|
65
67
|
identity;
|
|
66
|
-
/** What a signed-in member may do on your
|
|
68
|
+
/** What a signed-in member may do on your application. */
|
|
67
69
|
access;
|
|
68
|
-
/** The
|
|
70
|
+
/** The applications a workspace can open - for a launcher grid. */
|
|
69
71
|
apps;
|
|
70
|
-
/** Whether a workspace may use your
|
|
72
|
+
/** Whether a workspace may use your application, and on what plan. */
|
|
71
73
|
entitlements;
|
|
72
74
|
/** Your plan catalog, and metering usage against add-on balances. */
|
|
73
75
|
billing;
|
|
74
|
-
/** Files in
|
|
76
|
+
/** Files in a workspace's Drive. */
|
|
75
77
|
drive;
|
|
76
78
|
/** RAG chat and structured extraction. */
|
|
77
79
|
ai;
|
|
78
80
|
/** WhatsApp/SMS phone verification. */
|
|
79
81
|
otp;
|
|
80
|
-
/** Feature events into the Console's audit log, filterable to your
|
|
82
|
+
/** Feature events into the Console's audit log, filterable to your application. */
|
|
81
83
|
logs;
|
|
82
|
-
/**
|
|
84
|
+
/** Emit product events and read back this application's aggregated numbers. */
|
|
85
|
+
analytics;
|
|
86
|
+
/** This Connect account's own login sessions - account-wide, not scoped to this application. Requires the `sessions:manage` scope. */
|
|
83
87
|
sessions;
|
|
88
|
+
/** Composio-hosted third-party connections (Google Calendar, Slack, ...) a workspace has connected. */
|
|
89
|
+
integrations;
|
|
84
90
|
constructor(options) {
|
|
85
91
|
assertNotBrowser();
|
|
86
92
|
if (!options.apiKey) {
|
|
87
|
-
throw new TypeError("ConnectClient requires `apiKey` - the plaintext shown once in the
|
|
93
|
+
throw new TypeError("ConnectClient requires `apiKey` - the plaintext shown once in the Integration tab.");
|
|
88
94
|
}
|
|
89
95
|
const appBaseUrl = (options.baseUrl ?? exports.DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
90
96
|
const transport = {
|
|
91
|
-
baseUrl: `${appBaseUrl}${
|
|
97
|
+
baseUrl: `${appBaseUrl}${APPLICATION_API_PREFIX}`,
|
|
92
98
|
apiKey: options.apiKey,
|
|
93
99
|
timeoutMs: options.timeoutMs ?? 20_000,
|
|
94
100
|
maxRetries: options.maxRetries ?? 2,
|
|
@@ -96,7 +102,7 @@ class ConnectClient {
|
|
|
96
102
|
userAgent: `cosmoops-connect-sdk/${exports.SDK_VERSION}`,
|
|
97
103
|
};
|
|
98
104
|
// `authorizeUrl` points at the app, not the API prefix - it is a browser
|
|
99
|
-
// redirect, not
|
|
105
|
+
// redirect, not an application call, so identity takes both.
|
|
100
106
|
this.identity = new identity_js_1.IdentityResource(transport, options.clientId ?? null, appBaseUrl);
|
|
101
107
|
this.access = new access_js_1.AccessResource(transport);
|
|
102
108
|
this.apps = new apps_js_1.AppsResource(transport);
|
|
@@ -106,9 +112,11 @@ class ConnectClient {
|
|
|
106
112
|
this.ai = new ai_js_1.AiResource(transport);
|
|
107
113
|
this.otp = new otp_js_1.OtpResource(transport);
|
|
108
114
|
this.logs = new logs_js_1.LogsResource(transport);
|
|
115
|
+
this.analytics = new analytics_js_1.AnalyticsResource(transport);
|
|
109
116
|
this.sessions = new sessions_js_1.SessionsResource(transport, options.clientId ?? null);
|
|
117
|
+
this.integrations = new integrations_js_1.IntegrationsResource(transport);
|
|
110
118
|
}
|
|
111
119
|
}
|
|
112
120
|
exports.ConnectClient = ConnectClient;
|
|
113
121
|
/** Kept in step with `package.json` by `sdk.test.ts`. */
|
|
114
|
-
exports.SDK_VERSION = "0.
|
|
122
|
+
exports.SDK_VERSION = "0.7.0";
|