@segmentstream/app 0.0.0-stage → 0.38.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.
Files changed (125) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +2 -0
  3. package/README.md +1236 -2
  4. package/dist/agent.d.ts +56 -0
  5. package/dist/agent.js +203 -0
  6. package/dist/app.d.ts +82 -0
  7. package/dist/app.js +434 -0
  8. package/dist/browser-auth-capability.d.ts +2 -0
  9. package/dist/browser-auth-capability.js +2 -0
  10. package/dist/browser-revision.d.ts +19 -0
  11. package/dist/browser-revision.js +140 -0
  12. package/dist/channel-protocol.d.ts +16 -0
  13. package/dist/channel-protocol.js +17 -0
  14. package/dist/channel-session.d.ts +22 -0
  15. package/dist/channel-session.js +89 -0
  16. package/dist/config.d.ts +53 -0
  17. package/dist/config.js +112 -0
  18. package/dist/context.d.ts +10 -0
  19. package/dist/context.js +1 -0
  20. package/dist/cookies.d.ts +56 -0
  21. package/dist/cookies.js +131 -0
  22. package/dist/data.d.ts +233 -0
  23. package/dist/data.js +206 -0
  24. package/dist/decision-pages.d.ts +14 -0
  25. package/dist/decision-pages.js +87 -0
  26. package/dist/deployment.d.ts +30 -0
  27. package/dist/deployment.js +72 -0
  28. package/dist/errors.d.ts +60 -0
  29. package/dist/errors.js +123 -0
  30. package/dist/federation.d.ts +24 -0
  31. package/dist/federation.js +613 -0
  32. package/dist/groups.d.ts +95 -0
  33. package/dist/groups.js +280 -0
  34. package/dist/handlers.d.ts +10 -0
  35. package/dist/handlers.js +161 -0
  36. package/dist/index.d.ts +46 -0
  37. package/dist/index.js +29 -0
  38. package/dist/jobs.d.ts +49 -0
  39. package/dist/jobs.js +40 -0
  40. package/dist/legacy.d.ts +77 -0
  41. package/dist/legacy.js +57 -0
  42. package/dist/logo.d.ts +1 -0
  43. package/dist/logo.js +25 -0
  44. package/dist/me.d.ts +42 -0
  45. package/dist/me.js +54 -0
  46. package/dist/navigation/build.d.ts +68 -0
  47. package/dist/navigation/build.js +290 -0
  48. package/dist/navigation/cli.d.ts +19 -0
  49. package/dist/navigation/cli.js +37 -0
  50. package/dist/navigation/generate.d.ts +43 -0
  51. package/dist/navigation/generate.js +138 -0
  52. package/dist/navigation/next.d.ts +10 -0
  53. package/dist/navigation/next.js +18 -0
  54. package/dist/navigation-protocol.d.ts +55 -0
  55. package/dist/navigation-protocol.js +298 -0
  56. package/dist/neon.d.ts +101 -0
  57. package/dist/neon.js +539 -0
  58. package/dist/oauth-completion.d.ts +6 -0
  59. package/dist/oauth-completion.js +106 -0
  60. package/dist/oauth.d.ts +59 -0
  61. package/dist/oauth.js +129 -0
  62. package/dist/ontology-names.d.ts +10 -0
  63. package/dist/ontology-names.js +38 -0
  64. package/dist/ontology-transport.d.ts +34 -0
  65. package/dist/ontology-transport.js +130 -0
  66. package/dist/ontology-wire.d.ts +66 -0
  67. package/dist/ontology-wire.js +355 -0
  68. package/dist/ontology.d.ts +381 -0
  69. package/dist/ontology.js +367 -0
  70. package/dist/pages.d.ts +6 -0
  71. package/dist/pages.js +6 -0
  72. package/dist/parameters.d.ts +55 -0
  73. package/dist/parameters.js +118 -0
  74. package/dist/permissions.d.ts +19 -0
  75. package/dist/permissions.js +55 -0
  76. package/dist/pkce.d.ts +8 -0
  77. package/dist/pkce.js +40 -0
  78. package/dist/proxy.d.ts +25 -0
  79. package/dist/proxy.js +135 -0
  80. package/dist/request-timing.d.ts +6 -0
  81. package/dist/request-timing.js +53 -0
  82. package/dist/return-to.d.ts +2 -0
  83. package/dist/return-to.js +24 -0
  84. package/dist/server.d.ts +11 -0
  85. package/dist/server.js +80 -0
  86. package/dist/sessions.d.ts +27 -0
  87. package/dist/sessions.js +72 -0
  88. package/dist/sign-in.d.ts +37 -0
  89. package/dist/sign-in.js +95 -0
  90. package/dist/storage.d.ts +79 -0
  91. package/dist/storage.js +180 -0
  92. package/dist/telegram-launch.d.ts +7 -0
  93. package/dist/telegram-launch.js +134 -0
  94. package/dist/telegram.d.ts +2 -0
  95. package/dist/telegram.js +6 -0
  96. package/dist/tokens.d.ts +51 -0
  97. package/dist/tokens.js +70 -0
  98. package/dist/ui/agent-connect.d.ts +18 -0
  99. package/dist/ui/agent-connect.js +23 -0
  100. package/dist/ui/components.d.ts +27 -0
  101. package/dist/ui/components.js +71 -0
  102. package/dist/ui/hooks.d.ts +19 -0
  103. package/dist/ui/hooks.js +56 -0
  104. package/dist/ui/index.d.ts +22 -0
  105. package/dist/ui/index.js +15 -0
  106. package/dist/ui/navigation.d.ts +5 -0
  107. package/dist/ui/navigation.js +8 -0
  108. package/dist/ui/segmentstream-logo.d.ts +2 -0
  109. package/dist/ui/segmentstream-logo.js +7 -0
  110. package/dist/ui/sign-in-check.d.ts +14 -0
  111. package/dist/ui/sign-in-check.js +41 -0
  112. package/dist/ui/sign-in.d.ts +17 -0
  113. package/dist/ui/sign-in.js +65 -0
  114. package/dist/ui/store.d.ts +80 -0
  115. package/dist/ui/store.js +280 -0
  116. package/dist/ui/styles.css +249 -0
  117. package/dist/ui/telegram-sign-in.d.ts +16 -0
  118. package/dist/ui/telegram-sign-in.js +21 -0
  119. package/dist/ui/use-browser-sign-in.d.ts +52 -0
  120. package/dist/ui/use-browser-sign-in.js +169 -0
  121. package/dist/ui/use-channel-sign-in.d.ts +10 -0
  122. package/dist/ui/use-channel-sign-in.js +118 -0
  123. package/dist/ui/use-sign-in.d.ts +109 -0
  124. package/dist/ui/use-sign-in.js +304 -0
  125. package/package.json +95 -4
