@cosmoops/connect-sdk 0.7.0 → 0.15.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 +662 -0
- package/README.md +376 -124
- package/dist/cjs/cli/doctor.js +3 -3
- package/dist/cjs/cli/init.js +3 -3
- package/dist/cjs/client/components/access-gate.js +59 -5
- package/dist/cjs/client/components/ai-format.js +135 -0
- package/dist/cjs/client/components/ai-widgets.js +232 -0
- package/dist/cjs/client/components/app-shell.js +80 -45
- package/dist/cjs/client/components/apps-grid.js +3 -2
- package/dist/cjs/client/components/ask-ai.js +353 -0
- package/dist/cjs/client/components/confirm-dialog.js +40 -0
- package/dist/cjs/client/components/cursor-pagination.js +22 -0
- package/dist/cjs/client/components/filter-tabs.js +24 -0
- package/dist/cjs/client/components/grievance-notice.js +30 -0
- package/dist/cjs/client/components/link-button.js +17 -10
- package/dist/cjs/client/components/logo.js +4 -3
- package/dist/cjs/client/components/nav.js +42 -1
- package/dist/cjs/client/components/plan-pricing.js +27 -0
- package/dist/cjs/client/components/plans.js +1 -1
- package/dist/cjs/client/components/platform-gate.js +48 -0
- package/dist/cjs/client/components/shell-context.js +149 -0
- package/dist/cjs/client/components/side-nav.js +50 -24
- package/dist/cjs/client/components/sidebar.js +127 -0
- package/dist/cjs/client/components/subscribe-dialog.js +2 -2
- package/dist/cjs/client/components/subscription.js +1 -1
- package/dist/cjs/client/components/user-menu.js +122 -40
- package/dist/cjs/client/components/workspace-switcher.js +100 -0
- package/dist/cjs/client/components/workspace-type-gate.js +48 -0
- package/dist/cjs/client/index.js +98 -3
- package/dist/cjs/client/provider.js +100 -2
- package/dist/cjs/client/use-checkout.js +9 -5
- package/dist/cjs/errors.js +1 -1
- package/dist/cjs/index.js +11 -1
- package/dist/cjs/next/index.js +2 -2
- package/dist/cjs/server/client.js +25 -2
- package/dist/cjs/server/handler.js +237 -16
- package/dist/cjs/server/http.js +52 -26
- package/dist/cjs/server/resources/acting-as.js +16 -0
- package/dist/cjs/server/resources/ai.js +15 -2
- package/dist/cjs/server/resources/data.js +374 -0
- package/dist/cjs/server/resources/entitlements.js +41 -0
- package/dist/cjs/server/resources/identity.js +9 -3
- package/dist/cjs/server/resources/kv.js +84 -0
- package/dist/cjs/server/resources/platform.js +43 -0
- package/dist/cjs/server/resources/sessions.js +1 -1
- package/dist/cjs/server/resources/workspaces.js +74 -0
- package/dist/cjs/store.js +152 -0
- package/dist/cjs/ui/empty-state.js +28 -0
- package/dist/cjs/ui/index.js +44 -0
- package/dist/cjs/ui/page-header.js +27 -0
- package/dist/cjs/ui/page-shell.js +44 -0
- package/dist/cjs/ui/section.js +20 -0
- package/dist/cjs/ui/setting-row.js +14 -0
- package/dist/cjs/ui/status-chip.js +17 -0
- package/dist/esm/cli/doctor.js +3 -3
- package/dist/esm/cli/init.js +3 -3
- package/dist/esm/client/components/access-gate.js +60 -6
- package/dist/esm/client/components/ai-format.js +129 -0
- package/dist/esm/client/components/ai-widgets.js +223 -0
- package/dist/esm/client/components/app-shell.js +85 -50
- package/dist/esm/client/components/apps-grid.js +3 -2
- package/dist/esm/client/components/ask-ai.js +350 -0
- package/dist/esm/client/components/confirm-dialog.js +37 -0
- package/dist/esm/client/components/cursor-pagination.js +19 -0
- package/dist/esm/client/components/filter-tabs.js +21 -0
- package/dist/esm/client/components/grievance-notice.js +27 -0
- package/dist/esm/client/components/link-button.js +17 -10
- package/dist/esm/client/components/logo.js +4 -3
- package/dist/esm/client/components/nav.js +41 -1
- package/dist/esm/client/components/plan-pricing.js +25 -0
- package/dist/esm/client/components/plans.js +2 -2
- package/dist/esm/client/components/platform-gate.js +45 -0
- package/dist/esm/client/components/shell-context.js +141 -0
- package/dist/esm/client/components/side-nav.js +49 -22
- package/dist/esm/client/components/sidebar.js +120 -0
- package/dist/esm/client/components/subscribe-dialog.js +3 -3
- package/dist/esm/client/components/subscription.js +2 -2
- package/dist/esm/client/components/user-menu.js +121 -41
- package/dist/esm/client/components/workspace-switcher.js +97 -0
- package/dist/esm/client/components/workspace-type-gate.js +45 -0
- package/dist/esm/client/index.js +58 -5
- package/dist/esm/client/provider.js +94 -2
- package/dist/esm/client/use-checkout.js +9 -5
- package/dist/esm/errors.js +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/next/index.js +2 -2
- package/dist/esm/server/client.js +25 -2
- package/dist/esm/server/handler.js +237 -16
- package/dist/esm/server/http.js +52 -26
- package/dist/esm/server/resources/acting-as.js +13 -0
- package/dist/esm/server/resources/ai.js +15 -2
- package/dist/esm/server/resources/data.js +369 -0
- package/dist/esm/server/resources/entitlements.js +41 -0
- package/dist/esm/server/resources/identity.js +9 -3
- package/dist/esm/server/resources/kv.js +80 -0
- package/dist/esm/server/resources/platform.js +39 -0
- package/dist/esm/server/resources/sessions.js +1 -1
- package/dist/esm/server/resources/workspaces.js +70 -0
- package/dist/esm/store.js +141 -0
- package/dist/esm/ui/empty-state.js +25 -0
- package/dist/esm/ui/index.js +34 -0
- package/dist/esm/ui/page-header.js +24 -0
- package/dist/esm/ui/page-shell.js +41 -0
- package/dist/esm/ui/section.js +17 -0
- package/dist/esm/ui/setting-row.js +11 -0
- package/dist/esm/ui/status-chip.js +14 -0
- package/dist/theme.css +87 -0
- package/dist/types/client/components/access-gate.d.ts +17 -3
- package/dist/types/client/components/ai-format.d.ts +24 -0
- package/dist/types/client/components/ai-widgets.d.ts +42 -0
- package/dist/types/client/components/app-shell.d.ts +85 -31
- package/dist/types/client/components/apps-grid.d.ts +11 -2
- package/dist/types/client/components/ask-ai.d.ts +73 -0
- package/dist/types/client/components/confirm-dialog.d.ts +34 -0
- package/dist/types/client/components/cursor-pagination.d.ts +27 -0
- package/dist/types/client/components/filter-tabs.d.ts +26 -0
- package/dist/types/client/components/grievance-notice.d.ts +31 -0
- package/dist/types/client/components/link-button.d.ts +32 -9
- package/dist/types/client/components/logo.d.ts +18 -2
- package/dist/types/client/components/nav.d.ts +27 -3
- package/dist/types/client/components/plan-pricing.d.ts +10 -0
- package/dist/types/client/components/platform-gate.d.ts +53 -0
- package/dist/types/client/components/shell-context.d.ts +116 -0
- package/dist/types/client/components/side-nav.d.ts +28 -14
- package/dist/types/client/components/sidebar.d.ts +95 -0
- package/dist/types/client/components/user-menu.d.ts +70 -23
- package/dist/types/client/components/workspace-switcher.d.ts +49 -0
- package/dist/types/client/components/workspace-type-gate.d.ts +48 -0
- package/dist/types/client/index.d.ts +36 -7
- package/dist/types/client/provider.d.ts +149 -3
- package/dist/types/client/use-checkout.d.ts +8 -4
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/next/index.d.ts +1 -1
- package/dist/types/server/client.d.ts +25 -2
- package/dist/types/server/http.d.ts +14 -3
- package/dist/types/server/index.d.ts +4 -0
- package/dist/types/server/resources/acting-as.d.ts +11 -0
- package/dist/types/server/resources/ai.d.ts +9 -1
- package/dist/types/server/resources/data.d.ts +258 -0
- package/dist/types/server/resources/entitlements.d.ts +33 -1
- package/dist/types/server/resources/kv.d.ts +63 -0
- package/dist/types/server/resources/platform.d.ts +32 -0
- package/dist/types/server/resources/workspaces.d.ts +55 -0
- package/dist/types/store.d.ts +96 -0
- package/dist/types/types.d.ts +491 -13
- package/dist/types/ui/empty-state.d.ts +34 -0
- package/dist/types/ui/index.d.ts +40 -0
- package/dist/types/ui/page-header.d.ts +34 -0
- package/dist/types/ui/page-shell.d.ts +39 -0
- package/dist/types/ui/section.d.ts +26 -0
- package/dist/types/ui/setting-row.d.ts +18 -0
- package/dist/types/ui/status-chip.d.ts +36 -0
- package/package.json +13 -3
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
-
import type { AddonUsageResponse, ConnectUser, IntegrationsListResponse, WorkspaceApp, PlansResponse, ReadinessResponse,
|
|
2
|
+
import type { AddonUsageResponse, CompanyProfileResponse, ConnectUser, IntegrationsListResponse, WorkspaceApp, UserWorkspace, ConnectWorkspaceMember, PlansResponse, ReadinessResponse, SessionsListResponse, SessionSubscription, SessionAudience, SubscriptionResponse, WorkspaceType } from "../types.js";
|
|
3
3
|
export declare const CONNECT_APP_URL = "https://connect.cosmoops.com";
|
|
4
4
|
export interface ConnectSession {
|
|
5
5
|
user: ConnectUser | null;
|
|
6
6
|
subscription: SessionSubscription | null;
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The signed-in account's role on this application, or `null` - see
|
|
9
|
+
* `SessionAccess.role`. `null` when signed out too, which is why `user`
|
|
10
|
+
* rather than this is the signed-in test.
|
|
11
|
+
*/
|
|
12
|
+
role: string | null;
|
|
13
|
+
/** What to gate on - see `SessionAccess.permissions`. `[]` when signed out. */
|
|
14
|
+
permissions: string[];
|
|
15
|
+
/** Whether this is one of Connect's own operators - see `SessionAccess.staff`. `false` when signed out. */
|
|
16
|
+
staff: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* `null` when signed out, for the same reason `user` and `subscription`
|
|
19
|
+
* are: there is no workspace to compare an audience against yet. Never
|
|
20
|
+
* `null` on a signed-in session.
|
|
21
|
+
*/
|
|
22
|
+
audience: SessionAudience | null;
|
|
8
23
|
}
|
|
9
24
|
export interface ConnectContextValue {
|
|
10
25
|
/**
|
|
@@ -58,10 +73,26 @@ export interface ConnectContextValue {
|
|
|
58
73
|
* page.
|
|
59
74
|
*/
|
|
60
75
|
invalidateResource(path: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* POST through the bridge and hand back the raw `Response`, unread and
|
|
78
|
+
* uncached - the seam `<ConnectAskAi>` streams server-sent events over.
|
|
79
|
+
*
|
|
80
|
+
* Separate from `mutateResource` rather than a flag on it, because the two
|
|
81
|
+
* differ in every respect that matters: this one must not `await
|
|
82
|
+
* response.json()` (that buffers the whole stream and defeats the point),
|
|
83
|
+
* must not touch the resource cache (a conversation is not a resource), and
|
|
84
|
+
* takes an `AbortSignal` so a "Stop" button can actually stop generation.
|
|
85
|
+
*
|
|
86
|
+
* Throws on a non-2xx, having read the error envelope - which is safe,
|
|
87
|
+
* because a failure never has a stream behind it.
|
|
88
|
+
*/
|
|
89
|
+
streamResource(path: string, body: unknown, options?: {
|
|
90
|
+
signal?: AbortSignal;
|
|
91
|
+
}): Promise<Response>;
|
|
61
92
|
}
|
|
62
93
|
export interface ConnectProviderProps {
|
|
63
94
|
/**
|
|
64
|
-
* This application's public `client_id`, from its
|
|
95
|
+
* This application's public `client_id`, from its Connect client section in Connect.
|
|
65
96
|
*
|
|
66
97
|
* Not needed for the default sign-in flow: `signIn()` with no `redirectUri`
|
|
67
98
|
* bounces the browser to your own `/signin` route, which already knows
|
|
@@ -128,6 +159,56 @@ export declare function ConnectProvider({ clientId, basePath, redirectUri, appUr
|
|
|
128
159
|
export declare function useConnect(): ConnectContextValue;
|
|
129
160
|
/** The signed-in user, or `null`. Sugar over `useConnect().session`. */
|
|
130
161
|
export declare function useConnectUser(): ConnectUser | null;
|
|
162
|
+
/**
|
|
163
|
+
* Whether the signed-in workspace is a one-seat personal account or a team -
|
|
164
|
+
* `null` while the session is loading or signed out.
|
|
165
|
+
*
|
|
166
|
+
* Branch on this to stop rendering team UI at a solo account: a members
|
|
167
|
+
* table, an invite button and a seat meter are all dead controls on an
|
|
168
|
+
* `"individual"` workspace, which has exactly one seat and cannot gain
|
|
169
|
+
* another. `<ConnectWorkspaceTypeGate>` is the declarative form.
|
|
170
|
+
*/
|
|
171
|
+
export declare function useConnectWorkspaceType(): WorkspaceType | null;
|
|
172
|
+
/**
|
|
173
|
+
* Whether this account is the kind your application is sold to - `null` while
|
|
174
|
+
* the session is loading or signed out.
|
|
175
|
+
*
|
|
176
|
+
* `audience.matches === false` is a hard block, not a hint: readiness reports
|
|
177
|
+
* `audience_mismatch` and subscribing is refused. `<ConnectAccessGate>`
|
|
178
|
+
* already blocks the shell on it, so reach for this only when you need the
|
|
179
|
+
* verdict somewhere the gate does not run - a marketing page, say, or a
|
|
180
|
+
* sign-up CTA you would rather not show to an account that cannot complete it.
|
|
181
|
+
*/
|
|
182
|
+
export declare function useConnectAudience(): SessionAudience | null;
|
|
183
|
+
/**
|
|
184
|
+
* Whether this session is one of Connect's own operators - see
|
|
185
|
+
* `SessionAccess.staff`.
|
|
186
|
+
*
|
|
187
|
+
* `isStaff` is the branch you want; `roles` narrows further when your operator
|
|
188
|
+
* console has tiers of its own (a `developer` seeing a read-only view of what
|
|
189
|
+
* a `platform_admin` can edit, say).
|
|
190
|
+
*
|
|
191
|
+
* **A rendering decision, not an access decision.** The browser can call this
|
|
192
|
+
* whatever it likes. Everything an operator console exposes must be re-checked
|
|
193
|
+
* server-side against `staff` from
|
|
194
|
+
* `client.identity.getUser(sessionToken)` - see `<ConnectPlatformGate>`, which
|
|
195
|
+
* says the same thing at more length.
|
|
196
|
+
*/
|
|
197
|
+
export declare function useConnectPlatformAccess(): {
|
|
198
|
+
isStaff: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* The staff role, as a one-element array.
|
|
201
|
+
*
|
|
202
|
+
* Still an array because `<ConnectPlatformGate accept={[...]}>` matches
|
|
203
|
+
* against a set, and because a session reports one role since
|
|
204
|
+
* `role`/`permissions`/`staff` replaced the old `platformAccess.roles`
|
|
205
|
+
* list - Connect's platform roles nest, so the highest one is the whole
|
|
206
|
+
* answer. Empty for a member session.
|
|
207
|
+
*/
|
|
208
|
+
roles: string[];
|
|
209
|
+
/** `true` while the session read is in flight - neither staff nor not-staff yet. */
|
|
210
|
+
isLoading: boolean;
|
|
211
|
+
};
|
|
131
212
|
/** Readiness gates and the live subscription, fetched on first use. */
|
|
132
213
|
export declare function useConnectEntitlements(): {
|
|
133
214
|
data: {
|
|
@@ -179,6 +260,29 @@ export declare function useConnectPlans(): {
|
|
|
179
260
|
*/
|
|
180
261
|
refetch(): void;
|
|
181
262
|
};
|
|
263
|
+
/**
|
|
264
|
+
* The platform's legal identity and DPDP grievance channel.
|
|
265
|
+
*
|
|
266
|
+
* The one read here that does not depend on a session, so it resolves the
|
|
267
|
+
* same for a signed-out visitor - which is deliberate, because the moment a
|
|
268
|
+
* grievance channel most needs to be readable is on a public privacy page.
|
|
269
|
+
*
|
|
270
|
+
* Read it rather than copying it into your own configuration; see
|
|
271
|
+
* `CompanyProfile`. `<ConnectGrievanceNotice>` renders it for you.
|
|
272
|
+
*/
|
|
273
|
+
export declare function useConnectCompanyProfile(): {
|
|
274
|
+
data: CompanyProfileResponse | null;
|
|
275
|
+
isLoading: boolean;
|
|
276
|
+
error: string | null;
|
|
277
|
+
/**
|
|
278
|
+
* Forces a fresh read - the provider's cache clears the mutated path's
|
|
279
|
+
* entry on a successful `mutateResource` call, but nothing re-triggers
|
|
280
|
+
* this hook's own effect on its own (none of its dependencies change from
|
|
281
|
+
* a cache write nobody here observes). Call this right after a
|
|
282
|
+
* `mutateResource` you made against the same `path` completes.
|
|
283
|
+
*/
|
|
284
|
+
refetch(): void;
|
|
285
|
+
};
|
|
182
286
|
/** The apps this workspace can open. */
|
|
183
287
|
export declare function useConnectApps(): {
|
|
184
288
|
data: {
|
|
@@ -195,6 +299,48 @@ export declare function useConnectApps(): {
|
|
|
195
299
|
*/
|
|
196
300
|
refetch(): void;
|
|
197
301
|
};
|
|
302
|
+
/**
|
|
303
|
+
* The workspaces this user belongs to - what `<ConnectWorkspaceSwitcher>`
|
|
304
|
+
* renders.
|
|
305
|
+
*
|
|
306
|
+
* Empty or single-entry results are normal, not errors: most accounts have one
|
|
307
|
+
* workspace, and the switcher decides for itself whether that is worth
|
|
308
|
+
* drawing.
|
|
309
|
+
*/
|
|
310
|
+
export declare function useConnectWorkspaces(): {
|
|
311
|
+
data: {
|
|
312
|
+
workspaces: UserWorkspace[];
|
|
313
|
+
} | null;
|
|
314
|
+
isLoading: boolean;
|
|
315
|
+
error: string | null;
|
|
316
|
+
/**
|
|
317
|
+
* Forces a fresh read - the provider's cache clears the mutated path's
|
|
318
|
+
* entry on a successful `mutateResource` call, but nothing re-triggers
|
|
319
|
+
* this hook's own effect on its own (none of its dependencies change from
|
|
320
|
+
* a cache write nobody here observes). Call this right after a
|
|
321
|
+
* `mutateResource` you made against the same `path` completes.
|
|
322
|
+
*/
|
|
323
|
+
refetch(): void;
|
|
324
|
+
};
|
|
325
|
+
/**
|
|
326
|
+
* The team of the workspace this session is on, with each member's permissions
|
|
327
|
+
* already resolved for this application.
|
|
328
|
+
*/
|
|
329
|
+
export declare function useConnectWorkspaceMembers(): {
|
|
330
|
+
data: {
|
|
331
|
+
members: ConnectWorkspaceMember[];
|
|
332
|
+
} | null;
|
|
333
|
+
isLoading: boolean;
|
|
334
|
+
error: string | null;
|
|
335
|
+
/**
|
|
336
|
+
* Forces a fresh read - the provider's cache clears the mutated path's
|
|
337
|
+
* entry on a successful `mutateResource` call, but nothing re-triggers
|
|
338
|
+
* this hook's own effect on its own (none of its dependencies change from
|
|
339
|
+
* a cache write nobody here observes). Call this right after a
|
|
340
|
+
* `mutateResource` you made against the same `path` completes.
|
|
341
|
+
*/
|
|
342
|
+
refetch(): void;
|
|
343
|
+
};
|
|
198
344
|
/** Enabled Composio-hosted toolkits and this workspace's connection status for each. */
|
|
199
345
|
export declare function useConnectIntegrations(): {
|
|
200
346
|
data: IntegrationsListResponse | null;
|
|
@@ -85,9 +85,13 @@ export declare function buildCancelUrl({ appUrl, subscriptionId }: {
|
|
|
85
85
|
* The Connect URL that completes a subscribe or a plan change.
|
|
86
86
|
*
|
|
87
87
|
* Both land on a modal Connect renders over the relevant page (an intercepted
|
|
88
|
-
* parallel route - `app/@modal/(.)
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
88
|
+
* parallel route - `app/@modal/(.)apps/...` and `app/@modal/(.)billing/...`),
|
|
89
|
+
* so the customer arrives already looking at the confirmation for the plan
|
|
90
|
+
* they picked here, not at a catalogue they have to find it in again.
|
|
91
|
+
*
|
|
92
|
+
* The subscribe path is `/apps/...`, not `/applications/...`: the portal
|
|
93
|
+
* route customers see is `/apps`, and `/applications` is a Console-only
|
|
94
|
+
* prefix that has never served this page. Building the other one is what
|
|
95
|
+
* sent every first-time subscriber from a partner's pricing page to a 404.
|
|
92
96
|
*/
|
|
93
97
|
export declare function buildCheckoutUrl({ appUrl, applicationId, planId, subscriptionId, coupon, }: CheckoutUrlOptions): string;
|
package/dist/types/errors.d.ts
CHANGED
|
@@ -52,7 +52,7 @@ export declare class ConnectError extends Error {
|
|
|
52
52
|
* guessing keys. These two are the exception: reaching them required
|
|
53
53
|
* presenting a key whose hash matched, so you already hold it, and what you
|
|
54
54
|
* need to know is that no retry and no scope change will fix this - the key
|
|
55
|
-
* has to be reissued from the application's
|
|
55
|
+
* has to be reissued from the application's Connect client section.
|
|
56
56
|
*
|
|
57
57
|
* Worth alerting on. It is the one failure that will not resolve itself and
|
|
58
58
|
* takes down every call your integration makes.
|
package/dist/types/index.d.ts
CHANGED
|
@@ -13,5 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
export { ConnectError, isConnectError } from "./errors.js";
|
|
15
15
|
export { blockingBlockers, normalizePlanFeatures } from "./helpers.js";
|
|
16
|
+
export { arrayRemove, arrayUnion, deleteField, documentExists, increment, serverTimestamp, storeIndexFor, storeIndexSignature, unchangedSince, } from "./store.js";
|
|
17
|
+
export type { StoreIndexDirection, StoreIndexField } from "./store.js";
|
|
16
18
|
export type { WirePlanFeature } from "./helpers.js";
|
|
17
19
|
export type * from "./types.js";
|
|
@@ -125,7 +125,7 @@ export declare function getConnectSession(request?: Request, options?: {
|
|
|
125
125
|
* A thin wrapper, not a framework of its own - reach for `getConnectSession`
|
|
126
126
|
* plus your own check when "not signed in" isn't "redirect to sign-in"
|
|
127
127
|
* (an API route returning 401, say). Role and entitlement checks stay
|
|
128
|
-
* outside this function on purpose: `session.
|
|
128
|
+
* outside this function on purpose: `session.permissions` and
|
|
129
129
|
* `connect.entitlements.*` are one line each on top of the session this
|
|
130
130
|
* already gives you, and where that line redirects (a plans page, a
|
|
131
131
|
* "forbidden" screen) is a decision only your app can make - see
|
|
@@ -2,6 +2,9 @@ import type { FetchLike } from "./http.js";
|
|
|
2
2
|
import { AccessResource } from "./resources/access.js";
|
|
3
3
|
import { AppsResource } from "./resources/apps.js";
|
|
4
4
|
import { AiResource } from "./resources/ai.js";
|
|
5
|
+
import { DataResource } from "./resources/data.js";
|
|
6
|
+
import { WorkspacesResource } from "./resources/workspaces.js";
|
|
7
|
+
import { KvResource } from "./resources/kv.js";
|
|
5
8
|
import { BillingResource } from "./resources/billing.js";
|
|
6
9
|
import { DriveResource } from "./resources/drive.js";
|
|
7
10
|
import { EntitlementsResource } from "./resources/entitlements.js";
|
|
@@ -11,10 +14,11 @@ import { LogsResource } from "./resources/logs.js";
|
|
|
11
14
|
import { AnalyticsResource } from "./resources/analytics.js";
|
|
12
15
|
import { OtpResource } from "./resources/otp.js";
|
|
13
16
|
import { SessionsResource } from "./resources/sessions.js";
|
|
17
|
+
import { PlatformResource } from "./resources/platform.js";
|
|
14
18
|
export declare const DEFAULT_BASE_URL = "https://connect.cosmoops.com";
|
|
15
19
|
export interface ConnectClientOptions {
|
|
16
20
|
/**
|
|
17
|
-
* The API key plaintext from this application's
|
|
21
|
+
* The API key plaintext from this application's Connect client section, shown once at
|
|
18
22
|
* creation.
|
|
19
23
|
*
|
|
20
24
|
* One credential does three jobs: it is the `Authorization: Bearer` value
|
|
@@ -73,6 +77,10 @@ export declare class ConnectClient {
|
|
|
73
77
|
readonly drive: DriveResource;
|
|
74
78
|
/** RAG chat and structured extraction. */
|
|
75
79
|
readonly ai: AiResource;
|
|
80
|
+
/** Your application's own document store - see `DataResource`. */
|
|
81
|
+
readonly data: DataResource;
|
|
82
|
+
/** Your application's key/value store - see `KvResource`. */
|
|
83
|
+
readonly kv: KvResource;
|
|
76
84
|
/** WhatsApp/SMS phone verification. */
|
|
77
85
|
readonly otp: OtpResource;
|
|
78
86
|
/** Feature events into the Console's audit log, filterable to your application. */
|
|
@@ -83,7 +91,22 @@ export declare class ConnectClient {
|
|
|
83
91
|
readonly sessions: SessionsResource;
|
|
84
92
|
/** Composio-hosted third-party connections (Google Calendar, Slack, ...) a workspace has connected. */
|
|
85
93
|
readonly integrations: IntegrationsResource;
|
|
94
|
+
/** Which workspaces the signed-in user belongs to, switching between them, and the team - see `WorkspacesResource`. */
|
|
95
|
+
readonly workspaces: WorkspacesResource;
|
|
96
|
+
/** The platform's own legal identity and DPDP grievance channel - see `PlatformResource`. */
|
|
97
|
+
readonly platform: PlatformResource;
|
|
98
|
+
/**
|
|
99
|
+
* Relays one `/data/*` or `/kv/*` request verbatim - `createConnectHandler`'s
|
|
100
|
+
* store route and nothing else. See `storePassthrough`.
|
|
101
|
+
* @internal
|
|
102
|
+
*/
|
|
103
|
+
readonly storeRelay: (spec: {
|
|
104
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
105
|
+
path: string;
|
|
106
|
+
json?: unknown;
|
|
107
|
+
headers?: Record<string, string>;
|
|
108
|
+
}) => Promise<Response>;
|
|
86
109
|
constructor(options: ConnectClientOptions);
|
|
87
110
|
}
|
|
88
111
|
/** Kept in step with `package.json` by `sdk.test.ts`. */
|
|
89
|
-
export declare const SDK_VERSION = "0.
|
|
112
|
+
export declare const SDK_VERSION = "0.14.0";
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
2
2
|
export interface RequestSpec {
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* `PUT` and `DELETE` were added for the store resources. Both are idempotent
|
|
5
|
+
* by HTTP's own definition, so both are retried like `GET` - see the retry
|
|
6
|
+
* note on `request`.
|
|
7
|
+
*/
|
|
8
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
4
9
|
/** Relative to the API base, e.g. `/plans`. */
|
|
5
10
|
path: string;
|
|
6
11
|
query?: Record<string, string | number | undefined>;
|
|
@@ -12,7 +17,12 @@ export interface RequestSpec {
|
|
|
12
17
|
headers?: Record<string, string>;
|
|
13
18
|
/** Bearer API key (default), or none - the `/sso/*` endpoints authenticate inside the form body instead. */
|
|
14
19
|
auth?: "bearer" | "none";
|
|
15
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Skip JSON parsing and hand back the raw `Response` - for streaming
|
|
22
|
+
* endpoints.
|
|
23
|
+
*
|
|
24
|
+
* Also stops `timeoutMs` from applying to the *body*: see `request`.
|
|
25
|
+
*/
|
|
16
26
|
raw?: boolean;
|
|
17
27
|
signal?: AbortSignal;
|
|
18
28
|
}
|
|
@@ -44,7 +54,8 @@ export declare function pathSegment(value: string, name: string): string;
|
|
|
44
54
|
* `ConnectError`.
|
|
45
55
|
*
|
|
46
56
|
* **On retries.** Only idempotent requests are retried without a caller
|
|
47
|
-
* opt-in: every `GET`, plus any `POST` carrying an
|
|
57
|
+
* opt-in: every `GET`, `PUT` and `DELETE`, plus any `POST` carrying an
|
|
58
|
+
* `Idempotency-Key` (the
|
|
48
59
|
* resources that mutate - `billing.consumeAddon`, `otp.send` - always set
|
|
49
60
|
* one). A bare `POST` is attempted exactly once, because a 429 or a 504 says
|
|
50
61
|
* nothing about whether the server already did the work.
|
|
@@ -18,11 +18,15 @@ export type { AppsResource } from "./resources/apps.js";
|
|
|
18
18
|
export type { EntitlementsResource } from "./resources/entitlements.js";
|
|
19
19
|
export type { BillingResource } from "./resources/billing.js";
|
|
20
20
|
export type { AiResource } from "./resources/ai.js";
|
|
21
|
+
export type { DataResource } from "./resources/data.js";
|
|
22
|
+
export type { KvResource } from "./resources/kv.js";
|
|
23
|
+
export type { WorkspacesResource } from "./resources/workspaces.js";
|
|
21
24
|
export type { OtpResource } from "./resources/otp.js";
|
|
22
25
|
export type { LogsResource } from "./resources/logs.js";
|
|
23
26
|
export type { AnalyticsResource } from "./resources/analytics.js";
|
|
24
27
|
export type { SessionsResource } from "./resources/sessions.js";
|
|
25
28
|
export type { ExecuteIntegrationActionInput, IntegrationsResource } from "./resources/integrations.js";
|
|
29
|
+
export type { PlatformResource } from "./resources/platform.js";
|
|
26
30
|
/**
|
|
27
31
|
* Webhook verification and a ready-made POST route. Server-only for the
|
|
28
32
|
* obvious reason: the signing secret must never reach a browser bundle.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The header that turns a server-to-server store call into one made *on behalf
|
|
3
|
+
* of* a signed-in user.
|
|
4
|
+
*
|
|
5
|
+
* Connect resolves the token to a user and a workspace itself and checks the
|
|
6
|
+
* collection's declared permission against that member's live roles - so a
|
|
7
|
+
* caller supplying this is asking for a *narrower* check than an application
|
|
8
|
+
* call, never a wider one. An unresolvable token is refused rather than
|
|
9
|
+
* quietly downgraded, precisely because the downgrade would be an escalation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function actingAs(sessionToken: string | undefined): Record<string, string>;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { type TransportOptions } from "../http.js";
|
|
2
2
|
import type { ChatMessage } from "../../types.js";
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* RAG chat and structured extraction against a workspace's data.
|
|
5
|
+
*
|
|
6
|
+
* `asUser` on `chat` behaves as it does on the store resources: pass a
|
|
7
|
+
* signed-in user's `sessionToken` and Connect resolves the workspace from it,
|
|
8
|
+
* ignoring `workspaceId`. Without it you are the application, naming the
|
|
9
|
+
* workspace yourself.
|
|
10
|
+
*/
|
|
4
11
|
export declare class AiResource {
|
|
5
12
|
private readonly transport;
|
|
6
13
|
constructor(transport: TransportOptions);
|
|
@@ -13,6 +20,7 @@ export declare class AiResource {
|
|
|
13
20
|
chat(input: {
|
|
14
21
|
workspaceId: string;
|
|
15
22
|
messages: ChatMessage[];
|
|
23
|
+
asUser?: string;
|
|
16
24
|
}, options?: {
|
|
17
25
|
signal?: AbortSignal;
|
|
18
26
|
}): Promise<Response>;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { type TransportOptions } from "../http.js";
|
|
2
|
+
import type { StoreAggregatePage, StoreAggregation, StoreCommitOperation, StoreCommitResult, StoreDocument, StoreQueryFilter, StoreQueryPage, StoreOrderBy, StoreScanPage } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Your application's own document store - a dedicated Firestore database that
|
|
5
|
+
* only Connect can reach.
|
|
6
|
+
*
|
|
7
|
+
* You hold no Firebase credential and write no security rules. Collections are
|
|
8
|
+
* declared in the Console; an undeclared name is refused rather than created,
|
|
9
|
+
* and `workspaceId` is a path segment rather than a filter, so a query cannot
|
|
10
|
+
* cross tenants.
|
|
11
|
+
*
|
|
12
|
+
* **A query needs an index for its shape, and there are two ways to have one.**
|
|
13
|
+
* Firestore maintains a single-field index automatically, which covers one
|
|
14
|
+
* filter, or an `orderBy` on that same field. Anything wider - two filters, or
|
|
15
|
+
* a filter ordered by a different field - needs a composite index **declared
|
|
16
|
+
* on your application's Store tab**, which Connect then builds in your
|
|
17
|
+
* database. A query with no matching index is refused up front, naming the
|
|
18
|
+
* index to declare, rather than failing later with a Firestore index error
|
|
19
|
+
* pointing at a console you cannot open.
|
|
20
|
+
*
|
|
21
|
+
* **Dates are ISO-8601 strings.** The store writes what you send it, and JSON
|
|
22
|
+
* has no date type, so a `Date` must be sent as `toISOString()`. That is not a
|
|
23
|
+
* compromise: UTC ISO strings sort lexicographically in chronological order,
|
|
24
|
+
* so ordering and range filters on them behave exactly as they would on a
|
|
25
|
+
* timestamp - and Connect's own `_createdAt`/`_updatedAt` come back in the
|
|
26
|
+
* same form.
|
|
27
|
+
*
|
|
28
|
+
* **`workspaceId` is omitted for master data.** A collection declared
|
|
29
|
+
* application-scoped in the Console belongs to no workspace - one copy, owned
|
|
30
|
+
* by you, read by every tenant. Those are written with your API key only,
|
|
31
|
+
* never on behalf of a user: a write permission is something a *workspace*
|
|
32
|
+
* grants, so honouring one on shared data would give one tenant's admin reach
|
|
33
|
+
* over every other tenant's reference data.
|
|
34
|
+
*
|
|
35
|
+
* **`asUser` is how you act on behalf of a signed-in user.** Pass the opaque
|
|
36
|
+
* `sessionToken` you were given at sign-in and Connect resolves the user and
|
|
37
|
+
* their workspace from it - checking the collection's declared permission
|
|
38
|
+
* against what that member actually holds, and **ignoring `workspaceId`
|
|
39
|
+
* entirely**. Without it you are the application itself: your API key's scopes
|
|
40
|
+
* are the only gate, and the per-user permissions do not apply. The bridge
|
|
41
|
+
* (`createConnectHandler`) always passes it, which is what makes the browser
|
|
42
|
+
* path safe.
|
|
43
|
+
*/
|
|
44
|
+
export declare class DataResource {
|
|
45
|
+
private readonly transport;
|
|
46
|
+
constructor(transport: TransportOptions);
|
|
47
|
+
/** Reads one document. Throws `ConnectError` with status 404 when it does not exist. */
|
|
48
|
+
get(input: {
|
|
49
|
+
workspaceId?: string;
|
|
50
|
+
collection: string;
|
|
51
|
+
id: string;
|
|
52
|
+
asUser?: string;
|
|
53
|
+
}): Promise<StoreDocument>;
|
|
54
|
+
/**
|
|
55
|
+
* Lists a collection, one page at a time.
|
|
56
|
+
*
|
|
57
|
+
* `filters` are ANDed. More than one, or one combined with an `orderBy` on a
|
|
58
|
+
* different field, needs a composite index declared on the Store tab - see
|
|
59
|
+
* the class note above.
|
|
60
|
+
*
|
|
61
|
+
* `limit` defaults to 50 and caps at 200. Page by passing the previous
|
|
62
|
+
* page's `nextCursor`; a `null` `nextCursor` is the end of the collection.
|
|
63
|
+
*/
|
|
64
|
+
query(input: {
|
|
65
|
+
workspaceId?: string;
|
|
66
|
+
collection: string;
|
|
67
|
+
filters?: StoreQueryFilter[];
|
|
68
|
+
orderBy?: StoreOrderBy;
|
|
69
|
+
limit?: number;
|
|
70
|
+
cursor?: string | null;
|
|
71
|
+
asUser?: string;
|
|
72
|
+
}): Promise<StoreQueryPage>;
|
|
73
|
+
/**
|
|
74
|
+
* Counts, sums and averages a filtered collection - **in Firestore**, not by
|
|
75
|
+
* reading the rows back and adding them up.
|
|
76
|
+
*
|
|
77
|
+
* That distinction is the whole point. An aggregation is billed by the index
|
|
78
|
+
* entries it scans rather than by the documents it would have returned, so a
|
|
79
|
+
* dashboard tile over ten thousand rows costs a handful of reads and stays
|
|
80
|
+
* flat as the collection grows. Paging the rows into your own process to sum
|
|
81
|
+
* them is an unbounded read, and it is what every integration does when
|
|
82
|
+
* there is no aggregate call to reach for.
|
|
83
|
+
*
|
|
84
|
+
* ```ts
|
|
85
|
+
* const { values } = await connect.data.aggregate({
|
|
86
|
+
* workspaceId,
|
|
87
|
+
* collection: "deals",
|
|
88
|
+
* filters: [{ field: "outcome", op: "==", value: "won" }],
|
|
89
|
+
* aggregations: [
|
|
90
|
+
* { op: "count", alias: "count" },
|
|
91
|
+
* { op: "sum", field: "value", alias: "total" },
|
|
92
|
+
* ],
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* A `sum` or `avg` over nothing answers `null` rather than `0`, because
|
|
97
|
+
* "nothing matched" and "the total is zero" are different facts.
|
|
98
|
+
*
|
|
99
|
+
* The index it needs is the one its **filters** need plus the aggregated
|
|
100
|
+
* field - Firestore reads a sum out of the index rather than out of the
|
|
101
|
+
* documents.
|
|
102
|
+
*
|
|
103
|
+
* There is no `orderBy`, `limit` or `cursor`: the aggregate of an ordered
|
|
104
|
+
* page is the aggregate of the whole filtered set.
|
|
105
|
+
*/
|
|
106
|
+
aggregate(input: {
|
|
107
|
+
workspaceId?: string;
|
|
108
|
+
collection: string;
|
|
109
|
+
aggregations: StoreAggregation[];
|
|
110
|
+
filters?: StoreQueryFilter[];
|
|
111
|
+
asUser?: string;
|
|
112
|
+
}): Promise<StoreAggregatePage>;
|
|
113
|
+
/**
|
|
114
|
+
* Reads one collection across **every workspace at once** - your own
|
|
115
|
+
* back-office view of your whole customer base. Each row carries the
|
|
116
|
+
* `workspaceId` it came from.
|
|
117
|
+
*
|
|
118
|
+
* Needs the `data:read:all` scope, and the collection must be marked
|
|
119
|
+
* cross-workspace in the Console. There is deliberately **no `asUser`**: a
|
|
120
|
+
* scan is never available on behalf of a signed-in user, because a workspace
|
|
121
|
+
* admin is an admin of their own workspace and not of your other customers.
|
|
122
|
+
*
|
|
123
|
+
* Filtering and ordering follow the same index rules as `query`, and
|
|
124
|
+
* additionally need collection-group scope. Connect creates those from the
|
|
125
|
+
* declaration - the single-field ones when you mark a field queryable, and a
|
|
126
|
+
* group-scoped copy of every composite index the collection declares. A scan
|
|
127
|
+
* issued in the minutes after that declaration may fail while the index
|
|
128
|
+
* builds.
|
|
129
|
+
*/
|
|
130
|
+
scan(input: {
|
|
131
|
+
collection: string;
|
|
132
|
+
filters?: StoreQueryFilter[];
|
|
133
|
+
orderBy?: StoreOrderBy;
|
|
134
|
+
limit?: number;
|
|
135
|
+
cursor?: string | null;
|
|
136
|
+
}): Promise<StoreScanPage>;
|
|
137
|
+
/**
|
|
138
|
+
* Creates a document. Pass `id` to choose it, or omit it and one is
|
|
139
|
+
* allocated. An `id` that already exists throws with status 409 - use
|
|
140
|
+
* `replace` to overwrite deliberately.
|
|
141
|
+
*/
|
|
142
|
+
create(input: {
|
|
143
|
+
workspaceId?: string;
|
|
144
|
+
collection: string;
|
|
145
|
+
data: Record<string, unknown>;
|
|
146
|
+
id?: string;
|
|
147
|
+
asUser?: string;
|
|
148
|
+
}): Promise<StoreDocument>;
|
|
149
|
+
/** Replaces every field, creating the document if it does not exist. `_createdAt`/`_createdBy` survive. */
|
|
150
|
+
replace(input: {
|
|
151
|
+
workspaceId?: string;
|
|
152
|
+
collection: string;
|
|
153
|
+
id: string;
|
|
154
|
+
data: Record<string, unknown>;
|
|
155
|
+
asUser?: string;
|
|
156
|
+
}): Promise<StoreDocument>;
|
|
157
|
+
/** Merges top-level fields into an existing document. Throws with status 404 if it does not exist. */
|
|
158
|
+
update(input: {
|
|
159
|
+
workspaceId?: string;
|
|
160
|
+
collection: string;
|
|
161
|
+
id: string;
|
|
162
|
+
data: Record<string, unknown>;
|
|
163
|
+
asUser?: string;
|
|
164
|
+
}): Promise<StoreDocument>;
|
|
165
|
+
/** Idempotent - deleting a document that is not there succeeds. */
|
|
166
|
+
delete(input: {
|
|
167
|
+
workspaceId?: string;
|
|
168
|
+
collection: string;
|
|
169
|
+
id: string;
|
|
170
|
+
asUser?: string;
|
|
171
|
+
}): Promise<void>;
|
|
172
|
+
/**
|
|
173
|
+
* Applies a set of writes atomically, across as many of your collections as
|
|
174
|
+
* they name. All of them land, or none.
|
|
175
|
+
*
|
|
176
|
+
* This is the store's answer to a database transaction, and the shape is
|
|
177
|
+
* deliberate: **you never hold one**. A transaction handle passed across an
|
|
178
|
+
* HTTP boundary is a server-side lock whose duration your network controls,
|
|
179
|
+
* with Firestore's sixty-second ceiling and lock contention as the failure
|
|
180
|
+
* mode. Instead you read, decide, and commit *conditional on nothing having
|
|
181
|
+
* moved* - Connect runs the whole set as one short transaction on its side.
|
|
182
|
+
*
|
|
183
|
+
* ```ts
|
|
184
|
+
* await connect.data.commit({
|
|
185
|
+
* workspaceId,
|
|
186
|
+
* operations: [
|
|
187
|
+
* { op: "create", collection: "ledger", id, data: entry },
|
|
188
|
+
* {
|
|
189
|
+
* op: "merge",
|
|
190
|
+
* collection: "funds",
|
|
191
|
+
* id: entry.fundId,
|
|
192
|
+
* data: { balancePaise: increment(entry.amountPaise) },
|
|
193
|
+
* },
|
|
194
|
+
* ],
|
|
195
|
+
* });
|
|
196
|
+
* ```
|
|
197
|
+
*
|
|
198
|
+
* A precondition that no longer holds throws `ConnectError` with status 409
|
|
199
|
+
* and **writes nothing** - see `transaction`, which re-reads and retries for
|
|
200
|
+
* you. Note that the example above needs no precondition at all: an
|
|
201
|
+
* `increment` is commutative, so concurrent commits both land correctly.
|
|
202
|
+
*
|
|
203
|
+
* Returns the id each operation wrote, in order - which is how you learn the
|
|
204
|
+
* id a `create` without one was given.
|
|
205
|
+
*/
|
|
206
|
+
commit(input: {
|
|
207
|
+
workspaceId?: string;
|
|
208
|
+
operations: StoreCommitOperation[];
|
|
209
|
+
asUser?: string;
|
|
210
|
+
}): Promise<StoreCommitResult>;
|
|
211
|
+
/**
|
|
212
|
+
* Read, decide, commit - retried when the world moved underneath you.
|
|
213
|
+
*
|
|
214
|
+
* The optimistic-concurrency loop, written once. `build` reads whatever it
|
|
215
|
+
* needs and returns the operations to apply; if any precondition among them
|
|
216
|
+
* has gone stale by the time Connect looks, the commit is rejected whole and
|
|
217
|
+
* `build` runs again against fresh reads.
|
|
218
|
+
*
|
|
219
|
+
* ```ts
|
|
220
|
+
* await connect.data.transaction(async () => {
|
|
221
|
+
* const fund = await connect.data.get({ workspaceId, collection: "funds", id });
|
|
222
|
+
* if (!fund.data.active) throw new Error("That fund is closed.");
|
|
223
|
+
* return [
|
|
224
|
+
* {
|
|
225
|
+
* op: "merge",
|
|
226
|
+
* collection: "funds",
|
|
227
|
+
* id,
|
|
228
|
+
* data: { balancePaise: increment(amount) },
|
|
229
|
+
* precondition: unchangedSince(fund),
|
|
230
|
+
* },
|
|
231
|
+
* ];
|
|
232
|
+
* });
|
|
233
|
+
* ```
|
|
234
|
+
*
|
|
235
|
+
* **Only a 409 is retried.** A 403 or a validation error means the operation
|
|
236
|
+
* was wrong rather than late, and retrying it would turn one clear failure
|
|
237
|
+
* into `attempts` identical ones. An error thrown by `build` itself - the
|
|
238
|
+
* closed-fund check above - is not retried either: it is a decision, not a
|
|
239
|
+
* collision.
|
|
240
|
+
*
|
|
241
|
+
* `build` must be free of side effects outside the returned operations,
|
|
242
|
+
* because it can run more than once. That is the price of not holding a
|
|
243
|
+
* lock, and it is the same contract Firestore's own `runTransaction` states
|
|
244
|
+
* for the same reason.
|
|
245
|
+
*/
|
|
246
|
+
transaction(build: () => Promise<StoreCommitOperation[]>, options?: {
|
|
247
|
+
workspaceId?: string;
|
|
248
|
+
asUser?: string;
|
|
249
|
+
attempts?: number;
|
|
250
|
+
}): Promise<StoreCommitResult>;
|
|
251
|
+
private write;
|
|
252
|
+
}
|
|
253
|
+
export declare function storePassthrough(transport: TransportOptions, spec: {
|
|
254
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
255
|
+
path: string;
|
|
256
|
+
json?: unknown;
|
|
257
|
+
headers?: Record<string, string>;
|
|
258
|
+
}): Promise<Response>;
|