@biab-dev/sdk 0.2.1 → 0.7.2

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/README.md CHANGED
@@ -45,29 +45,439 @@ The scaffold currently provides:
45
45
 
46
46
  ## Example
47
47
 
48
+ The SDK has two surfaces: a low-level client over the package API, and
49
+ site-scoped helpers under `client.site(siteId)`.
50
+
48
51
  ```ts
49
52
  import { createBiabDevClient } from "@biab-dev/sdk";
50
53
 
51
54
  const client = createBiabDevClient({
52
- baseUrl: "https://host.example.com/api/package/v1",
55
+ baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!, // ends in /api/package/v1
53
56
  apiKey: process.env.BIAB_API_KEY!,
54
57
  });
55
58
 
56
- const site = client.site("00000000-0000-0000-0000-000000000000");
59
+ // Identity probe — always the first call in a fresh integration.
60
+ const auth = await client.introspect();
61
+
62
+ const site = client.site(process.env.BIAB_SITE_ID!);
63
+
64
+ // Marketing-page JSON edited from Site Builder → Marketing pages
65
+ const { page } = await site.marketingPages.get("home");
57
66
 
58
- await client.introspect();
67
+ // Custom collections
59
68
  await site.collections.list();
60
- await site.collections.get("products");
61
- await site.rows.query("products", {
62
- filters: [{ fieldName: "title", operator: "contains", value: "chair" }],
69
+ await site.rows.query("page-content", {
70
+ filters: [{ fieldName: "pageKey", operator: "equals", value: "home" }],
63
71
  limit: 10,
64
72
  });
65
73
  ```
66
74
 