@@ -0,0 +1,298 @@
1
+ // Generated from packages/ontology-sdk/src/navigation-catalog.ts; do not edit.
2
+ import { createHash } from "node:crypto";
3
+ export const NAVIGATION_CATALOG_LIMITS = Object.freeze({
4
+ pages: 1_000,
5
+ bytes: 1024 * 1024,
6
+ title: 120,
7
+ description: 2_000,
8
+ hint: 512,
9
+ associations: 32,
10
+ hints: 32,
11
+ responseBytes: 32 * 1024,
12
+ });
13
+ function routeShape(path, source) {
14
+ if (!path.startsWith("/")) {
15
+ return undefined;
16
+ }
17
+ const result = [];
18
+ for (const segment of path.split("/").filter(Boolean)) {
19
+ const parameter = source
20
+ ? /^:[A-Za-z0-9_]+([?*+]?)$/u.exec(segment)
21
+ : /^(?:\[\[\.\.\.[^\[\]]+\]\]|\[\.\.\.[^\[\]]+\]|\[[^\[\]]+\])$/u.exec(segment);
22
+ if (parameter) {
23
+ result.push({
24
+ literal: undefined,
25
+ optional: source ? ["?", "*"].includes(parameter[1]) : segment.startsWith("[["),
26
+ repeat: source ? ["*", "+"].includes(parameter[1]) : segment.includes("..."),
27
+ });
28
+ }
29
+ else if (/[:()*+?{}\\\[\]%]/u.test(segment)) {
30
+ return undefined;
31
+ }
32
+ else {
33
+ result.push({ literal: segment.toLowerCase(), optional: false, repeat: false });
34
+ }
35
+ }
36
+ return result;
37
+ }
38
+ /**
39
+ * Whether a generated page and a routing source can share a path. Compare complete segment
40
+ * shapes for ordinary parameters, optional parameters and catch-alls; custom regex sources
41
+ * remain conservative when their static prefixes cannot prove disjointness.
42
+ */
43
+ export function navigationRoutesMayOverlap(route, source) {
44
+ const page = routeShape(route, false);
45
+ const rule = routeShape(source, true);
46
+ if (page === undefined || rule === undefined) {
47
+ const pagePrefix = route.split("[")[0].toLowerCase();
48
+ const rulePrefix = source.split(/[:(*?+{\\]/u)[0].toLowerCase();
49
+ return (pagePrefix.includes("%") ||
50
+ rulePrefix.includes("%") ||
51
+ pagePrefix.startsWith(rulePrefix) ||
52
+ rulePrefix.startsWith(pagePrefix));
53
+ }
54
+ const pending = [[0, 0]];
55
+ const visited = new Set();
56
+ while (pending.length > 0) {
57
+ const [left, right] = pending.pop();
58
+ const key = `${left}:${right}`;
59
+ if (visited.has(key)) {
60
+ continue;
61
+ }
62
+ visited.add(key);
63
+ if (left === page.length && right === rule.length) {
64
+ return true;
65
+ }
66
+ const a = page[left];
67
+ const b = rule[right];
68
+ if (a?.optional) {
69
+ pending.push([left + 1, right]);
70
+ }
71
+ if (b?.optional) {
72
+ pending.push([left, right + 1]);
73
+ }
74
+ if (a && b && (a.literal === undefined || b.literal === undefined || a.literal === b.literal)) {
75
+ pending.push([left + 1, right + 1]);
76
+ if (a.repeat) {
77
+ pending.push([left, right + 1]);
78
+ }
79
+ if (b.repeat) {
80
+ pending.push([left + 1, right]);
81
+ }
82
+ }
83
+ }
84
+ return false;
85
+ }
86
+ export class NavigationCatalogError extends Error {
87
+ code;
88
+ name = "NavigationCatalogError";
89
+ constructor(code, message) {
90
+ super(message);
91
+ this.code = code;
92
+ }
93
+ }
94
+ function invalid(message) {
95
+ throw new NavigationCatalogError("invalid_page_catalog", message);
96
+ }
97
+ function bounded(condition, message) {
98
+ if (!condition) {
99
+ throw new NavigationCatalogError("page_catalog_too_large", message);
100
+ }
101
+ }
102
+ function object(value, fields) {
103
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
104
+ return invalid("Navigation metadata must be a JSON object.");
105
+ }
106
+ if (fields !== undefined && Object.keys(value).some((key) => !fields.includes(key))) {
107
+ return invalid("Navigation metadata contains an unknown field.");
108
+ }
109
+ return value;
110
+ }
111
+ function text(value, maximum, field) {
112
+ if (typeof value !== "string" ||
113
+ value.trim() === "" ||
114
+ /[\u0000-\u0008\u000b\u000c\u000e-\u001f]/u.test(value)) {
115
+ return invalid(`${field} must be nonblank text without control characters.`);
116
+ }
117
+ bounded(Array.from(value).length <= maximum, `${field} exceeds ${maximum} Unicode code points.`);
118
+ return value;
119
+ }
120
+ function hints(value) {
121
+ const entries = Object.entries(object(value));
122
+ bounded(entries.length <= NAVIGATION_CATALOG_LIMITS.hints, "A page has more than 32 query hints.");
123
+ return Object.freeze(Object.fromEntries(entries
124
+ .sort(([a], [b]) => compare(a, b))
125
+ .map(([key, hint]) => [
126
+ text(key, NAVIGATION_CATALOG_LIMITS.responseBytes, "Query name"),
127
+ text(hint, NAVIGATION_CATALOG_LIMITS.hint, "Query hint"),
128
+ ])));
129
+ }
130
+ function compare(left, right) {
131
+ return left < right ? -1 : left > right ? 1 : 0;
132
+ }
133
+ function entry(value) {
134
+ const page = object(value, [
135
+ "ref",
136
+ "route",
137
+ "title",
138
+ "description",
139
+ "entities",
140
+ "parameters",
141
+ "query",
142
+ ]);
143
+ const route = text(page.route, NAVIGATION_CATALOG_LIMITS.responseBytes, "Page route");
144
+ if (!route.startsWith("/") || /[?#\\\s\u007f]/u.test(route) || route.includes("//")) {
145
+ return invalid("A page route must be a normalized absolute path without an origin or query.");
146
+ }
147
+ const segments = route.slice(1).split("/").filter(Boolean);
148
+ const routeParameters = [];
149
+ for (const [index, segment] of segments.entries()) {
150
+ const match = /^(?:\[\[\.\.\.([^\[\]/]+)\]\]|\[\.\.\.([^\[\]/]+)\]|\[([^\[\]/]+)\])$/u.exec(segment);
151
+ if (match) {
152
+ const name = match[1] ?? match[2] ?? match[3];
153
+ const kind = match[3] === undefined ? "catch_all" : "segment";
154
+ text(name, NAVIGATION_CATALOG_LIMITS.responseBytes, "Parameter name");
155
+ if (routeParameters.some((parameter) => parameter.name === name) ||
156
+ (kind === "catch_all" && index !== segments.length - 1)) {
157
+ return invalid("Route parameters must be unique and catch-all parameters must be last.");
158
+ }
159
+ routeParameters.push({ name, kind, required: match[1] === undefined });
160
+ }
161
+ else {
162
+ let decoded;
163
+ try {
164
+ decoded = decodeURIComponent(segment);
165
+ }
166
+ catch {
167
+ return invalid("Page route has invalid percent encoding.");
168
+ }
169
+ if (decoded === "." || decoded === ".." || /[\[\]\/\\\u0000-\u0020\u007f]/u.test(decoded)) {
170
+ return invalid("Page route has an unsupported or unsafe segment.");
171
+ }
172
+ }
173
+ }
174
+ if (page.ref !== `page:${route}`) {
175
+ return invalid("Page references must be page: followed by the normalized route.");
176
+ }
177
+ if (!Array.isArray(page.entities) || !Array.isArray(page.parameters)) {
178
+ return invalid("Page entities and parameters must be arrays.");
179
+ }
180
+ bounded(page.entities.length <= NAVIGATION_CATALOG_LIMITS.associations, "A page has more than 32 entities.");
181
+ const entities = Array.from(page.entities, (name) => {
182
+ if (typeof name !== "string" || !/^[a-z][a-z0-9_]*$/u.test(name)) {
183
+ return invalid("Page entity associations must be canonical ontology names.");
184
+ }
185
+ return name;
186
+ });
187
+ if (new Set(entities).size !== entities.length) {
188
+ return invalid("A page repeats an entity association.");
189
+ }
190
+ if (page.parameters.length !== routeParameters.length) {
191
+ return invalid("Page parameters must exactly describe their route.");
192
+ }
193
+ const declaredParameters = page.parameters;
194
+ const parameters = routeParameters.map((expected, index) => {
195
+ const parameter = object(declaredParameters[index], [
196
+ "name",
197
+ "kind",
198
+ "required",
199
+ "description",
200
+ ]);
201
+ if (parameter.name !== expected.name ||
202
+ parameter.kind !== expected.kind ||
203
+ parameter.required !== expected.required) {
204
+ return invalid("Page parameters must match their route in path order.");
205
+ }
206
+ return Object.freeze({
207
+ ...expected,
208
+ ...(parameter.description === undefined
209
+ ? {}
210
+ : {
211
+ description: text(parameter.description, NAVIGATION_CATALOG_LIMITS.hint, "Parameter hint"),
212
+ }),
213
+ });
214
+ });
215
+ bounded(parameters.filter((parameter) => parameter.description !== undefined).length <=
216
+ NAVIGATION_CATALOG_LIMITS.hints, "A page has more than 32 parameter hints.");
217
+ const normalized = Object.freeze({
218
+ ref: `page:${route}`,
219
+ route,
220
+ title: text(page.title, NAVIGATION_CATALOG_LIMITS.title, "Page title"),
221
+ description: text(page.description, NAVIGATION_CATALOG_LIMITS.description, "Page description"),
222
+ entities: Object.freeze(entities.sort(compare)),
223
+ parameters: Object.freeze(parameters),
224
+ query: hints(page.query),
225
+ });
226
+ // An entry must fit even when more results follow. Runtime checks the actual origin/envelope too.
227
+ const revision = `sha256:${"0".repeat(64)}`;
228
+ const result = {
229
+ revision,
230
+ pages: [
231
+ {
232
+ ...normalized,
233
+ [parameters.length === 0 ? "url" : "url_pattern"]: `https://navigation.invalid${route}`,
234
+ },
235
+ ],
236
+ next_cursor: Buffer.from(JSON.stringify({
237
+ revision,
238
+ scope: "0".repeat(64),
239
+ request: "0".repeat(64),
240
+ last: normalized.ref,
241
+ })).toString("base64url"),
242
+ };
243
+ bounded(Buffer.byteLength(JSON.stringify({
244
+ content: [{ type: "text", text: JSON.stringify(result) }],
245
+ structuredContent: result,
246
+ })) <= NAVIGATION_CATALOG_LIMITS.responseBytes, "A complete page entry exceeds the MCP response budget.");
247
+ return normalized;
248
+ }
249
+ /** Canonical JSON is independent of insertion order, process locale, and object prototypes. */
250
+ function canonical(value) {
251
+ if (Array.isArray(value)) {
252
+ return `[${value.map(canonical).join(",")}]`;
253
+ }
254
+ if (typeof value === "object" && value !== null) {
255
+ return `{${Object.entries(value)
256
+ .sort(([a], [b]) => compare(a, b))
257
+ .map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`)
258
+ .join(",")}}`;
259
+ }
260
+ return JSON.stringify(value);
261
+ }
262
+ /** Validate and copy an untrusted artifact. Entity existence is checked against the serving ontology. */
263
+ export function parsePageCatalog(value) {
264
+ const catalog = object(value, ["version", "revision", "pages"]);
265
+ if (catalog.version !== 1 ||
266
+ typeof catalog.revision !== "string" ||
267
+ !/^sha256:[a-f0-9]{64}$/u.test(catalog.revision) ||
268
+ !Array.isArray(catalog.pages)) {
269
+ return invalid("Expected a version-1 page catalog with a SHA-256 revision and pages array.");
270
+ }
271
+ bounded(catalog.pages.length <= NAVIGATION_CATALOG_LIMITS.pages, "A catalog has more than 1,000 pages.");
272
+ const pages = Array.from(catalog.pages, entry).sort((a, b) => compare(a.ref, b.ref));
273
+ if (new Set(pages.map((page) => page.ref)).size !== pages.length) {
274
+ return invalid("Page catalog contains duplicate routes.");
275
+ }
276
+ const normalized = {
277
+ version: 1,
278
+ revision: catalog.revision,
279
+ pages: Object.freeze(pages),
280
+ };
281
+ bounded(Buffer.byteLength(canonical(normalized)) <= NAVIGATION_CATALOG_LIMITS.bytes, "Page catalog exceeds 1 MiB.");
282
+ return Object.freeze(normalized);
283
+ }
284
+ /** Generate an immutable catalog identity from normalized metadata, ontology, and source identity. */
285
+ export function createPageCatalog(pages, context) {
286
+ text(context.ontologyHash, NAVIGATION_CATALOG_LIMITS.bytes, "Ontology hash");
287
+ text(context.sourceHash, NAVIGATION_CATALOG_LIMITS.bytes, "Source hash");
288
+ const normalized = parsePageCatalog({ version: 1, revision: `sha256:${"0".repeat(64)}`, pages });
289
+ const revision = `sha256:${createHash("sha256")
290
+ .update(canonical({
291
+ version: 1,
292
+ pages: normalized.pages,
293
+ ontologyHash: context.ontologyHash,
294
+ sourceHash: context.sourceHash,
295
+ }))
296
+ .digest("hex")}`;
297
+ return Object.freeze({ ...normalized, revision });
298
+ }
package/dist/neon.d.ts ADDED
@@ -0,0 +1,101 @@
1
+ import { NextResponse } from "next/server";
2
+ import type { NextRequest } from "next/server";
3
+ import type { NeonAuthEnvironment, ResolvedConfig } from "./config.js";
4
+ import type { OntologyTransport } from "./ontology.js";
5
+ import type { ProxyOptions, SegmentStreamProxy } from "./proxy.js";
6
+ import type { Fetch } from "./sessions.js";
7
+ import type { AppUser } from "./tokens.js";
8
+ /** The app's sign-in page, which renders `<SignIn />` from `@segmentstream/app/ui`. */
9
+ export declare const SIGN_IN_PAGE = "/sign-in";
10
+ /** Where `app/src/app/api/auth/[...path]/route.ts` serves the Neon Auth API. */
11
+ export declare const AUTH_API_PATH = "/api/auth";
12
+ /**
13
+ * Paths every visitor may open: the Neon Auth API, the sign-in page, the health check, and the
14
+ * Next.js assets and metadata files the sign-in page needs.
15
+ */
16
+ export declare const OPEN_PATHS: ReadonlyArray<string>;
17
+ interface NeonError {
18
+ readonly status?: number;
19
+ readonly code?: string;
20
+ readonly message?: string;
21
+ }
22
+ interface NeonResult<T> {
23
+ readonly data: T | null;
24
+ readonly error: NeonError | null;
25
+ }
26
+ interface NeonSessionData {
27
+ readonly session: {
28
+ readonly id: string;
29
+ } | null;
30
+ readonly user: {
31
+ readonly id: string;
32
+ readonly email?: string | null;
33
+ readonly name?: string | null;
34
+ } | null;
35
+ }
36
+ export type AuthRouteHandler = (request: Request, context: {
37
+ params: Promise<{
38
+ path: string[];
39
+ }>;
40
+ }) => Promise<Response>;
41
+ /** The Neon Auth API for `app/src/app/api/auth/[...path]/route.ts`. */
42
+ export interface AuthRouteHandlers {
43
+ readonly GET: AuthRouteHandler;
44
+ readonly POST: AuthRouteHandler;
45
+ readonly PUT: AuthRouteHandler;
46
+ readonly DELETE: AuthRouteHandler;
47
+ readonly PATCH: AuthRouteHandler;
48
+ }
49
+ /** The part of `createNeonAuth(...)` from `@neondatabase/auth/next/server` the SDK uses. */
50
+ export interface NeonAuthServer {
51
+ getSession(): Promise<NeonResult<NeonSessionData>>;
52
+ token(): Promise<NeonResult<{
53
+ readonly token?: string;
54
+ }>>;
55
+ signOut(): Promise<NeonResult<unknown>>;
56
+ handler(): AuthRouteHandlers;
57
+ middleware(config?: {
58
+ loginUrl?: string;
59
+ }): (request: NextRequest) => Promise<NextResponse>;
60
+ }
61
+ export type CreateNeonAuth = (config: {
62
+ readonly baseUrl: string;
63
+ readonly cookies: {
64
+ readonly secret: string;
65
+ readonly sameSite: "lax";
66
+ };
67
+ }) => NeonAuthServer;
68
+ /** How `getUser`, `requireUser` and `can` read the signed-in user. */
69
+ export interface UserOptions {
70
+ /**
71
+ * Ask `/api/ontology/me` again instead of reusing the answer cached for up to a minute, and cache
72
+ * the new answer. For checks a role change must take effect on at once.
73
+ */
74
+ readonly fresh?: boolean;
75
+ }
76
+ export interface SignOutOptions {
77
+ /** Where to send the browser afterwards. Defaults to the sign-in page. */
78
+ readonly redirectTo?: string;
79
+ }
80
+ export interface NeonSessionDependencies {
81
+ readonly config: ResolvedConfig;
82
+ readonly settings: NeonAuthEnvironment;
83
+ readonly createNeonAuth: CreateNeonAuth;
84
+ readonly fetch: Fetch;
85
+ readonly now: () => number;
86
+ }
87
+ /**
88
+ * Neon Auth (Managed Better Auth) for the app's users: sessions in cookies through
89
+ * `@neondatabase/auth`, and roles and permissions from the ontology's `GET /api/ontology/me`.
90
+ */
91
+ export declare function createNeonSession(dependencies: NeonSessionDependencies): {
92
+ proxy: (options?: ProxyOptions) => SegmentStreamProxy;
93
+ authHandlers: () => AuthRouteHandlers;
94
+ getUser: (options?: UserOptions) => Promise<AppUser | null>;
95
+ requireUser: (options?: UserOptions) => Promise<AppUser>;
96
+ can: (permission: string, options?: UserOptions) => Promise<boolean>;
97
+ signOut: (options?: SignOutOptions) => Promise<never>;
98
+ ontologyTransport: OntologyTransport;
99
+ identityToken: () => Promise<string | null>;
100
+ };
101
+ export {};