@cosmoops/connect-sdk 0.6.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/dist/cjs/cli/doctor.js +3 -3
- package/dist/cjs/cli/init.js +3 -3
- package/dist/cjs/client/components/access-gate.js +3 -3
- package/dist/cjs/client/components/account-sessions.js +3 -3
- package/dist/cjs/client/components/app-shell.js +2 -2
- package/dist/cjs/client/components/apps-grid.js +3 -3
- package/dist/cjs/client/components/feature-gate.js +2 -2
- package/dist/cjs/client/components/integrations-modal.js +1 -1
- package/dist/cjs/client/components/logo.js +3 -3
- package/dist/cjs/client/components/plan-pricing.js +1 -1
- package/dist/cjs/client/components/plans.js +6 -6
- package/dist/cjs/client/components/readiness.js +3 -3
- package/dist/cjs/client/components/subscribe-dialog.js +2 -2
- package/dist/cjs/client/components/subscription.js +1 -1
- package/dist/cjs/client/components/usage-meter.js +1 -1
- package/dist/cjs/client/components/user-menu.js +4 -4
- package/dist/cjs/client/index.js +1 -1
- package/dist/cjs/client/mark.js +1 -1
- package/dist/cjs/client/provider.js +7 -7
- 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 +2 -2
- package/dist/cjs/server/client.js +15 -15
- package/dist/cjs/server/handler.js +13 -13
- package/dist/cjs/server/http.js +1 -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 +2 -2
- 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 +13 -13
- package/dist/cjs/server/resources/logs.js +3 -3
- package/dist/cjs/server/resources/sessions.js +6 -6
- package/dist/cjs/server/webhooks.js +4 -4
- 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 +3 -3
- package/dist/esm/client/components/account-sessions.js +3 -3
- package/dist/esm/client/components/app-shell.js +2 -2
- package/dist/esm/client/components/apps-grid.js +3 -3
- package/dist/esm/client/components/feature-gate.js +2 -2
- package/dist/esm/client/components/integrations-modal.js +1 -1
- package/dist/esm/client/components/logo.js +3 -3
- package/dist/esm/client/components/plan-pricing.js +1 -1
- package/dist/esm/client/components/plans.js +6 -6
- package/dist/esm/client/components/readiness.js +3 -3
- package/dist/esm/client/components/subscribe-dialog.js +2 -2
- package/dist/esm/client/components/subscription.js +1 -1
- package/dist/esm/client/components/usage-meter.js +1 -1
- package/dist/esm/client/components/user-menu.js +4 -4
- package/dist/esm/client/index.js +1 -1
- package/dist/esm/client/mark.js +1 -1
- package/dist/esm/client/provider.js +7 -7
- 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 +2 -2
- package/dist/esm/server/client.js +15 -15
- package/dist/esm/server/handler.js +13 -13
- package/dist/esm/server/http.js +1 -1
- 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 +2 -2
- 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 +13 -13
- package/dist/esm/server/resources/logs.js +3 -3
- package/dist/esm/server/resources/sessions.js +6 -6
- package/dist/esm/server/webhooks.js +4 -4
- package/dist/esm/types.js +1 -1
- package/dist/types/client/components/access-gate.d.ts +1 -1
- package/dist/types/client/components/account-sessions.d.ts +1 -1
- package/dist/types/client/components/app-shell.d.ts +4 -4
- 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 +1 -1
- package/dist/types/client/components/logo.d.ts +5 -5
- 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/subscribe-dialog.d.ts +3 -3
- 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 +1 -1
- package/dist/types/client/mark.d.ts +1 -1
- package/dist/types/client/provider.d.ts +9 -9
- 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 +1 -1
- package/dist/types/server/client.d.ts +13 -13
- package/dist/types/server/handler.d.ts +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/types/server/resources/integrations.d.ts +9 -9
- 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 +4 -4
- package/dist/types/types.d.ts +61 -61
- package/package.json +1 -1
|
@@ -91,9 +91,9 @@ function redirect(location, cookies = []) {
|
|
|
91
91
|
* export { handler as GET, handler as POST };
|
|
92
92
|
* ```
|
|
93
93
|
*
|
|
94
|
-
* Every route resolves the
|
|
94
|
+
* Every route resolves the workspace from the caller's *own* session, never
|
|
95
95
|
* from a query parameter. A browser must not be able to ask about an
|
|
96
|
-
*
|
|
96
|
+
* workspace it is not signed into, and a client-supplied `workspaceId`
|
|
97
97
|
* is exactly that hole.
|
|
98
98
|
*/
|
|
99
99
|
export function createConnectHandler(options) {
|
|
@@ -160,7 +160,7 @@ export function createConnectHandler(options) {
|
|
|
160
160
|
}
|
|
161
161
|
return token;
|
|
162
162
|
}
|
|
163
|
-
/** Signed-in identity plus the
|
|
163
|
+
/** Signed-in identity plus the workspace it belongs to - the first read every other route needs. */
|
|
164
164
|
async function whoami(request) {
|
|
165
165
|
return client.identity.getUser(await requireToken(request));
|
|
166
166
|
}
|
|
@@ -170,32 +170,32 @@ export function createConnectHandler(options) {
|
|
|
170
170
|
// Signed out is a normal state for a page rendering a Login button, not
|
|
171
171
|
// an error - `user: null` rather than a 401 the client must catch.
|
|
172
172
|
if (!token)
|
|
173
|
-
return json({ user: null, subscription: null,
|
|
173
|
+
return json({ user: null, subscription: null, applicationRole: null });
|
|
174
174
|
return json(await client.identity.getUser(token));
|
|
175
175
|
},
|
|
176
176
|
"GET /entitlements": async (request) => {
|
|
177
177
|
const { user } = await whoami(request);
|
|
178
178
|
const [readiness, subscription] = await Promise.all([
|
|
179
|
-
client.entitlements.getReadiness(user.
|
|
180
|
-
client.entitlements.getSubscription(user.
|
|
179
|
+
client.entitlements.getReadiness(user.workspaceId),
|
|
180
|
+
client.entitlements.getSubscription(user.workspaceId),
|
|
181
181
|
]);
|
|
182
182
|
return json({ readiness, subscription });
|
|
183
183
|
},
|
|
184
184
|
"GET /plans": async () => json(await client.billing.listPlans()),
|
|
185
|
-
//
|
|
185
|
+
// Workspace comes from the caller's own session, same as every other
|
|
186
186
|
// route here - a browser must not be able to ask what another workspace
|
|
187
187
|
// has left.
|
|
188
188
|
"GET /addons": async (request) => {
|
|
189
189
|
const { user } = await whoami(request);
|
|
190
|
-
return json(await client.billing.getAddonUsage(user.
|
|
190
|
+
return json(await client.billing.getAddonUsage(user.workspaceId));
|
|
191
191
|
},
|
|
192
192
|
"GET /apps": async (request) => {
|
|
193
193
|
const { user } = await whoami(request);
|
|
194
|
-
return json({ apps: await client.apps.list(user.
|
|
194
|
+
return json({ apps: await client.apps.list(user.workspaceId) });
|
|
195
195
|
},
|
|
196
196
|
"GET /integrations": async (request) => {
|
|
197
197
|
const { user } = await whoami(request);
|
|
198
|
-
return json({ toolkits: await client.integrations.list(user.
|
|
198
|
+
return json({ toolkits: await client.integrations.list(user.workspaceId) });
|
|
199
199
|
},
|
|
200
200
|
"POST /integrations/connect": async (request) => {
|
|
201
201
|
const { user } = await whoami(request);
|
|
@@ -208,7 +208,7 @@ export function createConnectHandler(options) {
|
|
|
208
208
|
endpoint: "POST /integrations/connect",
|
|
209
209
|
});
|
|
210
210
|
}
|
|
211
|
-
return json(await client.integrations.initiateConnect(user.
|
|
211
|
+
return json(await client.integrations.initiateConnect(user.workspaceId, body.toolkitSlug, body.returnUrl));
|
|
212
212
|
},
|
|
213
213
|
"POST /integrations/disconnect": async (request) => {
|
|
214
214
|
const { user } = await whoami(request);
|
|
@@ -221,10 +221,10 @@ export function createConnectHandler(options) {
|
|
|
221
221
|
endpoint: "POST /integrations/disconnect",
|
|
222
222
|
});
|
|
223
223
|
}
|
|
224
|
-
await client.integrations.disconnect(user.
|
|
224
|
+
await client.integrations.disconnect(user.workspaceId, body.toolkitSlug);
|
|
225
225
|
return json({ ok: true });
|
|
226
226
|
},
|
|
227
|
-
// Account-wide, not scoped to this
|
|
227
|
+
// Account-wide, not scoped to this application - see `SessionsResource`'s
|
|
228
228
|
// doc comment. `requireToken` alone identifies the caller; the target
|
|
229
229
|
// `sessionId` on the revoke routes travels in the JSON body, not the
|
|
230
230
|
// URL, so the exact-match routes table above never needs a dynamic
|
package/dist/esm/server/http.js
CHANGED
|
@@ -40,7 +40,7 @@ function parseRetryAfterMs(response) {
|
|
|
40
40
|
return Number.isFinite(seconds) ? Math.max(0, seconds) * 1000 : null;
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
|
-
* Both error dialects, one shape. `/api/v1/
|
|
43
|
+
* Both error dialects, one shape. `/api/v1/application/*` answers
|
|
44
44
|
* `{ error: { code, message } }`; the `/sso/*` endpoints answer OAuth2's
|
|
45
45
|
* `{ error, error_description }`.
|
|
46
46
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pathSegment, request } from "../http.js";
|
|
2
|
-
/** What a signed-in member may do on your
|
|
2
|
+
/** What a signed-in member may do on your application, and the role catalog behind it. */
|
|
3
3
|
export class AccessResource {
|
|
4
4
|
transport;
|
|
5
5
|
constructor(transport) {
|
|
@@ -14,10 +14,10 @@ export class AccessResource {
|
|
|
14
14
|
return request(this.transport, {
|
|
15
15
|
method: "GET",
|
|
16
16
|
path: `/rbac/users/${pathSegment(userId, "userId")}/roles`,
|
|
17
|
-
query: {
|
|
17
|
+
query: { workspaceId: input.workspaceId },
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
|
-
/** Your
|
|
20
|
+
/** Your application's own permission catalog and role definitions - the definitions `getUserRoles` resolves against. */
|
|
21
21
|
listRoles() {
|
|
22
22
|
return request(this.transport, { method: "GET", path: "/roles" });
|
|
23
23
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { request } from "../http.js";
|
|
2
2
|
/**
|
|
3
|
-
* Your
|
|
3
|
+
* Your application's own analytics: emit product events, and read back the daily
|
|
4
4
|
* numbers Connect aggregates from them.
|
|
5
5
|
*
|
|
6
|
-
* There is no way to name
|
|
6
|
+
* There is no way to name an application in either call. The scope is always the one
|
|
7
7
|
* your API key belongs to - that is the endpoint's security model, not an
|
|
8
8
|
* omission.
|
|
9
9
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { request } from "../http.js";
|
|
2
|
-
/** The
|
|
2
|
+
/** The applications a workspace can open - the data behind a launcher grid. */
|
|
3
3
|
export class AppsResource {
|
|
4
4
|
transport;
|
|
5
5
|
constructor(transport) {
|
|
@@ -7,13 +7,13 @@ export class AppsResource {
|
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Launchable apps only, so a grid tile is never a dead end. The calling
|
|
10
|
-
*
|
|
10
|
+
* application is included and flagged `isCurrent` rather than filtered out.
|
|
11
11
|
*/
|
|
12
|
-
async list(
|
|
12
|
+
async list(workspaceId) {
|
|
13
13
|
const result = await request(this.transport, {
|
|
14
14
|
method: "GET",
|
|
15
15
|
path: "/apps",
|
|
16
|
-
query: {
|
|
16
|
+
query: { workspaceId },
|
|
17
17
|
});
|
|
18
18
|
// `?? []` for the same reason `billing.listPlans` has it: this is a
|
|
19
19
|
// collection every caller immediately maps or measures, and a body without
|
|
@@ -7,7 +7,7 @@ export class BillingResource {
|
|
|
7
7
|
this.transport = transport;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* Your
|
|
10
|
+
* Your application's active plans - render live pricing instead of hardcoding it.
|
|
11
11
|
*
|
|
12
12
|
* `features` is normalised on the way out: Connect used to send bare keys
|
|
13
13
|
* and now sends `{ key, name, description }`, and this SDK is versioned
|
|
@@ -25,7 +25,7 @@ export class BillingResource {
|
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* What is left of every consumable add-on on
|
|
28
|
+
* What is left of every consumable add-on on a workspace's
|
|
29
29
|
* subscription - the read half of `consumeAddon`.
|
|
30
30
|
*
|
|
31
31
|
* Needs a key scoped to `addons:read`, which is separate from
|
|
@@ -35,10 +35,10 @@ export class BillingResource {
|
|
|
35
35
|
* Returns an empty `addons` array rather than throwing when there is
|
|
36
36
|
* nothing to meter, so a caller can render it unconditionally.
|
|
37
37
|
*/
|
|
38
|
-
async getAddonUsage(
|
|
38
|
+
async getAddonUsage(workspaceId) {
|
|
39
39
|
const response = await request(this.transport, {
|
|
40
40
|
method: "GET",
|
|
41
|
-
path: `/addons/
|
|
41
|
+
path: `/addons/workspaces/${pathSegment(workspaceId, "workspaceId")}`,
|
|
42
42
|
});
|
|
43
43
|
// Normalised, not passed through: the promise above resolves for any 2xx,
|
|
44
44
|
// and `ConnectUsageMeter` reads `addons` straight off it. A body without
|
|
@@ -49,7 +49,7 @@ export class BillingResource {
|
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
51
|
* Debit a consumable add-on's per-cycle balance on behalf of an
|
|
52
|
-
*
|
|
52
|
+
* workspace's users. Call it at whatever cadence your usage happens.
|
|
53
53
|
*
|
|
54
54
|
* An `Idempotency-Key` is always sent, generated per call when you do not
|
|
55
55
|
* supply one: a balance cannot be un-spent, so a retried consume without a
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pathSegment, request } from "../http.js";
|
|
2
|
-
/** Files in
|
|
2
|
+
/** Files in a workspace's Drive - upload, and signed URLs to read back. */
|
|
3
3
|
export class DriveResource {
|
|
4
4
|
transport;
|
|
5
5
|
constructor(transport) {
|
|
@@ -9,7 +9,7 @@ export class DriveResource {
|
|
|
9
9
|
const form = new FormData();
|
|
10
10
|
const fileName = input.fileName ?? input.file.name ?? "upload";
|
|
11
11
|
form.set("file", input.file, fileName);
|
|
12
|
-
form.set("
|
|
12
|
+
form.set("workspaceId", input.workspaceId);
|
|
13
13
|
if (input.parentId)
|
|
14
14
|
form.set("parentId", input.parentId);
|
|
15
15
|
return request(this.transport, { method: "POST", path: "/drive/files", multipart: form });
|
|
@@ -19,7 +19,7 @@ export class DriveResource {
|
|
|
19
19
|
const result = await request(this.transport, {
|
|
20
20
|
method: "GET",
|
|
21
21
|
path: `/drive/files/${pathSegment(fileId, "fileId")}/url`,
|
|
22
|
-
query: {
|
|
22
|
+
query: { workspaceId: input.workspaceId },
|
|
23
23
|
});
|
|
24
24
|
return result.url;
|
|
25
25
|
}
|
|
@@ -28,7 +28,7 @@ export class DriveResource {
|
|
|
28
28
|
const result = await request(this.transport, {
|
|
29
29
|
method: "GET",
|
|
30
30
|
path: `/drive/files/${pathSegment(fileId, "fileId")}/preview-url`,
|
|
31
|
-
query: {
|
|
31
|
+
query: { workspaceId: input.workspaceId, size: input.size },
|
|
32
32
|
});
|
|
33
33
|
return result.url;
|
|
34
34
|
}
|
|
@@ -9,7 +9,7 @@ export class EntitlementsResource {
|
|
|
9
9
|
this.transport = transport;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* Every gate Connect owns between
|
|
12
|
+
* Every gate Connect owns between a workspace and your application -
|
|
13
13
|
* subscription, KYC/KYB, a chargeable payment method, seat headroom -
|
|
14
14
|
* resolved in one call.
|
|
15
15
|
*
|
|
@@ -17,17 +17,17 @@ export class EntitlementsResource {
|
|
|
17
17
|
* Connect screen that fixes it, so you can route them somewhere useful
|
|
18
18
|
* instead of refusing them with nowhere to go.
|
|
19
19
|
*/
|
|
20
|
-
getReadiness(
|
|
20
|
+
getReadiness(workspaceId) {
|
|
21
21
|
return request(this.transport, {
|
|
22
22
|
method: "GET",
|
|
23
|
-
path: `/onboarding/
|
|
23
|
+
path: `/onboarding/workspaces/${pathSegment(workspaceId, "workspaceId")}`,
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
/** The live plan and subscription, including `plan.features`. */
|
|
27
|
-
getSubscription(
|
|
27
|
+
getSubscription(workspaceId) {
|
|
28
28
|
return request(this.transport, {
|
|
29
29
|
method: "GET",
|
|
30
|
-
path: `/subscriptions/
|
|
30
|
+
path: `/subscriptions/workspaces/${pathSegment(workspaceId, "workspaceId")}`,
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
@@ -38,8 +38,8 @@ export class EntitlementsResource {
|
|
|
38
38
|
* all: "not entitled" is the same answer either way, and a feature gate
|
|
39
39
|
* should not need a try/catch around it.
|
|
40
40
|
*/
|
|
41
|
-
async hasFeature(
|
|
42
|
-
const result = await this.getSubscription(
|
|
41
|
+
async hasFeature(workspaceId, feature) {
|
|
42
|
+
const result = await this.getSubscription(workspaceId);
|
|
43
43
|
return result.hasActiveSubscription && (result.plan?.features.includes(feature) ?? false);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -66,7 +66,7 @@ export class IdentityResource {
|
|
|
66
66
|
sessionTokenExpiresIn: wire.session_token_expires_in,
|
|
67
67
|
user: wire.user,
|
|
68
68
|
subscription: wire.subscription,
|
|
69
|
-
|
|
69
|
+
applicationRole: wire.applicationRole,
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
@@ -136,7 +136,7 @@ export class IdentityResource {
|
|
|
136
136
|
return {
|
|
137
137
|
user: wire.user,
|
|
138
138
|
subscription: wire.subscription,
|
|
139
|
-
|
|
139
|
+
applicationRole: wire.applicationRole,
|
|
140
140
|
sessionExpiresAt: wire.session_expires_at,
|
|
141
141
|
};
|
|
142
142
|
}
|
|
@@ -145,7 +145,7 @@ export class IdentityResource {
|
|
|
145
145
|
* rest of its ~15-day life. Discard your own copy of `sessionToken` too;
|
|
146
146
|
* this does not do that for you.
|
|
147
147
|
*
|
|
148
|
-
* `scope` defaults to `"device"`: this sign-in, every other
|
|
148
|
+
* `scope` defaults to `"device"`: this sign-in, every other application signed
|
|
149
149
|
* into from the same browser, and Connect's own session on that one device.
|
|
150
150
|
* `"all"` ends every session on every device - an explicit "sign out
|
|
151
151
|
* everywhere" action only.
|
|
@@ -177,7 +177,7 @@ export class IdentityResource {
|
|
|
177
177
|
throw new ConnectError({
|
|
178
178
|
status: 0,
|
|
179
179
|
code: "missing_client_id",
|
|
180
|
-
message: "identity.* needs `clientId`. Pass it to `new ConnectClient({ clientId, apiKey })` - it is shown in this
|
|
180
|
+
message: "identity.* needs `clientId`. Pass it to `new ConnectClient({ clientId, apiKey })` - it is shown in this application's Integration tab, under Connect client.",
|
|
181
181
|
endpoint: "identity",
|
|
182
182
|
});
|
|
183
183
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { request } from "../http.js";
|
|
2
2
|
/**
|
|
3
3
|
* Composio-hosted third-party connections (Google Calendar, Slack,
|
|
4
|
-
* Twitter/X, ...)
|
|
5
|
-
* here - your
|
|
4
|
+
* Twitter/X, ...) a workspace has connected. Connect proxies every call
|
|
5
|
+
* here - your application never sees or holds the underlying OAuth token, which
|
|
6
6
|
* stays with Composio.
|
|
7
7
|
*/
|
|
8
8
|
export class IntegrationsResource {
|
|
@@ -10,12 +10,12 @@ export class IntegrationsResource {
|
|
|
10
10
|
constructor(transport) {
|
|
11
11
|
this.transport = transport;
|
|
12
12
|
}
|
|
13
|
-
/** Enabled toolkits and this
|
|
14
|
-
async list(
|
|
13
|
+
/** Enabled toolkits and this workspace's connection status for each. */
|
|
14
|
+
async list(workspaceId) {
|
|
15
15
|
const result = await request(this.transport, {
|
|
16
16
|
method: "GET",
|
|
17
17
|
path: "/integrations",
|
|
18
|
-
query: {
|
|
18
|
+
query: { workspaceId },
|
|
19
19
|
});
|
|
20
20
|
// `?? []` for the same reason `AppsResource.list` has it - a collection
|
|
21
21
|
// every caller immediately maps or measures.
|
|
@@ -32,31 +32,31 @@ export class IntegrationsResource {
|
|
|
32
32
|
* itself. Reconnecting a disconnected/failed toolkit calls this same
|
|
33
33
|
* method - there is no separate reconnect.
|
|
34
34
|
*
|
|
35
|
-
* Meant to be called on behalf of a signed-in
|
|
35
|
+
* Meant to be called on behalf of a signed-in workspace admin (this is what the
|
|
36
36
|
* bridge's fixed `POST /integrations/connect` route does), not as a bare
|
|
37
37
|
* background action with no admin present to complete the OAuth screen.
|
|
38
38
|
*/
|
|
39
|
-
async initiateConnect(
|
|
39
|
+
async initiateConnect(workspaceId, toolkitSlug, returnUrl) {
|
|
40
40
|
return request(this.transport, {
|
|
41
41
|
method: "POST",
|
|
42
42
|
path: "/integrations/connect",
|
|
43
|
-
json: {
|
|
43
|
+
json: { workspaceId, toolkitSlug, returnUrl },
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
/** Idempotent - disconnecting a toolkit that was never connected, or is already disconnected, is a success. */
|
|
47
|
-
async disconnect(
|
|
47
|
+
async disconnect(workspaceId, toolkitSlug) {
|
|
48
48
|
return request(this.transport, {
|
|
49
49
|
method: "POST",
|
|
50
50
|
path: "/integrations/disconnect",
|
|
51
|
-
json: {
|
|
51
|
+
json: { workspaceId, toolkitSlug },
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
|
-
/** Calls a Composio action against this
|
|
55
|
-
async execute(
|
|
54
|
+
/** Calls a Composio action against this workspace's connected account for the named toolkit. */
|
|
55
|
+
async execute(workspaceId, input) {
|
|
56
56
|
return request(this.transport, {
|
|
57
57
|
method: "POST",
|
|
58
58
|
path: "/integrations/actions/execute",
|
|
59
|
-
json: {
|
|
59
|
+
json: { workspaceId, ...input },
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { request } from "../http.js";
|
|
2
|
-
/** Push feature events into the Console's audit log, filterable to your
|
|
2
|
+
/** Push feature events into the Console's audit log, filterable to your application. */
|
|
3
3
|
export class LogsResource {
|
|
4
4
|
transport;
|
|
5
5
|
constructor(transport) {
|
|
@@ -11,9 +11,9 @@ export class LogsResource {
|
|
|
11
11
|
* reported through the return value.
|
|
12
12
|
*
|
|
13
13
|
* Pass `sessionToken` to attribute the event to the end user it belongs to.
|
|
14
|
-
* Both scopes on the stored entry come from something verified - the
|
|
14
|
+
* Both scopes on the stored entry come from something verified - the application
|
|
15
15
|
* from your API key, the user from that token, which Connect checks was
|
|
16
|
-
* minted for your
|
|
16
|
+
* minted for your application before attributing anything. `attributed` in the
|
|
17
17
|
* result says whether it resolved; a `false` there still means the line was
|
|
18
18
|
* stored, just without a user on it.
|
|
19
19
|
*/
|
|
@@ -5,11 +5,11 @@ import { request } from "../http.js";
|
|
|
5
5
|
* timestamps - the same list Connect's own account settings page shows the
|
|
6
6
|
* user themselves.
|
|
7
7
|
*
|
|
8
|
-
* **Account-wide, not scoped to this
|
|
9
|
-
* browser's login to Connect, and it fans out to every partner
|
|
10
|
-
* `sessionToken` - Connect has no per-
|
|
8
|
+
* **Account-wide, not scoped to this application.** A Connect session is one
|
|
9
|
+
* browser's login to Connect, and it fans out to every partner application's own
|
|
10
|
+
* `sessionToken` - Connect has no per-application session concept to filter by.
|
|
11
11
|
* `list()` returns every session on the account, including ones that
|
|
12
|
-
* originated from a completely different, unrelated
|
|
12
|
+
* originated from a completely different, unrelated application. Requires the
|
|
13
13
|
* `sessions:manage` scope on your API key - unlike `identity`'s base `sso`
|
|
14
14
|
* capability, this is never granted to a zero-scope legacy key by default.
|
|
15
15
|
*
|
|
@@ -35,7 +35,7 @@ export class SessionsResource {
|
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Ends one specific session by id - not necessarily the one `sessionToken`
|
|
38
|
-
* itself was minted from. Cascades to every partner-
|
|
38
|
+
* itself was minted from. Cascades to every partner-application sign-in that
|
|
39
39
|
* originated from that same browser, same as Connect's own "sign out this
|
|
40
40
|
* device".
|
|
41
41
|
*/
|
|
@@ -69,7 +69,7 @@ export class SessionsResource {
|
|
|
69
69
|
throw new ConnectError({
|
|
70
70
|
status: 0,
|
|
71
71
|
code: "missing_client_id",
|
|
72
|
-
message: "sessions.* needs `clientId`. Pass it to `new ConnectClient({ clientId, apiKey })` - it is shown in this
|
|
72
|
+
message: "sessions.* needs `clientId`. Pass it to `new ConnectClient({ clientId, apiKey })` - it is shown in this application's Integration tab, under Connect client.",
|
|
73
73
|
endpoint: "sessions",
|
|
74
74
|
});
|
|
75
75
|
}
|
|
@@ -54,10 +54,10 @@ export function verifyConnectWebhook(rawBody, signatureHeader, secret, now = new
|
|
|
54
54
|
* export const POST = createConnectWebhookHandler({
|
|
55
55
|
* secret: process.env.CONNECT_WEBHOOK_SECRET!,
|
|
56
56
|
* on: {
|
|
57
|
-
* "
|
|
58
|
-
* freeze(
|
|
59
|
-
* "
|
|
60
|
-
* "
|
|
57
|
+
* "workspace.deletion_scheduled": ({ workspaceId, purgeAfter }) =>
|
|
58
|
+
* freeze(workspaceId, purgeAfter),
|
|
59
|
+
* "workspace.deletion_cancelled": ({ workspaceId }) => unfreeze(workspaceId),
|
|
60
|
+
* "workspace.deleted": ({ workspaceId }) => purge(workspaceId),
|
|
61
61
|
* },
|
|
62
62
|
* })
|
|
63
63
|
* ```
|
package/dist/esm/types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Wire types for the `/api/v1/
|
|
2
|
+
* Wire types for the `/api/v1/application/*` surface - the application-partner API,
|
|
3
3
|
* and the only thing this SDK covers.
|
|
4
4
|
*
|
|
5
5
|
* Hand-written rather than generated so the published package carries no
|
|
@@ -3,7 +3,7 @@ import type { ReadinessBlocker } from "../../types.js";
|
|
|
3
3
|
export type ConnectAccessGateState = "loading"
|
|
4
4
|
/** No signed-in user - not this component's concern, see the doc comment on `ConnectAccessGate`. */
|
|
5
5
|
| "signed_out"
|
|
6
|
-
/** `
|
|
6
|
+
/** `workspace_suspended` - a platform admin took this workspace offline. Hard block, no dismiss. */
|
|
7
7
|
| "suspended"
|
|
8
8
|
/** `subscription_missing` - nothing to subscribe to yet. Hard block. */
|
|
9
9
|
| "no_subscription"
|
|
@@ -10,7 +10,7 @@ export interface ConnectAccountSessionsProps {
|
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Every device signed into this Connect account - not scoped to this
|
|
13
|
-
*
|
|
13
|
+
* application, see `ConnectUserSession`'s doc comment. Owns the one
|
|
14
14
|
* `useConnectSessions()` call for this modal; every revoke action here
|
|
15
15
|
* mutates through it and re-reads the list itself, since nothing else
|
|
16
16
|
* invalidates it automatically - see `mutateResource`'s doc comment.
|
|
@@ -2,9 +2,9 @@ import { type ReactNode } from "react";
|
|
|
2
2
|
import { type ConnectLinkRenderer, type ConnectNav } from "./nav.js";
|
|
3
3
|
import type { ThemeMode } from "../../types.js";
|
|
4
4
|
export interface ConnectAppShellProps {
|
|
5
|
-
/** This
|
|
5
|
+
/** This application's name, in the `cosmo·ops VOICE` lockup. See `ConnectLogo`. */
|
|
6
6
|
name: string;
|
|
7
|
-
/** This
|
|
7
|
+
/** This application's glyph, drawn on the CosmoOps badge. Falls back to the Connect rings. */
|
|
8
8
|
icon?: ReactNode;
|
|
9
9
|
/** Where the lockup links. Defaults to `/`. */
|
|
10
10
|
homeHref?: string;
|
|
@@ -67,12 +67,12 @@ export interface ConnectAppShellProps {
|
|
|
67
67
|
children: ReactNode;
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
|
-
* The application frame every CosmoOps
|
|
70
|
+
* The application frame every CosmoOps application platform runs inside: a
|
|
71
71
|
* collapsible sidebar, a top bar carrying the app launcher and the account
|
|
72
72
|
* menu, and your pages in the middle.
|
|
73
73
|
*
|
|
74
74
|
* This is the piece each partner was otherwise writing by hand, and writing
|
|
75
|
-
* slightly differently - which is how a family of
|
|
75
|
+
* slightly differently - which is how a family of applications stops looking like
|
|
76
76
|
* one product. Everything that should be identical across platforms (the
|
|
77
77
|
* lockup, the rail geometry, the active-route treatment, the launcher, the
|
|
78
78
|
* account menu, the access gate) lives here; everything that genuinely
|
|
@@ -6,7 +6,7 @@ export interface ConnectAppsGridProps {
|
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* The Google-style app launcher: a grid icon in your top bar that opens a
|
|
9
|
-
* modal of every Connect
|
|
9
|
+
* modal of every Connect application this workspace can actually open.
|
|
10
10
|
*
|
|
11
11
|
* Only launchable apps appear, so no tile is a dead end - a paused
|
|
12
12
|
* subscription still shows, badged, because a dunning cycle should not make a
|
|
@@ -48,7 +48,7 @@ export interface ConnectFeatureGateProps {
|
|
|
48
48
|
*
|
|
49
49
|
* Like every gate in this package, it is a **UX gate, not a security
|
|
50
50
|
* boundary**: the entitlement is read through your own origin and the browser
|
|
51
|
-
* can ignore it. Check `client.entitlements.hasFeature(
|
|
51
|
+
* can ignore it. Check `client.entitlements.hasFeature(workspaceId, feature)` on the
|
|
52
52
|
* server before doing the thing the feature unlocks.
|
|
53
53
|
*
|
|
54
54
|
* Renders `loading` - not `fallback` - while the answer is unknown, so a paying
|
|
@@ -5,7 +5,7 @@ export interface ConnectIntegrationsModalProps {
|
|
|
5
5
|
label?: string;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* A grid of every Composio-hosted toolkit this
|
|
8
|
+
* A grid of every Composio-hosted toolkit this workspace can connect -
|
|
9
9
|
* Google Calendar, Slack, Twitter/X, whatever a platform admin enabled in
|
|
10
10
|
* Connect's own Console. Each tile carries its own connect/reconnect/
|
|
11
11
|
* disconnect action and its own pending state, independent of every other
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
export interface ConnectLogoProps {
|
|
3
3
|
/**
|
|
4
|
-
* This
|
|
4
|
+
* This application's name - rendered as the sub-brand beneath the `cosmo·ops`
|
|
5
5
|
* wordmark, in the house `cosmo·ops VOICE` treatment.
|
|
6
6
|
*/
|
|
7
7
|
name: string;
|
|
8
8
|
/**
|
|
9
|
-
* This
|
|
9
|
+
* This application's own glyph, drawn inside the accent badge. Any node - a
|
|
10
10
|
* `lucide-react` icon, an `<img>`, an inline `<svg>`. Paint it with
|
|
11
11
|
* `currentColor` and it inherits `--accent-foreground` from the badge, so it
|
|
12
12
|
* stays legible when a host app changes the accent.
|
|
@@ -19,10 +19,10 @@ export interface ConnectLogoProps {
|
|
|
19
19
|
className?: string;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* The shared platform lockup:
|
|
23
|
-
* `cosmo·ops` beside it, and the
|
|
22
|
+
* The shared platform lockup: an application's own glyph on the CosmoOps badge,
|
|
23
|
+
* `cosmo·ops` beside it, and the application name underneath.
|
|
24
24
|
*
|
|
25
|
-
* This is what makes a family of
|
|
25
|
+
* This is what makes a family of application platforms look like one product. Each
|
|
26
26
|
* platform passes only what differs - its `name` and its `icon` - and inherits
|
|
27
27
|
* the mark geometry, the wordmark treatment, the separator, and the accent from
|
|
28
28
|
* one place. Change the lockup here and every platform follows.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* an upgrade while the card behind it said downgrade would be worse than
|
|
5
5
|
* either label being wrong on its own.
|
|
6
6
|
*
|
|
7
|
-
* Mirrors `packages/data/src/
|
|
7
|
+
* Mirrors `packages/data/src/applications/catalog.ts` and
|
|
8
8
|
* `packages/data/src/payments/plan-change.ts`, which are the copies Connect's
|
|
9
9
|
* own UI uses and which decide which use-case actually runs. The duplication
|
|
10
10
|
* is deliberate and load-bearing: this package carries no dependency on
|
|
@@ -81,7 +81,7 @@ export declare function groupPlansByTier(plans: readonly Plan[]): PlanTier[];
|
|
|
81
81
|
*/
|
|
82
82
|
export declare function annualSaving(monthly: Plan | null | undefined, annual: Plan | null | undefined): number | null;
|
|
83
83
|
/**
|
|
84
|
-
* What moving to `plan` would be, given what the
|
|
84
|
+
* What moving to `plan` would be, given what the workspace is on today.
|
|
85
85
|
*
|
|
86
86
|
* `switch-to-annual`/`switch-to-monthly` exist because a change of *cadence*
|
|
87
87
|
* is neither an upgrade nor a downgrade, and calling it one is not a wording
|
|
@@ -6,7 +6,7 @@ export interface ConnectReadinessBannerProps {
|
|
|
6
6
|
className?: string;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
* Every gate between this workspace and your
|
|
9
|
+
* Every gate between this workspace and your application, with the way out of each.
|
|
10
10
|
*
|
|
11
11
|
* This is the component that keeps a blocked customer from staring at a broken
|
|
12
12
|
* app. `getReadiness` resolves subscription state, KYC/KYB, a chargeable
|
|
@@ -14,7 +14,7 @@ export interface ConnectReadinessBannerProps {
|
|
|
14
14
|
* `resolveUrl` into the exact Connect screen that fixes it** - so being blocked
|
|
15
15
|
* comes with somewhere to go rather than a refusal.
|
|
16
16
|
*
|
|
17
|
-
* Render it high on any page your
|
|
17
|
+
* Render it high on any page your application gates. It draws nothing at all when
|
|
18
18
|
* the workspace is ready, so it is safe to leave mounted permanently.
|
|
19
19
|
*
|
|
20
20
|
* Two deliberate refusals:
|
|
@@ -5,11 +5,11 @@ export interface ConnectSubscribeDialogProps {
|
|
|
5
5
|
plan: Plan | null;
|
|
6
6
|
/** Which of subscribe / upgrade / downgrade this is - decides the headline and what the notice says about money. */
|
|
7
7
|
action: PlanAction;
|
|
8
|
-
/** The
|
|
8
|
+
/** The workspace's live subscription, for the "from" side of a plan change. */
|
|
9
9
|
current: SubscriptionResponse | null;
|
|
10
10
|
/** Coupon typed into the plan grid, echoed here so it is visible before the hand-off carries it. */
|
|
11
11
|
coupon?: string;
|
|
12
|
-
/** Whether this
|
|
12
|
+
/** Whether this workspace's `plan.trialDays` still applies is Connect's call, not this component's - see the notice below. */
|
|
13
13
|
onClose(): void;
|
|
14
14
|
onConfirm(): void;
|
|
15
15
|
}
|
|
@@ -26,7 +26,7 @@ export interface ConnectSubscribeDialogProps {
|
|
|
26
26
|
* The authoritative price is computed by Connect against the real cart:
|
|
27
27
|
* proration is priced against the actual cycle, a coupon is validated
|
|
28
28
|
* against the plan it is being applied to, trial eligibility depends on
|
|
29
|
-
* whether this
|
|
29
|
+
* whether this workspace has ever subscribed to this application before, and
|
|
30
30
|
* an accumulated credit is deducted. None of that is knowable from the
|
|
31
31
|
* partner's origin, so this component states the list price and says where
|
|
32
32
|
* the final figure comes from rather than quietly guessing at one.
|
|
@@ -11,7 +11,7 @@ export interface ConnectUsageMeterProps {
|
|
|
11
11
|
*
|
|
12
12
|
* Reads the balance Connect actually debits, so the number here and the number
|
|
13
13
|
* `consumeAddon` enforces cannot disagree. Before the `addons:read` endpoint
|
|
14
|
-
* existed this component was impossible to write honestly:
|
|
14
|
+
* existed this component was impossible to write honestly: an application could
|
|
15
15
|
* spend an allowance down on every request and the only thing the API exposed
|
|
16
16
|
* was the list of add-on *ids* on the subscription.
|
|
17
17
|
*
|