@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,5 +1,5 @@
|
|
|
1
1
|
import { type TransportOptions } from "../http.js";
|
|
2
|
-
import type { ReadinessResponse, SubscriptionResponse } from "../../types.js";
|
|
2
|
+
import type { ApplicationSubscriber, ReadinessResponse, SubscribersResponse, SubscriptionResponse } from "../../types.js";
|
|
3
3
|
/**
|
|
4
4
|
* The two checks worth making on every request: may this workspace be here at
|
|
5
5
|
* all, and what is it paying for.
|
|
@@ -28,4 +28,36 @@ export declare class EntitlementsResource {
|
|
|
28
28
|
* should not need a try/catch around it.
|
|
29
29
|
*/
|
|
30
30
|
hasFeature(workspaceId: string, feature: string): Promise<boolean>;
|
|
31
|
+
/**
|
|
32
|
+
* One page of the workspaces subscribed to your application, newest first.
|
|
33
|
+
*
|
|
34
|
+
* The inverse of `getSubscription`, which asks about one workspace you
|
|
35
|
+
* already know. This asks who your subscribers *are* - what a partner
|
|
36
|
+
* dashboard, an MRR total or a churn report is built on.
|
|
37
|
+
*
|
|
38
|
+
* Rate-limited far more tightly than the per-workspace read (10/min per
|
|
39
|
+
* key, against 60): it walks your whole subscriber base and is a reporting
|
|
40
|
+
* call, not a per-request gate. Use `getSubscription` in a hot path.
|
|
41
|
+
*
|
|
42
|
+
* Your application is resolved from the API key, so there is no parameter
|
|
43
|
+
* for it and no way to ask about anyone else's.
|
|
44
|
+
*/
|
|
45
|
+
listSubscribers(options?: {
|
|
46
|
+
status?: ApplicationSubscriber["status"];
|
|
47
|
+
/** Cursor from a previous page's `nextBefore`. */
|
|
48
|
+
before?: string;
|
|
49
|
+
/** 1..100, default 25. */
|
|
50
|
+
limit?: number;
|
|
51
|
+
}): Promise<SubscribersResponse>;
|
|
52
|
+
/**
|
|
53
|
+
* Every subscriber, paged through for you.
|
|
54
|
+
*
|
|
55
|
+
* An async generator rather than an array: a large subscriber base is
|
|
56
|
+
* exactly where an accidental full materialisation hurts, and `for await`
|
|
57
|
+
* reads the same as a loop over one page.
|
|
58
|
+
*/
|
|
59
|
+
iterateSubscribers(options?: {
|
|
60
|
+
status?: ApplicationSubscriber["status"];
|
|
61
|
+
pageSize?: number;
|
|
62
|
+
}): AsyncGenerator<ApplicationSubscriber>;
|
|
31
63
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type TransportOptions } from "../http.js";
|
|
2
|
+
import type { KvEntry, KvPage } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Your application's key/value store - small values addressed by namespace and
|
|
5
|
+
* key, per workspace.
|
|
6
|
+
*
|
|
7
|
+
* Use it for what a document store is bad at: a feature flag, a cached
|
|
8
|
+
* computation, a counter, a draft nobody needs to query. Anything you want to
|
|
9
|
+
* *find* rather than *fetch* belongs in `data`.
|
|
10
|
+
*
|
|
11
|
+
* Namespaces are declared in the Console exactly like collections. Keys are
|
|
12
|
+
* `[A-Za-z0-9_-]` up to 64 characters, and values are JSON up to 128 KB.
|
|
13
|
+
*
|
|
14
|
+
* `asUser` behaves exactly as it does on `DataResource` - pass a signed-in
|
|
15
|
+
* user's `sessionToken` and Connect derives the user and workspace from it,
|
|
16
|
+
* checking the namespace's declared permission against their live roles.
|
|
17
|
+
*/
|
|
18
|
+
export declare class KvResource {
|
|
19
|
+
private readonly transport;
|
|
20
|
+
constructor(transport: TransportOptions);
|
|
21
|
+
/**
|
|
22
|
+
* Reads one key. Throws `ConnectError` with status 404 when the key is
|
|
23
|
+
* absent **or expired** - expiry is evaluated on read, so there is no window
|
|
24
|
+
* where a stale value is still served.
|
|
25
|
+
*/
|
|
26
|
+
get(input: {
|
|
27
|
+
workspaceId?: string;
|
|
28
|
+
namespace: string;
|
|
29
|
+
key: string;
|
|
30
|
+
asUser?: string;
|
|
31
|
+
}): Promise<KvEntry>;
|
|
32
|
+
/**
|
|
33
|
+
* Pages a namespace in key order.
|
|
34
|
+
*
|
|
35
|
+
* Expired entries are filtered out after paging, so a page can come back
|
|
36
|
+
* shorter than `limit` while still having a `nextCursor` - treat
|
|
37
|
+
* `nextCursor` as the only signal that more keys exist, never an empty page.
|
|
38
|
+
*/
|
|
39
|
+
list(input: {
|
|
40
|
+
workspaceId?: string;
|
|
41
|
+
namespace: string;
|
|
42
|
+
limit?: number;
|
|
43
|
+
cursor?: string | null;
|
|
44
|
+
asUser?: string;
|
|
45
|
+
}): Promise<KvPage>;
|
|
46
|
+
/** Sets a value, replacing whatever was there. `ttlSeconds` expires it; omit for no expiry. */
|
|
47
|
+
set(input: {
|
|
48
|
+
workspaceId?: string;
|
|
49
|
+
namespace: string;
|
|
50
|
+
key: string;
|
|
51
|
+
value: unknown;
|
|
52
|
+
ttlSeconds?: number;
|
|
53
|
+
asUser?: string;
|
|
54
|
+
}): Promise<KvEntry>;
|
|
55
|
+
/** Idempotent - deleting an absent key succeeds. */
|
|
56
|
+
delete(input: {
|
|
57
|
+
workspaceId?: string;
|
|
58
|
+
namespace: string;
|
|
59
|
+
key: string;
|
|
60
|
+
asUser?: string;
|
|
61
|
+
}): Promise<void>;
|
|
62
|
+
private path;
|
|
63
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type TransportOptions } from "../http.js";
|
|
2
|
+
import type { CompanyProfile } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Facts about the platform itself, rather than about a workspace or a user.
|
|
5
|
+
*
|
|
6
|
+
* One method today, and the resource exists anyway rather than hanging
|
|
7
|
+
* `getCompanyProfile` off `identity` or `workspaces`: neither of those is
|
|
8
|
+
* what it is about. This answers "who operates the thing my application runs
|
|
9
|
+
* on", which is a different subject from every other resource here, and a
|
|
10
|
+
* misfiled method is harder to find than an obvious one-method namespace.
|
|
11
|
+
*/
|
|
12
|
+
export declare class PlatformResource {
|
|
13
|
+
private readonly transport;
|
|
14
|
+
constructor(transport: TransportOptions);
|
|
15
|
+
/**
|
|
16
|
+
* The operating entity's legal identity and its DPDP grievance channel.
|
|
17
|
+
*
|
|
18
|
+
* Takes no `workspaceId` and takes no `asUser` - the answer is the same for
|
|
19
|
+
* every tenant and every caller, because it is a fact about the platform.
|
|
20
|
+
*
|
|
21
|
+
* Returns the inner `companyProfile` rather than the envelope, matching
|
|
22
|
+
* `apps.list()` and `billing.listPlans()`: the wrapper is a wire detail, and
|
|
23
|
+
* every caller would destructure it on the next line.
|
|
24
|
+
*
|
|
25
|
+
* **Do not copy the result into your own configuration.** Cache it if you
|
|
26
|
+
* render it on a hot path - Connect already sends
|
|
27
|
+
* `s-maxage=3600, stale-while-revalidate=86400` - but the reason this is an
|
|
28
|
+
* endpoint at all is that a grievance officer copied into `.env` goes stale
|
|
29
|
+
* without anyone finding out.
|
|
30
|
+
*/
|
|
31
|
+
getCompanyProfile(): Promise<CompanyProfile>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type TransportOptions } from "../http.js";
|
|
2
|
+
import type { ConnectWorkspaceMember, UserWorkspace, WorkspaceSwitchResult } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Which workspaces the signed-in user belongs to, moving between them, and who
|
|
5
|
+
* else is on the team.
|
|
6
|
+
*
|
|
7
|
+
* **Every call here needs `asUser`** - the signed-in user's opaque
|
|
8
|
+
* `sessionToken`. There is no application-wide form of any of these: they take
|
|
9
|
+
* no `userId` and no `workspaceId`, and resolve both from the token. That is
|
|
10
|
+
* what makes the whole module safe to reach from a browser through
|
|
11
|
+
* `createConnectHandler`, and it is why a partner cannot enumerate another
|
|
12
|
+
* tenant's team with their own API key.
|
|
13
|
+
*/
|
|
14
|
+
export declare class WorkspacesResource {
|
|
15
|
+
private readonly transport;
|
|
16
|
+
constructor(transport: TransportOptions);
|
|
17
|
+
/**
|
|
18
|
+
* The workspaces this user could switch to.
|
|
19
|
+
*
|
|
20
|
+
* Rows carry `inAudience` and `subscribed` so a switcher can show a
|
|
21
|
+
* workspace it cannot select, with the reason. Hiding it instead reads as
|
|
22
|
+
* data loss to the person who owns it.
|
|
23
|
+
*/
|
|
24
|
+
list(options: {
|
|
25
|
+
asUser: string;
|
|
26
|
+
}): Promise<UserWorkspace[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Moves this session to another workspace, returning a **new session
|
|
29
|
+
* token**. The one you passed is revoked.
|
|
30
|
+
*
|
|
31
|
+
* Persist the result before navigating - dropping it signs the user out,
|
|
32
|
+
* because the old token no longer works.
|
|
33
|
+
*
|
|
34
|
+
* Throws with status 404 when the workspace does not exist *or* the user is
|
|
35
|
+
* not a member (deliberately indistinguishable), and 403 when it is outside
|
|
36
|
+
* your audience, requires an MFA factor they have not enrolled, or is the
|
|
37
|
+
* workspace they are already on.
|
|
38
|
+
*/
|
|
39
|
+
switch(input: {
|
|
40
|
+
workspaceId: string;
|
|
41
|
+
}, options: {
|
|
42
|
+
asUser: string;
|
|
43
|
+
}): Promise<WorkspaceSwitchResult>;
|
|
44
|
+
/**
|
|
45
|
+
* The team of the workspace this session is on.
|
|
46
|
+
*
|
|
47
|
+
* Members carry permissions already resolved for *your* application, not raw
|
|
48
|
+
* Connect roles - so you never reimplement Connect's role resolution, and
|
|
49
|
+
* you are told nothing about the customer's Connect account beyond what your
|
|
50
|
+
* application needs.
|
|
51
|
+
*/
|
|
52
|
+
members(options: {
|
|
53
|
+
asUser: string;
|
|
54
|
+
}): Promise<ConnectWorkspaceMember[]>;
|
|
55
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { StoreDocument, StoreFieldTransform, StoreOrderBy, StorePrecondition, StoreQueryFilter } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Building blocks for `data.commit` - the transform sentinels, and the two
|
|
4
|
+
* ways to say "only if nothing has moved".
|
|
5
|
+
*
|
|
6
|
+
* Isomorphic and dependency-free, so a Server Component and a client component
|
|
7
|
+
* building the same write use the same constructors. They are functions rather
|
|
8
|
+
* than object literals you write by hand because the sentinel shape is an
|
|
9
|
+
* encoding, not an API: `{ __transform: "increment", by: 1 }` is what goes over
|
|
10
|
+
* the wire, and nothing outside this file should have to know that.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Add to a number, atomically.
|
|
14
|
+
*
|
|
15
|
+
* **The one operation you genuinely cannot do yourself.** Increments are
|
|
16
|
+
* commutative, so two concurrent `increment(500)` calls both land - where
|
|
17
|
+
* read-add-write from your own process loses one of them however carefully it
|
|
18
|
+
* retries, because the read and the write are two round trips with a gap in
|
|
19
|
+
* between. Use this for balances, counters and tallies, and reach for a
|
|
20
|
+
* precondition only when the new value depends on the old one in a way
|
|
21
|
+
* addition cannot express.
|
|
22
|
+
*
|
|
23
|
+
* Negative to subtract; there is no separate `decrement`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function increment(by: number): StoreFieldTransform;
|
|
26
|
+
/** Connect's own write time, rather than a clock reading from your process. */
|
|
27
|
+
export declare function serverTimestamp(): StoreFieldTransform;
|
|
28
|
+
/** Adds the values not already in the array. Order is not preserved. */
|
|
29
|
+
export declare function arrayUnion(...values: unknown[]): StoreFieldTransform;
|
|
30
|
+
/** Removes every occurrence of each value. */
|
|
31
|
+
export declare function arrayRemove(...values: unknown[]): StoreFieldTransform;
|
|
32
|
+
/**
|
|
33
|
+
* Removes the field entirely.
|
|
34
|
+
*
|
|
35
|
+
* `merge` only - a `replace` already drops every field it does not list, so
|
|
36
|
+
* asking it to delete one is a contradiction rather than a narrowing.
|
|
37
|
+
*/
|
|
38
|
+
export declare function deleteField(): StoreFieldTransform;
|
|
39
|
+
/**
|
|
40
|
+
* "Only if this document has not changed since I read it."
|
|
41
|
+
*
|
|
42
|
+
* Pass the document a read returned, and the precondition is built from its
|
|
43
|
+
* `_updateTime`. Taking the document rather than the timestamp is deliberate:
|
|
44
|
+
* a caller who has to reach for `doc.data._updateTime` themselves is one typo
|
|
45
|
+
* away from a precondition that silently does nothing.
|
|
46
|
+
*
|
|
47
|
+
* Throws rather than degrading when the document carries no `_updateTime` -
|
|
48
|
+
* that only happens for a document you built yourself rather than read, and a
|
|
49
|
+
* precondition that quietly became "no precondition" is worse than a crash at
|
|
50
|
+
* the call site.
|
|
51
|
+
*/
|
|
52
|
+
export declare function unchangedSince(document: StoreDocument): StorePrecondition;
|
|
53
|
+
/** "Only if this document exists" / "only if it does not." */
|
|
54
|
+
export declare function documentExists(exists?: boolean): StorePrecondition;
|
|
55
|
+
/** How one field sits in a composite index. `array-contains` is a position, not an order. */
|
|
56
|
+
export type StoreIndexDirection = "asc" | "desc" | "array-contains";
|
|
57
|
+
export interface StoreIndexField {
|
|
58
|
+
field: string;
|
|
59
|
+
direction: StoreIndexDirection;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The composite index a query shape needs, or `null` when Firestore's
|
|
63
|
+
* automatic single-field indexes already serve it.
|
|
64
|
+
*
|
|
65
|
+
* Use it to generate your Store tab declarations from the queries your code
|
|
66
|
+
* actually makes, rather than transcribing them by hand and discovering the
|
|
67
|
+
* gap in production:
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* const needed = MY_QUERY_SHAPES.map(storeIndexFor).filter(Boolean);
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* **Field order is Firestore's, not yours.** Equality fields first (sorted, so
|
|
74
|
+
* the order you passed them in cannot produce two different declarations for
|
|
75
|
+
* one query), then the `array-contains` field, then the field the query orders
|
|
76
|
+
* by. Declaring the same shape twice in two orders builds two indexes, one of
|
|
77
|
+
* which is dead weight on every document write.
|
|
78
|
+
*
|
|
79
|
+
* Connect runs the same derivation server-side and is the authority: a query
|
|
80
|
+
* with no matching declared index is refused with the index it needs spelled
|
|
81
|
+
* out, so a disagreement here surfaces on the first call rather than silently.
|
|
82
|
+
*
|
|
83
|
+
* Throws for a query Firestore cannot serve at all - two `array-contains`
|
|
84
|
+
* filters, ranges over two fields, or a range ordered by a different field.
|
|
85
|
+
*/
|
|
86
|
+
export declare function storeIndexFor(query: {
|
|
87
|
+
filters?: readonly StoreQueryFilter[];
|
|
88
|
+
orderBy?: StoreOrderBy | null;
|
|
89
|
+
}): StoreIndexField[] | null;
|
|
90
|
+
/**
|
|
91
|
+
* An index as one comparable string - `"status:asc,createdAt:desc"`.
|
|
92
|
+
*
|
|
93
|
+
* Deduplicate a generated list on this before declaring it: a dozen query
|
|
94
|
+
* shapes across a screen usually collapse to two or three distinct indexes.
|
|
95
|
+
*/
|
|
96
|
+
export declare function storeIndexSignature(fields: readonly StoreIndexField[]): string;
|