75
+ ### End-to-end consumer pattern
76
+
77
+ `custom-demo/src/lib/biab/get-home-content.ts` in this monorepo is the
78
+ canonical consumer pattern: it normalizes the base URL (https-only, ends in
79
+ `/api/package/v1`), reads the marketing-page JSON via the SDK, and falls back
80
+ to a local `content.md` document if the env is not configured. Copy that file
81
+ when you build a new frontend that consumes BIAB content.
82
+
83
+ ## Tenant auth (sign-in / sign-up / sign-out)
84
+
85
+ The SDK includes per-tenant authentication built on WorkOS Organizations. A
86
+ visitor who clicks "Sign in" on your site is signed in to **the org bound to
87
+ your API key** — not to BIAB itself. Sign-up, sign-in, password reset, MFA,
88
+ social login, and invitations are all handled by WorkOS's hosted page.
89
+
90
+ ### How it works
91
+
92
+ 1. Visitor clicks `<SignIn />` (a styled link).
93
+ 2. Browser hits your installed `/api/biab-auth/sign-in` route.
94
+ 3. SDK redirects to WorkOS's hosted page, scoped to your org.
95
+ 4. After auth, WorkOS redirects to your installed `/api/biab-auth/callback`.
96
+ 5. SDK exchanges the code, sets an httpOnly session cookie on **your domain**,
97
+ redirects the user to `returnTo`.
98
+ 6. Subsequent requests can read the session via `useUser()` (client) or
99
+ `getTenantSession()` (server / SSR).
100
+
101
+ Cookie lives on your tenant's domain, not BIAB's — so your SSR can read it,
102
+ and there's no XSS-readable token floating around.
103
+
104
+ ### One-time WorkOS configuration
105
+
106
+ Before the SDK auth flow works for your site, your BIAB platform admin (or
107
+ you, via the WorkOS dashboard if you have access) must register your
108
+ callback URL as an allowed **Redirect URI** for the WorkOS Organization
109
+ bound to your API key:
110
+
111
+ 1. Open the [WorkOS dashboard](https://dashboard.workos.com).
112
+ 2. Go to **Configuration → Redirects**.
113
+ 3. Click **Add Redirect URI** and enter your callback URL exactly:
114
+ - Production: `https://your-site.com/api/biab-auth/callback`
115
+ - Local dev: `http://localhost:3000/api/biab-auth/callback`
116
+ 4. Save. WorkOS will reject the auth flow with `redirect_uri_mismatch` if
117
+ this URL isn't registered byte-for-byte.
118
+
119
+ If you self-host BIAB or are using a sandbox, the same applies to the WorkOS
120
+ project that issued your platform's `WORKOS_CLIENT_ID`.
121
+
122
+ ### Install the auth handler
123
+
124
+ `createAuthHandler` returns Fetch-standard handlers — they accept a `Request`
125
+ and return a `Response`. Mount the same factory in any framework that speaks
126
+ Web standards. The React components below are framework-agnostic; only the
127
+ handler install line differs.
128
+
129
+ In every example, mount the handler at a path that **matches the
130
+ `callbackUrl` you registered with WorkOS** — a mismatch produces
131
+ `redirect_uri_mismatch`.
132
+
133
+ #### Next.js (App Router)
134
+
135
+ ```ts
136
+ // app/api/biab-auth/[...biab]/route.ts
137
+ import { createAuthHandler } from "@biab-dev/sdk";
138
+
139
+ const handler = createAuthHandler({
140
+ baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!,
141
+ apiKey: process.env.BIAB_API_KEY!,
142
+ callbackUrl: `${process.env.NEXT_PUBLIC_SITE_URL}/api/biab-auth/callback`,
143
+ });
144
+
145
+ export const GET = handler.GET;
146
+ export const POST = handler.POST;
147
+ ```
148
+
149
+ #### Next.js (Pages Router)
150
+
151
+ Pages Router uses Node `req`/`res`, not Fetch. Wrap the handler:
152
+
153
+ ```ts
154
+ // pages/api/biab-auth/[...biab].ts
155
+ import { createAuthHandler } from "@biab-dev/sdk";
156
+ import type { NextApiRequest, NextApiResponse } from "next";
157
+
158
+ const handler = createAuthHandler({
159
+ baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!,
160
+ apiKey: process.env.BIAB_API_KEY!,
161
+ callbackUrl: `${process.env.NEXT_PUBLIC_SITE_URL}/api/biab-auth/callback`,
162
+ });
163
+
164
+ export default async function (req: NextApiRequest, res: NextApiResponse) {
165
+ const url = new URL(req.url!, `https://${req.headers.host}`);
166
+ const request = new Request(url, {
167
+ method: req.method,
168
+ headers: new Headers(req.headers as Record<string, string>),
169
+ body: req.method === "GET" || req.method === "HEAD"
170
+ ? undefined
171
+ : JSON.stringify(req.body),
172
+ });
173
+ const response = await (req.method === "POST" ? handler.POST : handler.GET)(
174
+ request,
175
+ );
176
+ response.headers.forEach((v, k) => res.setHeader(k, v));
177
+ res.status(response.status).send(await response.text());
178
+ }
179
+ ```
180
+
181
+ #### Remix
182
+
183
+ ```ts
184
+ // app/routes/api.biab-auth.$.tsx
185
+ import { createAuthHandler } from "@biab-dev/sdk";
186
+ import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node";
187
+
188
+ const handler = createAuthHandler({
189
+ baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!,
190
+ apiKey: process.env.BIAB_API_KEY!,
191
+ callbackUrl: `${process.env.SITE_URL}/api/biab-auth/callback`,
192
+ });
193
+
194
+ export const loader = ({ request }: LoaderFunctionArgs) => handler.GET(request);
195
+ export const action = ({ request }: ActionFunctionArgs) => handler.POST(request);
196
+ ```
197
+
198
+ #### SvelteKit
199
+
200
+ ```ts
201
+ // src/routes/api/biab-auth/[...biab]/+server.ts
202
+ import { createAuthHandler } from "@biab-dev/sdk";
203
+ import { env } from "$env/dynamic/private";
204
+ import { env as pubEnv } from "$env/dynamic/public";
205
+
206
+ const handler = createAuthHandler({
207
+ baseUrl: env.BIAB_PACKAGE_API_BASE_URL,
208
+ apiKey: env.BIAB_API_KEY,
209
+ callbackUrl: `${pubEnv.PUBLIC_SITE_URL}/api/biab-auth/callback`,
210
+ });
211
+
212
+ export const GET = ({ request }) => handler.GET(request);
213
+ export const POST = ({ request }) => handler.POST(request);
214
+ ```
215
+
216
+ #### Astro
217
+
218
+ ```ts
219
+ // src/pages/api/biab-auth/[...biab].ts
220
+ import { createAuthHandler } from "@biab-dev/sdk";
221
+ import type { APIRoute } from "astro";
222
+
223
+ const handler = createAuthHandler({
224
+ baseUrl: import.meta.env.BIAB_PACKAGE_API_BASE_URL,
225
+ apiKey: import.meta.env.BIAB_API_KEY,
226
+ callbackUrl: `${import.meta.env.PUBLIC_SITE_URL}/api/biab-auth/callback`,
227
+ });
228
+
229
+ export const GET: APIRoute = ({ request }) => handler.GET(request);
230
+ export const POST: APIRoute = ({ request }) => handler.POST(request);
231
+ ```
232
+
233
+ > Astro requires `output: "server"` (or `"hybrid"`) and an SSR-capable adapter
234
+ > for cookies and `Response.redirect` to work. Static-only Astro can't host
235
+ > the auth handler.
236
+
237
+ #### Hono / Cloudflare Workers / Bun / Deno
238
+
239
+ These runtimes are already Fetch-native — pass the raw `Request` through:
240
+
241
+ ```ts
242
+ // Hono
243
+ import { Hono } from "hono";
244
+ import { createAuthHandler } from "@biab-dev/sdk";
245
+
246
+ const app = new Hono();
247
+ const handler = createAuthHandler({
248
+ baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!,
249
+ apiKey: process.env.BIAB_API_KEY!,
250
+ callbackUrl: `${process.env.SITE_URL}/api/biab-auth/callback`,
251
+ });
252
+
253
+ app.all("/api/biab-auth/*", (c) =>
254
+ c.req.method === "POST" ? handler.POST(c.req.raw) : handler.GET(c.req.raw),
255
+ );
256
+ ```
257
+
258
+ ```ts
259
+ // Cloudflare Worker (or Bun.serve / Deno.serve)
260
+ import { createAuthHandler } from "@biab-dev/sdk";
261
+
262
+ const handler = createAuthHandler({
263
+ baseUrl: env.BIAB_PACKAGE_API_BASE_URL,
264
+ apiKey: env.BIAB_API_KEY,
265
+ callbackUrl: `${env.SITE_URL}/api/biab-auth/callback`,
266
+ });
267
+
268
+ export default {
269
+ async fetch(request: Request) {
270
+ const { pathname } = new URL(request.url);
271
+ if (pathname.startsWith("/api/biab-auth")) {
272
+ return request.method === "POST"
273
+ ? handler.POST(request)
274
+ : handler.GET(request);
275
+ }
276
+ return new Response("Not found", { status: 404 });
277
+ },
278
+ };
279
+ ```
280
+
281
+ #### Express / Fastify (Node)
282
+
283
+ Use a Web-standards adapter such as `@whatwg-node/server` or
284
+ `fastify-web-standards` to bridge Node `req`/`res` ↔ Fetch `Request`/`Response`,
285
+ then call `handler.GET(request)` / `handler.POST(request)`. The adapter does
286
+ the conversion the Pages Router example does inline.
287
+
288
+ #### Nuxt 3 (Nitro)
289
+
290
+ Nitro server routes get a Fetch-style `event.node.req`. Use `toWebRequest`
291
+ from `h3` to bridge:
292
+
293
+ ```ts
294
+ // server/api/biab-auth/[...biab].ts
295
+ import { createAuthHandler } from "@biab-dev/sdk";
296
+ import { toWebRequest } from "h3";
297
+
298
+ const handler = createAuthHandler({
299
+ baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!,
300
+ apiKey: process.env.BIAB_API_KEY!,
301
+ callbackUrl: `${process.env.NUXT_PUBLIC_SITE_URL}/api/biab-auth/callback`,
302
+ });
303
+
304
+ export default defineEventHandler(async (event) => {
305
+ const request = toWebRequest(event);
306
+ return event.node.req.method === "POST"
307
+ ? handler.POST(request)
308
+ : handler.GET(request);
309
+ });
310
+ ```
311
+
312
+ #### TanStack Start
313
+
314
+ TanStack Start API routes return Web-standards Responses directly.
315
+
316
+ ```ts
317
+ // app/routes/api/biab-auth.$.ts
318
+ import { createAPIFileRoute } from "@tanstack/start/api";
319
+ import { createAuthHandler } from "@biab-dev/sdk";
320
+
321
+ const handler = createAuthHandler({
322
+ baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!,
323
+ apiKey: process.env.BIAB_API_KEY!,
324
+ callbackUrl: `${process.env.SITE_URL}/api/biab-auth/callback`,
325
+ });
326
+
327
+ export const Route = createAPIFileRoute("/api/biab-auth/$")({
328
+ GET: ({ request }) => handler.GET(request),
329
+ POST: ({ request }) => handler.POST(request),
330
+ });
331
+ ```
332
+
333
+ #### SolidStart
334
+
335
+ ```ts
336
+ // src/routes/api/biab-auth/[...biab].ts
337
+ import { createAuthHandler } from "@biab-dev/sdk";
338
+ import type { APIEvent } from "@solidjs/start/server";
339
+
340
+ const handler = createAuthHandler({
341
+ baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!,
342
+ apiKey: process.env.BIAB_API_KEY!,
343
+ callbackUrl: `${process.env.SITE_URL}/api/biab-auth/callback`,
344
+ });
345
+
346
+ export const GET = ({ request }: APIEvent) => handler.GET(request);
347
+ export const POST = ({ request }: APIEvent) => handler.POST(request);
348
+ ```
349
+
350
+ #### Vite SPA, plain Svelte, plain Vue, plain Solid
351
+
352
+ Pure client-side apps **don't have a server**, so they can't mount
353
+ `createAuthHandler` directly — there's no place to store a secret API key
354
+ or set an httpOnly cookie. You need an adjacent server runtime:
355
+
356
+ - Cloudflare Workers / Deno Deploy / Bun.serve / Express → use the example
357
+ above for that runtime, then point your Vite SPA at its hostname.
358
+ - Or upgrade to the framework's full-stack variant (SvelteKit instead of
359
+ Svelte, Nuxt instead of Vue, SolidStart instead of Solid).
360
+
361
+ There's no client-only mode for the auth handler by design — the API key
362
+ must stay on a server.
363
+
364
+ ### Non-React UI components
365
+
366
+ The `<SignIn />` / `<SignUp />` / `<SignOut />` / `useUser()` exports under
367
+ `@biab-dev/sdk/react` are React-specific. Other frameworks can build the
368
+ exact same UI with two trivial primitives once the auth handler is mounted:
369
+
370
+ 1. **Buttons are links.** Sign-in/up/out are plain anchors:
371
+
372
+ ```html
373
+ <a href="/api/biab-auth/sign-in">Sign in</a>
374
+ <a href="/api/biab-auth/sign-up">Create account</a>
375
+ <a href="/api/biab-auth/sign-out">Sign out</a>
376
+ ```
377
+
378
+ Add `?returnTo=/dashboard` or `?loginHint=user@example.com` query params
379
+ as needed.
380
+
381
+ 2. **Reading the session.** `GET /api/biab-auth/me` returns the current user
382
+ or `null`. Same shape as `useUser()`'s React hook:
383
+
384
+ ```js
385
+ const session = await fetch("/api/biab-auth/me", { credentials: "include" })
386
+ .then((r) => r.json());
387
+ // → { user: {...}, organizationId, role } | null
388
+ ```
389
+
390
+ Wire that into your framework's reactivity primitive of choice (Svelte
391
+ stores, Vue `ref`, Solid signals, vanilla `useState`).
392
+
393
+ ### Drop the components into your pages
394
+
395
+ These are plain React components — they work in any framework that can render
396
+ React (Next.js, Remix, SvelteKit-with-React, Astro, Vite SPAs, etc.). Only
397
+ the handler install above differs per framework.
398
+
399
+ ```tsx
400
+ // app/page.tsx
401
+ import { SignIn, SignOut, SignUp, useUser } from "@biab-dev/sdk/react";
402
+
403
+ export default function Home() {
404
+ const me = useUser();
405
+
406
+ if (me.status === "loading") return null;
407
+
408
+ if (me.status === "signed-in") {
409
+ return (
410
+ <div>
411
+ <p>Hi, {me.user.user.firstName ?? me.user.user.email}.</p>
412
+ <SignOut className="btn">Sign out</SignOut>
413
+ </div>
414
+ );
415
+ }
416
+
417
+ return (
418
+ <div>
419
+ <SignIn className="btn">Sign in</SignIn>
420
+ <SignUp className="btn btn-secondary">Create account</SignUp>
421
+ </div>
422
+ );
423
+ }
424
+ ```
425
+
426
+ ### Reading the session in SSR
427
+
428
+ ```ts
429
+ // app/dashboard/page.tsx
430
+ import { cookies } from "next/headers";
431
+ import { DEFAULT_AUTH_COOKIE_NAME, getTenantSession } from "@biab-dev/sdk";
432
+
433
+ export default async function Dashboard() {
434
+ const cookieValue = (await cookies()).get(DEFAULT_AUTH_COOKIE_NAME)?.value;
435
+ const session = await getTenantSession({
436
+ cookieValue,
437
+ baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!,
438
+ apiKey: process.env.BIAB_API_KEY!,
439
+ });
440
+
441
+ if (!session) redirect("/");
442
+ return <p>Welcome, {session.user.email}.</p>;
443
+ }
444
+ ```
445
+
446
+ ### Invitations (existing-vs-new users)
447
+
448
+ Invitations sent from the WorkOS dashboard work for both cases automatically:
449
+
450
+ - **Existing user** → invitation link signs them in and adds them to the org.
451
+ - **New user** → invitation link prompts them to set a password, creates the
452
+ user, and adds them to the org.
453
+
454
+ In both cases the BIAB host syncs the membership into its database on the
455
+ first authed callback. You don't need to write any invitation acceptance
456
+ code — link them at the WorkOS-generated URL and the rest is handled.
457
+
458
+ ## Configuration
459
+
460
+ | Env var | Where it comes from |
461
+ | --- | --- |
462
+ | `BIAB_API_KEY` | One-time reveal in **Site Builder → Developer → Package API & Unkey keys** in the host app. |
463
+ | `BIAB_SITE_ID` | The "Site ID" shown directly above the API key list in the same panel. |
464
+ | `BIAB_PACKAGE_API_BASE_URL` | The "Package API base URL" shown above — **always `https://` for production**, and the URL **must** end in `/api/package/v1`. |
465
+
466
+ > **Two production traps to avoid:**
467
+ > 1. `http://` against a production host. The host responds `308 → https://`,
468
+ > and `fetch` strips the `Authorization` header on cross-scheme redirects
469
+ > per the WHATWG fetch spec — the redirected request lands unauthenticated.
470
+ > 2. A base URL that does **not** include `/api/package/v1`. SDK versions
471
+ > ≤ 0.2.0 silently drop the base URL's pathname when constructing site-scoped
472
+ > requests; 0.2.1 fixes this. Either upgrade or include the path component
473
+ > in the env var.
474
+
67
475
  ## Notes
68
476
 
69
- - This package is scaffolded first; the host package routes still need to be implemented.
70
- - Collection contracts intentionally mirror the current BIAB `site_data_*` model instead of inventing a second schema system.
477
+ - Collection contracts intentionally mirror the current BIAB `site_data_*`
478
+ model instead of inventing a second schema system.
479
+ - The host owns API key verification, scope enforcement, RBAC, persistence,
480
+ and audit. The SDK is a transport + typed contract layer.
71
481
 
72
482
  ## Publishing to npm
73
483
 
@@ -0,0 +1,91 @@
1
+ /**
2
+ * SDK auth handler — the file a tenant developer mounts on their own site
3
+ * to handle the WorkOS callback. Cookie lives on the tenant's domain so the
4
+ * tenant's SSR can read it via standard cookie APIs.
5
+ *
6
+ * Usage (Next.js App Router):
7
+ *
8
+ * // app/api/biab-auth/[...biab]/route.ts
9
+ * import { createAuthHandler } from "@biab-dev/sdk";
10
+ *
11
+ * const handler = createAuthHandler({
12
+ * baseUrl: process.env.BIAB_PACKAGE_API_BASE_URL!,
13
+ * apiKey: process.env.BIAB_API_KEY!,
14
+ * callbackUrl: "https://my-site.com/api/biab-auth/callback",
15
+ * });
16
+ *
17
+ * export const GET = handler.GET;
18
+ * export const POST = handler.POST;
19
+ *
20
+ * Then drop <SignIn />, <SignUp />, <SignOut /> into your pages — they call
21
+ * `/api/biab-auth/sign-in?intent=sign-in` etc., which 302s through the WorkOS
22
+ * hosted page and back to `callbackUrl`. The handler exchanges the code,
23
+ * sets the session cookie, and redirects the user to `returnTo`.
24
+ */
25
+ import { type BiabDevClientOptions } from "./client";
26
+ export declare const DEFAULT_AUTH_COOKIE_NAME = "biab_session";
27
+ export declare const DEFAULT_AUTH_BASE_PATH = "/api/biab-auth";
28
+ export type CreateAuthHandlerOptions = {
29
+ /** BIAB platform base URL — e.g. https://app.biab.com/api/package/v1 */
30
+ baseUrl: string;
31
+ /** Org-bound package API key (server-side secret). */
32
+ apiKey: string;
33
+ /**
34
+ * Public, fully-qualified URL of THIS handler's `/callback` route on the
35
+ * tenant's domain. Must be registered as a redirect URI in WorkOS.
36
+ */
37
+ callbackUrl: string;
38
+ /** Where to send the user after successful sign-in if no `returnTo` was passed. */
39
+ defaultReturnTo?: string;
40
+ /** Where to send the user after sign-out. Defaults to "/". */
41
+ signOutReturnTo?: string;
42
+ /** Cookie name. Defaults to "biab_session". */
43
+ cookieName?: string;
44
+ /**
45
+ * Cookie domain. Leave undefined to scope to current host. Set if you want
46
+ * to share the session across subdomains (e.g. ".my-site.com").
47
+ */
48
+ cookieDomain?: string;
49
+ /**
50
+ * The base path this handler is mounted at — used to derive sub-routes.
51
+ * Defaults to "/api/biab-auth". Must match the route file location.
52
+ */
53
+ basePath?: string;
54
+ /** Optional fetch override (testing, edge runtimes). */
55
+ fetch?: BiabDevClientOptions["fetch"];
56
+ /**
57
+ * Origin sent on every server-to-server request to the platform. Defaults
58
+ * to the origin of `callbackUrl`. Override only when your dev/prod hosts
59
+ * differ from the callback (rare).
60
+ */
61
+ siteOrigin?: string;
62
+ };
63
+ type SimpleHandler = (request: Request) => Promise<Response>;
64
+ export type AuthHandlerRoutes = {
65
+ GET: SimpleHandler;
66
+ POST: SimpleHandler;
67
+ };
68
+ export declare function createAuthHandler(options: CreateAuthHandlerOptions): AuthHandlerRoutes;
69
+ /**
70
+ * Server-side helper for tenant SSR: read the current session from the cookie.
71
+ * Returns null when the user isn't signed in.
72
+ */
73
+ export declare function getTenantSession(input: {
74
+ cookieValue: string | null | undefined;
75
+ baseUrl: string;
76
+ apiKey: string;
77
+ /** Required when the API key has Allowed Host set; see {@link BiabDevClientOptions.siteOrigin}. */
78
+ siteOrigin?: string;
79
+ fetch?: BiabDevClientOptions["fetch"];
80
+ }): Promise<{
81
+ role: string | null;
82
+ user: {
83
+ id: string;
84
+ email: string | null;
85
+ firstName: string | null;
86
+ lastName: string | null;
87
+ };
88
+ organizationId: string;
89
+ } | null>;
90
+ export {};
91
+ //# sourceMappingURL=auth-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-handler.d.ts","sourceRoot":"","sources":["../src/auth-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAEN,KAAK,oBAAoB,EACzB,MAAM,UAAU,CAAC;AAGlB,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AACvD,eAAO,MAAM,sBAAsB,mBAAmB,CAAC;AAEvD,MAAM,MAAM,wBAAwB,GAAG;IACtC,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8DAA8D;IAC9D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,KAAK,CAAC,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE7D,MAAM,MAAM,iBAAiB,GAAG;IAC/B,GAAG,EAAE,aAAa,CAAC;IACnB,IAAI,EAAE,aAAa,CAAC;CACpB,CAAC;AAkGF,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,wBAAwB,GAC/B,iBAAiB,CA0GnB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC7C,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,mGAAmG;IACnG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;CACtC;;;;;;;;;UASA"}