@burdenoff/microfe-housingvista 2026.709.3 → 2026.716.1

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.
@@ -1,26 +1,11 @@
1
1
  /**
2
- * HousingVista adapter for the shared fe-libs AssistantWidget.
2
+ * housingvista adapter for the shared fe-libs AssistantWidget transport.
3
3
  *
4
- * The floating widget (fe-libs, Layer 1) is backend-agnostic — it calls an
5
- * injected `AssistantTransport`. This hook builds a transport that reuses the
6
- * existing sandbox `api-calls` agent: it provisions/reuses a sandbox, opens a
7
- * session, dispatches the prompt async, then polls for the streamed answer. The
8
- * agent introspects the GraphQL schema and performs API calls on the user's
9
- * behalf using their workspace token, contextual to the current screen (via
10
- * `gatherPageContext`).
11
- *
12
- * This is a thin orchestration over the functions in `assistantApi`.
13
- */
14
- /**
15
- * Locally-defined mirror of the fe-libs `AssistantTransport` contract.
16
- *
17
- * We intentionally do NOT import the type from `@burdenoff/fe-libs` here:
18
- * microfe's tsconfig maps `@burdenoff/fe-libs/*` to fe-libs *source*, so
19
- * vite-plugin-dts would rewrite a cross-package type used in this hook's
20
- * public signature to a broken source-relative path in the emitted `.d.ts`.
21
- * Structural typing makes this shape assignable to fe-libs' `AssistantTransport`
22
- * at the call site (housingvista-app's AppShell), which is where compatibility
23
- * is enforced — drift there fails the app type-check.
4
+ * The sandbox lifecycle + poll/stream loop now lives in
5
+ * `@burdenoff/fe-libs/shared/assistant` (one implementation for all products);
6
+ * this is a thin wrapper. The exported name/shape are unchanged so app-shell
7
+ * imports don't move. The public return type is a LOCALLY-declared structural
8
+ * mirror — never re-export fe-libs types (vite-plugin-dts path rewriting).
24
9
  */
25
10
  interface AssistantSendArgs {
26
11
  prompt: string;
@@ -31,12 +16,9 @@ export interface AssistantTransport {
31
16
  sendPrompt: (args: AssistantSendArgs) => Promise<{
32
17
  text: string;
33
18
  }>;
19
+ prewarm?: (level?: 'probe' | 'full') => void;
20
+ suspend?: () => void;
34
21
  }
35
- /**
36
- * Returns a memoized `AssistantTransport` wired to the HousingVista sandbox
37
- * `api-calls` agent. The sandbox + session are cached in refs so follow-up
38
- * turns reuse the warm environment for the lifetime of the host shell.
39
- */
40
22
  export declare function useSandboxAssistantTransport(): AssistantTransport;
41
23
  export {};
42
24
  //# sourceMappingURL=createSandboxAssistantTransport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createSandboxAssistantTransport.d.ts","sourceRoot":"","sources":["../../../src/housingvista/services/createSandboxAssistantTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH;;;;;;;;;;GAUG;AACH,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AA+GD;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,kBAAkB,CA8GjE"}
1
+ {"version":3,"file":"createSandboxAssistantTransport.d.ts","sourceRoot":"","sources":["../../../src/housingvista/services/createSandboxAssistantTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnE,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,wBAAgB,4BAA4B,IAAI,kBAAkB,CAMjE"}
@@ -1,120 +1,14 @@
1
- import { createAssistantSandbox as e, createAssistantSession as t, extendAssistantSandboxTTL as n, findExistingSandbox as r, getAssistantMessages as i, sendAssistantPromptAsync as a, waitForAssistantServiceReady as o, waitForSandboxReady as s } from "./assistantApi.js";
2
- import { gatherPageContext as c } from "../utils/pageContext.js";
3
- import { useCallback as l, useMemo as u, useRef as d } from "react";
4
- import { useGatewayClient as f } from "@burdenoff/fe-libs/shared/graphql";
5
- import { useAuthToken as p } from "@burdenoff/fe-libs/shared/providers/shell";
1
+ import { gatherPageContext as e } from "../utils/pageContext.js";
2
+ import { useSandboxAssistantTransport as t } from "@burdenoff/fe-libs/shared/assistant";
6
3
  //#region src/housingvista/services/createSandboxAssistantTransport.ts
7
- var m = "assistant", h = 18e4, g = 1500, _ = 3e4;
8
- function v(e) {
9
- try {
10
- let t = e === "workspaceId" ? "burdenoff-active-context-workspace" : "burdenoff-active-context-organization", n = localStorage.getItem(t);
11
- if (n) return n;
12
- let r = sessionStorage.getItem("bf-active-profile");
13
- if (!r) return "";
14
- let i = localStorage.getItem(`bf-p-${r}-context`);
15
- return i ? JSON.parse(i)[e] ?? "" : "";
16
- } catch {
17
- return "";
18
- }
19
- }
20
- function y() {
21
- return new URLSearchParams(window.location.search).get("workspace") ?? v("workspaceId");
22
- }
23
- function b() {
24
- return new URLSearchParams(window.location.search).get("org") ?? v("organizationId");
25
- }
26
- function x(e) {
27
- return e.info?.time?.created ?? 0;
28
- }
29
- function S(e) {
30
- return (e ?? []).filter((e) => e.type === "text" && typeof e.text == "string").map((e) => e.text?.trim() ?? "").filter(Boolean).join("\n");
31
- }
32
- function C(e) {
33
- return (e ?? []).filter((e) => e.type === "tool" && e.tool).map((e) => {
34
- let t = e.state?.status ?? "running", n = e.tool ?? "tool";
35
- return t === "completed" ? `Completed: ${n}` : t === "failed" ? `Failed: ${n}` : `Running: ${n}`;
4
+ function n() {
5
+ return t({
6
+ product: "housingvista",
7
+ gatherPageContext: e,
8
+ enableCredits: !0
36
9
  });
37
10
  }
38
- function w(e, t) {
39
- let n = e.filter((e) => e.info?.role === "assistant" && x(e) >= t).sort((e, t) => x(e) - x(t));
40
- if (n.length === 0) return {
41
- content: "Thinking…",
42
- done: !1
43
- };
44
- let r = n[n.length - 1], i = S(r.parts), a = C(r.parts);
45
- return {
46
- content: [i, ...a].filter(Boolean).join("\n\n") || "Thinking…",
47
- done: !!r.info?.time?.completed && (!!i || a.length > 0)
48
- };
49
- }
50
- function T(e) {
51
- return e.replace(/(Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/(X-Workspace-Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+\b/g, "[REDACTED_JWT]").replace(/\bsk-ant-[A-Za-z0-9-]+\b/g, "[REDACTED_API_KEY]");
52
- }
53
- function E(e) {
54
- let t = e instanceof Error ? e.message.toLowerCase() : String(e).toLowerCase();
55
- return t.includes("rate limit exceeded") || t.includes("unauthorized") || t.includes("k8s api error 401") ? !1 : [
56
- "sandbox not found",
57
- "sandbox is not running",
58
- "sandbox service not available yet",
59
- "sandbox failed",
60
- "sandbox startup timed out",
61
- "assistant service did not become healthy",
62
- "proxy error: 404",
63
- "proxy error: 502",
64
- "proxy error: 503"
65
- ].some((e) => t.includes(e));
66
- }
67
- function D() {
68
- let v = f("workspace"), { getAccessToken: x, getWorkspaceToken: S, userId: C } = p(), D = d(null), O = d(null), k = l(async (n, i) => {
69
- let a = D.current;
70
- if (!a) {
71
- if (a = await r(v, n, m, i), !a) {
72
- if (!x()) throw Error("API Calls mode requires an authenticated session. Please sign in again.");
73
- a = await e(v, m, n, i);
74
- }
75
- await s(v, a, n, i), await o(v, a, n, i), D.current = a;
76
- }
77
- let c = O.current;
78
- return c || (c = (await t(v, a, n, m, i)).sessionId, O.current = c), {
79
- sandboxId: a,
80
- sessionId: c
81
- };
82
- }, [v, x]), A = l(async ({ prompt: e, onProgress: t, signal: r }) => {
83
- let o = y();
84
- if (!o) throw Error("The assistant needs an active workspace. Open a workspace and try again.");
85
- let s = {
86
- accessToken: x(),
87
- workspaceToken: S(),
88
- userId: C,
89
- organizationId: b()
90
- }, l = async (u) => {
91
- try {
92
- let { sandboxId: l, sessionId: u } = await k(o, s), d = Date.now();
93
- await a(v, l, o, u, e, m, c(), s);
94
- let f = Date.now() + h, p = Date.now(), y = w([], d);
95
- for (; Date.now() < f;) {
96
- if (r.aborted) throw Error("Cancelled");
97
- if (y = w(await i(v, l, o, u, s, 50), d), t(T(y.content)), y.done) break;
98
- Date.now() - p > _ && (await n(v, l, o, 600, s).catch(() => void 0), p = Date.now()), await new Promise((e) => setTimeout(e, g));
99
- }
100
- if (!y.done) throw Error("The assistant timed out while responding. Please try again.");
101
- return { text: T(y.content) };
102
- } catch (e) {
103
- if (u === 1 && E(e)) return D.current = null, O.current = null, l(2);
104
- throw e;
105
- }
106
- };
107
- return l(1);
108
- }, [
109
- v,
110
- k,
111
- x,
112
- S,
113
- C
114
- ]);
115
- return u(() => ({ sendPrompt: A }), [A]);
116
- }
117
11
  //#endregion
118
- export { D as useSandboxAssistantTransport };
12
+ export { n as useSandboxAssistantTransport };
119
13
 
120
14
  //# sourceMappingURL=createSandboxAssistantTransport.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../../src/housingvista/services/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * HousingVista adapter for the shared fe-libs AssistantWidget.\n *\n * The floating widget (fe-libs, Layer 1) is backend-agnostic — it calls an\n * injected `AssistantTransport`. This hook builds a transport that reuses the\n * existing sandbox `api-calls` agent: it provisions/reuses a sandbox, opens a\n * session, dispatches the prompt async, then polls for the streamed answer. The\n * agent introspects the GraphQL schema and performs API calls on the user's\n * behalf using their workspace token, contextual to the current screen (via\n * `gatherPageContext`).\n *\n * This is a thin orchestration over the functions in `assistantApi`.\n */\n\nimport { useCallback, useMemo, useRef } from 'react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\nimport { useAuthToken } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n createAssistantSandbox,\n createAssistantSession,\n extendAssistantSandboxTTL,\n findExistingSandbox,\n getAssistantMessages,\n sendAssistantPromptAsync,\n waitForAssistantServiceReady,\n waitForSandboxReady,\n type AssistantRawMessage,\n type AssistantSandboxAuthContext,\n} from './assistantApi';\nimport { gatherPageContext } from '../utils/pageContext';\nimport type { AssistantMode } from '../types/assistant';\n\n/**\n * Locally-defined mirror of the fe-libs `AssistantTransport` contract.\n *\n * We intentionally do NOT import the type from `@burdenoff/fe-libs` here:\n * microfe's tsconfig maps `@burdenoff/fe-libs/*` to fe-libs *source*, so\n * vite-plugin-dts would rewrite a cross-package type used in this hook's\n * public signature to a broken source-relative path in the emitted `.d.ts`.\n * Structural typing makes this shape assignable to fe-libs' `AssistantTransport`\n * at the call site (housingvista-app's AppShell), which is where compatibility\n * is enforced — drift there fails the app type-check.\n */\ninterface AssistantSendArgs {\n prompt: string;\n onProgress: (partialText: string) => void;\n signal: AbortSignal;\n}\n\nexport interface AssistantTransport {\n sendPrompt: (args: AssistantSendArgs) => Promise<{ text: string }>;\n}\n\nconst MODE: AssistantMode = 'assistant';\nconst STREAM_BUDGET_MS = 180_000;\nconst POLL_INTERVAL_MS = 1500;\nconst TTL_EXTEND_INTERVAL_MS = 30_000;\n\n// ── Context helpers (mirror AssistantChatArea's resolution) ──────────\n\nfunction getProfileContextValue(key: 'workspaceId' | 'organizationId'): string {\n try {\n const activeContextKey =\n key === 'workspaceId' ? 'burdenoff-active-context-workspace' : 'burdenoff-active-context-organization';\n const activeContextValue = localStorage.getItem(activeContextKey);\n if (activeContextValue) return activeContextValue;\n\n const activeProfileId = sessionStorage.getItem('bf-active-profile');\n if (!activeProfileId) return '';\n const raw = localStorage.getItem(`bf-p-${activeProfileId}-context`);\n if (!raw) return '';\n const context = JSON.parse(raw) as { workspaceId?: string; organizationId?: string };\n return context[key] ?? '';\n } catch {\n return '';\n }\n}\n\nfunction getWorkspaceId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('workspace') ?? getProfileContextValue('workspaceId');\n}\n\nfunction getOrganizationId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('org') ?? getProfileContextValue('organizationId');\n}\n\n// ── Message-progress helpers (pure; mirror AssistantChatArea) ────────\n\nfunction getRawMessageCreatedAt(message: AssistantRawMessage): number {\n return message.info?.time?.created ?? 0;\n}\n\nfunction getAssistantText(parts: AssistantRawMessage['parts']): string {\n return (parts ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text?.trim() ?? '')\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction getToolProgress(parts: AssistantRawMessage['parts']): string[] {\n return (parts ?? [])\n .filter((part) => part.type === 'tool' && part.tool)\n .map((part) => {\n const status = part.state?.status ?? 'running';\n const tool = part.tool ?? 'tool';\n if (status === 'completed') return `Completed: ${tool}`;\n if (status === 'failed') return `Failed: ${tool}`;\n return `Running: ${tool}`;\n });\n}\n\nfunction buildProgress(messages: AssistantRawMessage[], sinceMs: number): { content: string; done: boolean } {\n const relevant = messages\n .filter((message) => message.info?.role === 'assistant' && getRawMessageCreatedAt(message) >= sinceMs)\n .sort((left, right) => getRawMessageCreatedAt(left) - getRawMessageCreatedAt(right));\n\n if (relevant.length === 0) return { content: 'Thinking…', done: false };\n\n const latest = relevant[relevant.length - 1]!;\n const text = getAssistantText(latest.parts);\n const toolProgress = getToolProgress(latest.parts);\n const content = [text, ...toolProgress].filter(Boolean).join('\\n\\n') || 'Thinking…';\n\n return {\n content,\n done: Boolean(latest.info?.time?.completed) && (Boolean(text) || toolProgress.length > 0),\n };\n}\n\nfunction sanitize(response: string): string {\n return response\n .replace(/(Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/(X-Workspace-Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9._-]+\\.[A-Za-z0-9._-]+\\b/g, '[REDACTED_JWT]')\n .replace(/\\bsk-ant-[A-Za-z0-9-]+\\b/g, '[REDACTED_API_KEY]');\n}\n\nfunction isRecoverable(error: unknown): boolean {\n const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n if (\n message.includes('rate limit exceeded') ||\n message.includes('unauthorized') ||\n message.includes('k8s api error 401')\n ) {\n return false;\n }\n return [\n 'sandbox not found',\n 'sandbox is not running',\n 'sandbox service not available yet',\n 'sandbox failed',\n 'sandbox startup timed out',\n 'assistant service did not become healthy',\n 'proxy error: 404',\n 'proxy error: 502',\n 'proxy error: 503',\n ].some((fragment) => message.includes(fragment));\n}\n\n/**\n * Returns a memoized `AssistantTransport` wired to the HousingVista sandbox\n * `api-calls` agent. The sandbox + session are cached in refs so follow-up\n * turns reuse the warm environment for the lifetime of the host shell.\n */\nexport function useSandboxAssistantTransport(): AssistantTransport {\n const apollo = useGatewayClient('workspace');\n const { getAccessToken, getWorkspaceToken, userId } = useAuthToken();\n\n const sandboxIdRef = useRef<string | null>(null);\n const sessionIdRef = useRef<string | null>(null);\n\n const ensureRuntime = useCallback(\n async (\n workspaceId: string,\n authContext: AssistantSandboxAuthContext\n ): Promise<{ sandboxId: string; sessionId: string }> => {\n let sandboxId = sandboxIdRef.current;\n if (!sandboxId) {\n sandboxId = await findExistingSandbox(apollo, workspaceId, MODE, authContext);\n if (!sandboxId) {\n if (!getAccessToken()) {\n throw new Error('API Calls mode requires an authenticated session. Please sign in again.');\n }\n sandboxId = await createAssistantSandbox(apollo, MODE, workspaceId, authContext);\n }\n await waitForSandboxReady(apollo, sandboxId, workspaceId, authContext);\n await waitForAssistantServiceReady(apollo, sandboxId, workspaceId, authContext);\n sandboxIdRef.current = sandboxId;\n }\n\n let sessionId = sessionIdRef.current;\n if (!sessionId) {\n const result = await createAssistantSession(apollo, sandboxId, workspaceId, MODE, authContext);\n sessionId = result.sessionId;\n sessionIdRef.current = sessionId;\n }\n\n return { sandboxId, sessionId };\n },\n [apollo, getAccessToken]\n );\n\n const sendPrompt = useCallback(\n async ({ prompt, onProgress, signal }: AssistantSendArgs): Promise<{ text: string }> => {\n const workspaceId = getWorkspaceId();\n if (!workspaceId) {\n throw new Error('The assistant needs an active workspace. Open a workspace and try again.');\n }\n const authContext: AssistantSandboxAuthContext = {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n userId,\n organizationId: getOrganizationId(),\n };\n\n const run = async (attempt: 1 | 2): Promise<{ text: string }> => {\n try {\n const { sandboxId, sessionId } = await ensureRuntime(workspaceId, authContext);\n\n const startedAt = Date.now();\n await sendAssistantPromptAsync(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n prompt,\n MODE,\n gatherPageContext(),\n authContext\n );\n\n const timeoutAt = Date.now() + STREAM_BUDGET_MS;\n let lastTtlExtensionAt = Date.now();\n let progress = buildProgress([], startedAt);\n\n while (Date.now() < timeoutAt) {\n if (signal.aborted) throw new Error('Cancelled');\n\n const messages = await getAssistantMessages(apollo, sandboxId, workspaceId, sessionId, authContext, 50);\n progress = buildProgress(messages, startedAt);\n onProgress(sanitize(progress.content));\n if (progress.done) break;\n\n if (Date.now() - lastTtlExtensionAt > TTL_EXTEND_INTERVAL_MS) {\n await extendAssistantSandboxTTL(apollo, sandboxId, workspaceId, 600, authContext).catch(() => undefined);\n lastTtlExtensionAt = Date.now();\n }\n\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n\n if (!progress.done) {\n throw new Error('The assistant timed out while responding. Please try again.');\n }\n\n return { text: sanitize(progress.content) };\n } catch (error) {\n // A stale/expired sandbox or session is recoverable — drop the warm\n // refs and retry once from a clean runtime.\n if (attempt === 1 && isRecoverable(error)) {\n sandboxIdRef.current = null;\n sessionIdRef.current = null;\n return run(2);\n }\n throw error;\n }\n };\n\n return run(1);\n },\n [apollo, ensureRuntime, getAccessToken, getWorkspaceToken, userId]\n );\n\n return useMemo<AssistantTransport>(() => ({ sendPrompt }), [sendPrompt]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../../src/housingvista/services/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * housingvista adapter for the shared fe-libs AssistantWidget transport.\n *\n * The sandbox lifecycle + poll/stream loop now lives in\n * `@burdenoff/fe-libs/shared/assistant` (one implementation for all products);\n * this is a thin wrapper. The exported name/shape are unchanged so app-shell\n * imports don't move. The public return type is a LOCALLY-declared structural\n * mirror — never re-export fe-libs types (vite-plugin-dts path rewriting).\n */\n\nimport { useSandboxAssistantTransport as useSharedTransport } from '@burdenoff/fe-libs/shared/assistant';\nimport { gatherPageContext } from '../utils/pageContext';\n\ninterface AssistantSendArgs {\n prompt: string;\n onProgress: (partialText: string) => void;\n signal: AbortSignal;\n}\n\nexport interface AssistantTransport {\n sendPrompt: (args: AssistantSendArgs) => Promise<{ text: string }>;\n prewarm?: (level?: 'probe' | 'full') => void;\n suspend?: () => void;\n}\n\nexport function useSandboxAssistantTransport(): AssistantTransport {\n return useSharedTransport({\n product: 'housingvista',\n gatherPageContext: gatherPageContext,\n enableCredits: true,\n });\n}\n"],"mappings":";;;AAyBA,SAAgB,IAAmD;AACjE,QAAO,EAAmB;EACxB,SAAS;EACU;EACnB,eAAe;EAChB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { EmptyState } from '../housingvista/components/EmptyState';
3
+
4
+ declare const meta: Meta<typeof EmptyState>;
5
+ export default meta;
6
+ type Story = StoryObj<typeof meta>;
7
+ export declare const IconOnly: Story;
8
+ export declare const WithAction: Story;
9
+ export declare const Illustrated: Story;
10
+ //# sourceMappingURL=EmptyState.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.stories.d.ts","sourceRoot":"","sources":["../../src/stories/EmptyState.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AAEnE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,UAAU,CAMjC,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,QAAQ,EAAE,KAMtB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAexB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAMzB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { StatCard } from '../housingvista/components/StatCard';
3
+
4
+ declare const meta: Meta<typeof StatCard>;
5
+ export default meta;
6
+ type Story = StoryObj<typeof meta>;
7
+ export declare const Default: Story;
8
+ export declare const WithTrend: Story;
9
+ export declare const Featured: Story;
10
+ //# sourceMappingURL=StatCard.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatCard.stories.d.ts","sourceRoot":"","sources":["../../src/stories/StatCard.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAE/D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,QAAQ,CAM/B,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KASvB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAWtB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { StatusBadge } from '../housingvista/components/StatusBadge';
3
+
4
+ declare const meta: Meta<typeof StatusBadge>;
5
+ export default meta;
6
+ type Story = StoryObj<typeof meta>;
7
+ export declare const Available: Story;
8
+ export declare const Pending: Story;
9
+ export declare const Sold: Story;
10
+ export declare const Info: Story;
11
+ //# sourceMappingURL=StatusBadge.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBadge.stories.d.ts","sourceRoot":"","sources":["../../src/stories/StatusBadge.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAErE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,WAAW,CAYlC,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAKlB,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAMlB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-housingvista",
3
- "version": "2026.709.3",
3
+ "version": "2026.716.1",
4
4
  "description": "Burdenoff HousingVista Microfrontend - Comprehensive real estate platform for property management, investment, and transactions",
5
5
  "type": "module",
6
6
  "files": [
@@ -40,11 +40,14 @@
40
40
  "switch:local": "bun scripts/deps-mode.ts local",
41
41
  "switch:check": "bun scripts/deps-mode.ts check",
42
42
  "prepare": "lefthook install || true",
43
- "format:check": "prettier --check \"src/**/*.{ts,tsx}\""
43
+ "format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
44
+ "storybook": "storybook dev -p 6006",
45
+ "build-storybook": "storybook build",
46
+ "test:storybook": "test-storybook"
44
47
  },
45
48
  "dependencies": {
46
49
  "@apollo/client": "^4.0.11",
47
- "@burdenoff/fe-libs": "^2026.709.5",
50
+ "@burdenoff/fe-libs": "2026.713.6",
48
51
  "clsx": "^2.1.1",
49
52
  "date-fns": "^4.1.0",
50
53
  "graphql": "^16.12.0",
@@ -66,6 +69,13 @@
66
69
  "@graphql-codegen/typescript": "^4.0.0",
67
70
  "@graphql-codegen/typescript-operations": "^4.0.0",
68
71
  "@graphql-codegen/typescript-react-apollo": "^4.0.0",
72
+ "@storybook/addon-essentials": "^8.6.0",
73
+ "@storybook/addon-interactions": "^8.6.0",
74
+ "@storybook/react": "^8.6.0",
75
+ "@storybook/react-vite": "^8.6.0",
76
+ "@storybook/test": "^8.6.0",
77
+ "@storybook/test-runner": "0.22.0",
78
+ "@tailwindcss/vite": "^4.3.2",
69
79
  "@types/react": "^19.0.2",
70
80
  "@types/react-dom": "^19.0.2",
71
81
  "@vitejs/plugin-react": "^4.3.4",
@@ -76,6 +86,7 @@
76
86
  "lefthook": "^2.1.1",
77
87
  "postcss": "^8.4.49",
78
88
  "prettier": "^3.4.2",
89
+ "storybook": "^8.6.0",
79
90
  "tailwindcss": "^4.0.0",
80
91
  "typescript": "^5.9.0",
81
92
  "typescript-eslint": "^8.46.0",
@@ -1,67 +0,0 @@
1
- import { gql as e } from "@apollo/client";
2
- import "@apollo/client/react";
3
- e`
4
- mutation CheckAiCredits {
5
- checkAiCredits
6
- }
7
- `, e`
8
- mutation ReportAiTokenUsage($input: ReportAiTokenUsageInput!) {
9
- reportAiTokenUsage(input: $input)
10
- }
11
- `;
12
- var t = e`
13
- query GetSandbox($id: ID!, $context: ContextInput!) {
14
- getSandbox(id: $id, context: $context) {
15
- id
16
- status
17
- errorMessage
18
- network {
19
- internalUrl
20
- }
21
- }
22
- }
23
- `, n = e`
24
- query GetActiveSandboxes($context: ContextInput!) {
25
- getActiveSandboxes(context: $context) {
26
- id
27
- name
28
- status
29
- metadata
30
- template
31
- createdBy
32
- }
33
- }
34
- `, r = e`
35
- mutation CreateSandbox($input: CreateSandboxInput!) {
36
- createSandbox(input: $input) {
37
- id
38
- name
39
- status
40
- network {
41
- internalUrl
42
- }
43
- }
44
- }
45
- `, i = e`
46
- mutation ProxySandboxRequest($input: ProxySandboxRequestInput!) {
47
- proxySandboxRequest(input: $input) {
48
- status
49
- body
50
- }
51
- }
52
- `, a = e`
53
- mutation ExtendSandboxTtl($id: ID!, $additionalSeconds: Int!, $context: ContextInput!) {
54
- extendSandboxTTL(
55
- id: $id
56
- additionalSeconds: $additionalSeconds
57
- context: $context
58
- ) {
59
- id
60
- expiresAt
61
- }
62
- }
63
- `;
64
- //#endregion
65
- export { r as CreateSandboxDocument, a as ExtendSandboxTtlDocument, n as GetActiveSandboxesDocument, t as GetSandboxDocument, i as ProxySandboxRequestDocument };
66
-
67
- //# sourceMappingURL=wspace-operations.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"wspace-operations.js","names":[],"sources":["../../src/generated/wspace-operations.ts"],"sourcesContent":["// @ts-nocheck\nimport * as Types from './wspace-types';\n\nimport { gql } from '@apollo/client';\nimport * as Apollo from '@apollo/client';\nimport * as ApolloReactHooks from '@apollo/client/react';\nconst defaultOptions = {} as const;\nexport type CheckAiCreditsMutationVariables = Types.Exact<{ [key: string]: never; }>;\n\n\nexport type CheckAiCreditsMutation = { __typename?: 'Mutation', checkAiCredits: boolean };\n\nexport type ReportAiTokenUsageMutationVariables = Types.Exact<{\n input: Types.ReportAiTokenUsageInput;\n}>;\n\n\nexport type ReportAiTokenUsageMutation = { __typename?: 'Mutation', reportAiTokenUsage: boolean };\n\nexport type GetSandboxQueryVariables = Types.Exact<{\n id: Types.Scalars['ID']['input'];\n context: Types.ContextInput;\n}>;\n\n\nexport type GetSandboxQuery = { __typename?: 'Query', getSandbox?: { __typename?: 'Sandbox', id: string, status: Types.SandboxStatus, errorMessage?: string | null, network: { __typename?: 'SandboxNetwork', internalUrl?: string | null } } | null };\n\nexport type GetActiveSandboxesQueryVariables = Types.Exact<{\n context: Types.ContextInput;\n}>;\n\n\nexport type GetActiveSandboxesQuery = { __typename?: 'Query', getActiveSandboxes: Array<{ __typename?: 'Sandbox', id: string, name: string, status: Types.SandboxStatus, metadata?: Record<string, unknown> | null, template: Types.SandboxTemplate, createdBy: string }> };\n\nexport type CreateSandboxMutationVariables = Types.Exact<{\n input: Types.CreateSandboxInput;\n}>;\n\n\nexport type CreateSandboxMutation = { __typename?: 'Mutation', createSandbox: { __typename?: 'Sandbox', id: string, name: string, status: Types.SandboxStatus, network: { __typename?: 'SandboxNetwork', internalUrl?: string | null } } };\n\nexport type ProxySandboxRequestMutationVariables = Types.Exact<{\n input: Types.ProxySandboxRequestInput;\n}>;\n\n\nexport type ProxySandboxRequestMutation = { __typename?: 'Mutation', proxySandboxRequest: { __typename?: 'ProxySandboxResponse', status: number, body?: Record<string, unknown> | null } };\n\nexport type ExtendSandboxTtlMutationVariables = Types.Exact<{\n id: Types.Scalars['ID']['input'];\n additionalSeconds: Types.Scalars['Int']['input'];\n context: Types.ContextInput;\n}>;\n\n\nexport type ExtendSandboxTtlMutation = { __typename?: 'Mutation', extendSandboxTTL: { __typename?: 'Sandbox', id: string, expiresAt: string } };\n\n\nexport const CheckAiCreditsDocument = gql`\n mutation CheckAiCredits {\n checkAiCredits\n}\n `;\nexport type CheckAiCreditsMutationFn = Apollo.MutationFunction<Types.CheckAiCreditsMutation, Types.CheckAiCreditsMutationVariables>;\n\n/**\n * __useCheckAiCreditsMutation__\n *\n * To run a mutation, you first call `useCheckAiCreditsMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useCheckAiCreditsMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [checkAiCreditsMutation, { data, loading, error }] = useCheckAiCreditsMutation({\n * variables: {\n * },\n * });\n */\nexport function useCheckAiCreditsMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<Types.CheckAiCreditsMutation, Types.CheckAiCreditsMutationVariables>) {\n const options = {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useMutation<Types.CheckAiCreditsMutation, Types.CheckAiCreditsMutationVariables>(CheckAiCreditsDocument, options);\n }\nexport type CheckAiCreditsMutationHookResult = ReturnType<typeof useCheckAiCreditsMutation>;\nexport type CheckAiCreditsMutationResult = Apollo.MutationResult<Types.CheckAiCreditsMutation>;\nexport type CheckAiCreditsMutationOptions = Apollo.BaseMutationOptions<Types.CheckAiCreditsMutation, Types.CheckAiCreditsMutationVariables>;\nexport const ReportAiTokenUsageDocument = gql`\n mutation ReportAiTokenUsage($input: ReportAiTokenUsageInput!) {\n reportAiTokenUsage(input: $input)\n}\n `;\nexport type ReportAiTokenUsageMutationFn = Apollo.MutationFunction<Types.ReportAiTokenUsageMutation, Types.ReportAiTokenUsageMutationVariables>;\n\n/**\n * __useReportAiTokenUsageMutation__\n *\n * To run a mutation, you first call `useReportAiTokenUsageMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useReportAiTokenUsageMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [reportAiTokenUsageMutation, { data, loading, error }] = useReportAiTokenUsageMutation({\n * variables: {\n * input: // value for 'input'\n * },\n * });\n */\nexport function useReportAiTokenUsageMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<Types.ReportAiTokenUsageMutation, Types.ReportAiTokenUsageMutationVariables>) {\n const options = {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useMutation<Types.ReportAiTokenUsageMutation, Types.ReportAiTokenUsageMutationVariables>(ReportAiTokenUsageDocument, options);\n }\nexport type ReportAiTokenUsageMutationHookResult = ReturnType<typeof useReportAiTokenUsageMutation>;\nexport type ReportAiTokenUsageMutationResult = Apollo.MutationResult<Types.ReportAiTokenUsageMutation>;\nexport type ReportAiTokenUsageMutationOptions = Apollo.BaseMutationOptions<Types.ReportAiTokenUsageMutation, Types.ReportAiTokenUsageMutationVariables>;\nexport const GetSandboxDocument = gql`\n query GetSandbox($id: ID!, $context: ContextInput!) {\n getSandbox(id: $id, context: $context) {\n id\n status\n errorMessage\n network {\n internalUrl\n }\n }\n}\n `;\n\n/**\n * __useGetSandboxQuery__\n *\n * To run a query within a React component, call `useGetSandboxQuery` and pass it any options that fit your needs.\n * When your component renders, `useGetSandboxQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useGetSandboxQuery({\n * variables: {\n * id: // value for 'id'\n * context: // value for 'context'\n * },\n * });\n */\nexport function useGetSandboxQuery(baseOptions: ApolloReactHooks.QueryHookOptions<Types.GetSandboxQuery, Types.GetSandboxQueryVariables> & ({ variables: Types.GetSandboxQueryVariables; skip?: boolean; } | { skip: boolean; }) ) {\n const options = {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useQuery<Types.GetSandboxQuery, Types.GetSandboxQueryVariables>(GetSandboxDocument, options);\n }\nexport function useGetSandboxLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.GetSandboxQuery, Types.GetSandboxQueryVariables>) {\n const options = {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useLazyQuery<Types.GetSandboxQuery, Types.GetSandboxQueryVariables>(GetSandboxDocument, options);\n }\n// @ts-ignore\nexport function useGetSandboxSuspenseQuery(baseOptions?: ApolloReactHooks.SuspenseQueryHookOptions<Types.GetSandboxQuery, Types.GetSandboxQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.GetSandboxQuery, Types.GetSandboxQueryVariables>;\nexport function useGetSandboxSuspenseQuery(baseOptions?: ApolloReactHooks.SkipToken | ApolloReactHooks.SuspenseQueryHookOptions<Types.GetSandboxQuery, Types.GetSandboxQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.GetSandboxQuery | undefined, Types.GetSandboxQueryVariables>;\nexport function useGetSandboxSuspenseQuery(baseOptions?: ApolloReactHooks.SkipToken | ApolloReactHooks.SuspenseQueryHookOptions<Types.GetSandboxQuery, Types.GetSandboxQueryVariables>) {\n const options = baseOptions === ApolloReactHooks.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useSuspenseQuery<Types.GetSandboxQuery, Types.GetSandboxQueryVariables>(GetSandboxDocument, options);\n }\nexport type GetSandboxQueryHookResult = ReturnType<typeof useGetSandboxQuery>;\nexport type GetSandboxLazyQueryHookResult = ReturnType<typeof useGetSandboxLazyQuery>;\nexport type GetSandboxSuspenseQueryHookResult = ReturnType<typeof useGetSandboxSuspenseQuery>;\nexport type GetSandboxQueryResult = Apollo.QueryResult<Types.GetSandboxQuery, Types.GetSandboxQueryVariables>;\nexport const GetActiveSandboxesDocument = gql`\n query GetActiveSandboxes($context: ContextInput!) {\n getActiveSandboxes(context: $context) {\n id\n name\n status\n metadata\n template\n createdBy\n }\n}\n `;\n\n/**\n * __useGetActiveSandboxesQuery__\n *\n * To run a query within a React component, call `useGetActiveSandboxesQuery` and pass it any options that fit your needs.\n * When your component renders, `useGetActiveSandboxesQuery` returns an object from Apollo Client that contains loading, error, and data properties\n * you can use to render your UI.\n *\n * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;\n *\n * @example\n * const { data, loading, error } = useGetActiveSandboxesQuery({\n * variables: {\n * context: // value for 'context'\n * },\n * });\n */\nexport function useGetActiveSandboxesQuery(baseOptions: ApolloReactHooks.QueryHookOptions<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables> & ({ variables: Types.GetActiveSandboxesQueryVariables; skip?: boolean; } | { skip: boolean; }) ) {\n const options = {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useQuery<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables>(GetActiveSandboxesDocument, options);\n }\nexport function useGetActiveSandboxesLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables>) {\n const options = {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useLazyQuery<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables>(GetActiveSandboxesDocument, options);\n }\n// @ts-ignore\nexport function useGetActiveSandboxesSuspenseQuery(baseOptions?: ApolloReactHooks.SuspenseQueryHookOptions<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables>;\nexport function useGetActiveSandboxesSuspenseQuery(baseOptions?: ApolloReactHooks.SkipToken | ApolloReactHooks.SuspenseQueryHookOptions<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.GetActiveSandboxesQuery | undefined, Types.GetActiveSandboxesQueryVariables>;\nexport function useGetActiveSandboxesSuspenseQuery(baseOptions?: ApolloReactHooks.SkipToken | ApolloReactHooks.SuspenseQueryHookOptions<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables>) {\n const options = baseOptions === ApolloReactHooks.skipToken ? baseOptions : {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useSuspenseQuery<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables>(GetActiveSandboxesDocument, options);\n }\nexport type GetActiveSandboxesQueryHookResult = ReturnType<typeof useGetActiveSandboxesQuery>;\nexport type GetActiveSandboxesLazyQueryHookResult = ReturnType<typeof useGetActiveSandboxesLazyQuery>;\nexport type GetActiveSandboxesSuspenseQueryHookResult = ReturnType<typeof useGetActiveSandboxesSuspenseQuery>;\nexport type GetActiveSandboxesQueryResult = Apollo.QueryResult<Types.GetActiveSandboxesQuery, Types.GetActiveSandboxesQueryVariables>;\nexport const CreateSandboxDocument = gql`\n mutation CreateSandbox($input: CreateSandboxInput!) {\n createSandbox(input: $input) {\n id\n name\n status\n network {\n internalUrl\n }\n }\n}\n `;\nexport type CreateSandboxMutationFn = Apollo.MutationFunction<Types.CreateSandboxMutation, Types.CreateSandboxMutationVariables>;\n\n/**\n * __useCreateSandboxMutation__\n *\n * To run a mutation, you first call `useCreateSandboxMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useCreateSandboxMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [createSandboxMutation, { data, loading, error }] = useCreateSandboxMutation({\n * variables: {\n * input: // value for 'input'\n * },\n * });\n */\nexport function useCreateSandboxMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<Types.CreateSandboxMutation, Types.CreateSandboxMutationVariables>) {\n const options = {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useMutation<Types.CreateSandboxMutation, Types.CreateSandboxMutationVariables>(CreateSandboxDocument, options);\n }\nexport type CreateSandboxMutationHookResult = ReturnType<typeof useCreateSandboxMutation>;\nexport type CreateSandboxMutationResult = Apollo.MutationResult<Types.CreateSandboxMutation>;\nexport type CreateSandboxMutationOptions = Apollo.BaseMutationOptions<Types.CreateSandboxMutation, Types.CreateSandboxMutationVariables>;\nexport const ProxySandboxRequestDocument = gql`\n mutation ProxySandboxRequest($input: ProxySandboxRequestInput!) {\n proxySandboxRequest(input: $input) {\n status\n body\n }\n}\n `;\nexport type ProxySandboxRequestMutationFn = Apollo.MutationFunction<Types.ProxySandboxRequestMutation, Types.ProxySandboxRequestMutationVariables>;\n\n/**\n * __useProxySandboxRequestMutation__\n *\n * To run a mutation, you first call `useProxySandboxRequestMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useProxySandboxRequestMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [proxySandboxRequestMutation, { data, loading, error }] = useProxySandboxRequestMutation({\n * variables: {\n * input: // value for 'input'\n * },\n * });\n */\nexport function useProxySandboxRequestMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<Types.ProxySandboxRequestMutation, Types.ProxySandboxRequestMutationVariables>) {\n const options = {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useMutation<Types.ProxySandboxRequestMutation, Types.ProxySandboxRequestMutationVariables>(ProxySandboxRequestDocument, options);\n }\nexport type ProxySandboxRequestMutationHookResult = ReturnType<typeof useProxySandboxRequestMutation>;\nexport type ProxySandboxRequestMutationResult = Apollo.MutationResult<Types.ProxySandboxRequestMutation>;\nexport type ProxySandboxRequestMutationOptions = Apollo.BaseMutationOptions<Types.ProxySandboxRequestMutation, Types.ProxySandboxRequestMutationVariables>;\nexport const ExtendSandboxTtlDocument = gql`\n mutation ExtendSandboxTtl($id: ID!, $additionalSeconds: Int!, $context: ContextInput!) {\n extendSandboxTTL(\n id: $id\n additionalSeconds: $additionalSeconds\n context: $context\n ) {\n id\n expiresAt\n }\n}\n `;\nexport type ExtendSandboxTtlMutationFn = Apollo.MutationFunction<Types.ExtendSandboxTtlMutation, Types.ExtendSandboxTtlMutationVariables>;\n\n/**\n * __useExtendSandboxTtlMutation__\n *\n * To run a mutation, you first call `useExtendSandboxTtlMutation` within a React component and pass it any options that fit your needs.\n * When your component renders, `useExtendSandboxTtlMutation` returns a tuple that includes:\n * - A mutate function that you can call at any time to execute the mutation\n * - An object with fields that represent the current status of the mutation's execution\n *\n * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;\n *\n * @example\n * const [extendSandboxTtlMutation, { data, loading, error }] = useExtendSandboxTtlMutation({\n * variables: {\n * id: // value for 'id'\n * additionalSeconds: // value for 'additionalSeconds'\n * context: // value for 'context'\n * },\n * });\n */\nexport function useExtendSandboxTtlMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<Types.ExtendSandboxTtlMutation, Types.ExtendSandboxTtlMutationVariables>) {\n const options = {...defaultOptions, ...baseOptions}\n return ApolloReactHooks.useMutation<Types.ExtendSandboxTtlMutation, Types.ExtendSandboxTtlMutationVariables>(ExtendSandboxTtlDocument, options);\n }\nexport type ExtendSandboxTtlMutationHookResult = ReturnType<typeof useExtendSandboxTtlMutation>;\nexport type ExtendSandboxTtlMutationResult = Apollo.MutationResult<Types.ExtendSandboxTtlMutation>;\nexport type ExtendSandboxTtlMutationOptions = Apollo.BaseMutationOptions<Types.ExtendSandboxTtlMutation, Types.ExtendSandboxTtlMutationVariables>;"],"mappings":";;AA0DsC,CAAG;;;;OA8BC,CAAG;;;;;AA+B7C,IAAa,IAAqB,CAAG;;;;;;;;;;;OAiDxB,IAA6B,CAAG;;;;;;;;;;;OAgDhC,IAAwB,CAAG;;;;;;;;;;;OAsC3B,IAA8B,CAAG;;;;;;;OAkCjC,IAA2B,CAAG"}
@@ -1,90 +0,0 @@
1
- import { ApolloClient } from '@apollo/client';
2
- import { AssistantArtifact, AssistantMode } from '../types/assistant';
3
- import { PageContext } from '../utils/pageContext';
4
-
5
- export interface AssistantPromptResult {
6
- response: string;
7
- tokens?: {
8
- input: number;
9
- output: number;
10
- };
11
- artifacts?: AssistantArtifact[];
12
- }
13
- export interface AssistantRawMessagePart {
14
- type?: string;
15
- text?: string;
16
- tool?: string;
17
- state?: {
18
- status?: string;
19
- input?: unknown;
20
- output?: unknown;
21
- raw?: unknown;
22
- };
23
- }
24
- export interface AssistantRawMessage {
25
- info?: {
26
- id?: string;
27
- role?: string;
28
- providerID?: string;
29
- modelID?: string;
30
- tokens?: {
31
- input: number;
32
- output: number;
33
- };
34
- time?: {
35
- created?: number;
36
- completed?: number;
37
- };
38
- };
39
- parts?: AssistantRawMessagePart[];
40
- }
41
- export interface AssistantSandboxAuthContext {
42
- accessToken?: string | null;
43
- workspaceToken?: string | null;
44
- userId?: string | null;
45
- organizationId?: string | null;
46
- }
47
- export interface AssistantSessionInfo {
48
- id: string;
49
- mode: string;
50
- }
51
- export interface DownloadedAssistantArtifact {
52
- filename: string;
53
- mimeType: string;
54
- contentBase64: string;
55
- }
56
- export declare function findExistingSandbox(_apollo: ApolloClient, workspaceId: string, mode: AssistantMode, authContext?: AssistantSandboxAuthContext): Promise<string | null>;
57
- export declare function createAssistantSandbox(_apollo: ApolloClient, mode: AssistantMode, workspaceId: string, authContext?: AssistantSandboxAuthContext): Promise<string>;
58
- export declare function waitForSandboxReady(_apollo: ApolloClient, sandboxId: string, workspaceId: string, authContext?: AssistantSandboxAuthContext, maxWaitMs?: number, onProgress?: (message: string) => void): Promise<void>;
59
- export declare function waitForAssistantServiceReady(apollo: ApolloClient, sandboxId: string, workspaceId: string, authContext?: AssistantSandboxAuthContext, maxWaitMs?: number, onProgress?: (message: string) => void): Promise<void>;
60
- export declare function createAssistantSession(apollo: ApolloClient, sandboxId: string, workspaceId: string, mode: AssistantMode, authContext?: AssistantSandboxAuthContext): Promise<{
61
- sessionId: string;
62
- }>;
63
- export declare function getAssistantSession(apollo: ApolloClient, sandboxId: string, workspaceId: string, sessionId: string, authContext?: AssistantSandboxAuthContext): Promise<AssistantSessionInfo>;
64
- export declare function sendAssistantPrompt(apollo: ApolloClient, sandboxId: string, workspaceId: string, sessionId: string, prompt: string, mode: AssistantMode, pageContext?: PageContext, authContext?: AssistantSandboxAuthContext): Promise<AssistantPromptResult>;
65
- export declare function sendAssistantPromptAsync(apollo: ApolloClient, sandboxId: string, workspaceId: string, sessionId: string, prompt: string, mode: AssistantMode, pageContext?: PageContext, authContext?: AssistantSandboxAuthContext): Promise<void>;
66
- export declare function getAssistantMessages(apollo: ApolloClient, sandboxId: string, workspaceId: string, sessionId: string, authContext?: AssistantSandboxAuthContext, limit?: number): Promise<AssistantRawMessage[]>;
67
- /**
68
- * Pre-flight AI-credit gate. Resolves to `true` when the caller still has
69
- * AI-credit budget; throws a quota error (HTTP 429 / QUOTA_EXHAUSTED, from
70
- * the wspace gateway's @usage check) when the monthly token budget is
71
- * depleted. Detect the rejection with `isQuotaExhaustedError()`.
72
- */
73
- export declare function checkAssistantAiCredits(_apollo: ApolloClient, workspaceId: string, authContext?: AssistantSandboxAuthContext): Promise<boolean>;
74
- /**
75
- * Post-turn charge. Reports the turn's raw input/output token counts + the
76
- * model so the svc computes COST-WEIGHTED credits server-side and charges them
77
- * against the product's AI credits. `messageId` makes the charge idempotent
78
- * (retries don't double-charge). No-ops when there are no tokens, or when the
79
- * model is unknown (the charge requires it). Best-effort — callers must not
80
- * block the displayed answer on it.
81
- */
82
- export declare function reportAssistantAiTokenUsage(_apollo: ApolloClient, workspaceId: string, sessionId: string, messageId: string, model: string | undefined, tokens: {
83
- input: number;
84
- output: number;
85
- }, authContext?: AssistantSandboxAuthContext): Promise<void>;
86
- export declare function getAssistantArtifacts(apollo: ApolloClient, sandboxId: string, workspaceId: string, sessionId: string, authContext?: AssistantSandboxAuthContext): Promise<AssistantArtifact[]>;
87
- export declare function downloadAssistantArtifact(apollo: ApolloClient, sandboxId: string, workspaceId: string, sessionId: string, artifactPath: string, authContext?: AssistantSandboxAuthContext): Promise<DownloadedAssistantArtifact>;
88
- export declare function sendHeartbeat(apollo: ApolloClient, sandboxId: string, workspaceId: string, sessionId: string, authContext?: AssistantSandboxAuthContext): Promise<void>;
89
- export declare function extendAssistantSandboxTTL(_apollo: ApolloClient, sandboxId: string, workspaceId: string, additionalSeconds?: number, authContext?: AssistantSandboxAuthContext): Promise<void>;
90
- //# sourceMappingURL=assistantApi.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"assistantApi.d.ts","sourceRoot":"","sources":["../../../src/housingvista/services/assistantApi.ts"],"names":[],"mappings":"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"}
@@ -1,222 +0,0 @@
1
- import { CreateSandboxDocument as e, ExtendSandboxTtlDocument as t, GetActiveSandboxesDocument as n, GetSandboxDocument as r, ProxySandboxRequestDocument as i } from "../../generated/wspace-operations.js";
2
- import { print as a } from "graphql";
3
- //#region src/housingvista/services/assistantApi.ts
4
- var o = "burdenoffregistry.azurecr.io", s = "alpha-proxy-auth-v1", c = "alpha-delegated-auth-v11", l = "sandbox-app-client-headers-v1";
5
- function u(e) {
6
- switch (e) {
7
- case "general": return s;
8
- case "assistant":
9
- case "api-calls": return c;
10
- case "vibe-plugins": return s;
11
- }
12
- }
13
- function d(e) {
14
- return `${o}/wspace/ai-assistant-${e === "assistant" ? "api-calls" : e}:${u(e)}`;
15
- }
16
- function f(e) {
17
- switch (e) {
18
- case "general": return {
19
- cpuRequest: "100m",
20
- cpuLimit: "500m",
21
- memoryRequest: "256Mi",
22
- memoryLimit: "1Gi"
23
- };
24
- case "vibe-plugins": return {
25
- cpuRequest: "150m",
26
- cpuLimit: "750m",
27
- memoryRequest: "384Mi",
28
- memoryLimit: "1536Mi"
29
- };
30
- case "assistant":
31
- case "api-calls": return {
32
- cpuRequest: "150m",
33
- cpuLimit: "750m",
34
- memoryRequest: "384Mi",
35
- memoryLimit: "1536Mi"
36
- };
37
- }
38
- }
39
- function p(e) {
40
- let t = e.metadata?.assistantMode;
41
- if (t === "assistant" || t === "general" || t === "api-calls" || t === "vibe-plugins") return t;
42
- let n = e.name ?? "";
43
- return n.startsWith("ai-assistant-vibe-plugins-") ? "vibe-plugins" : n.startsWith("ai-assistant-api-calls-") ? "api-calls" : n.startsWith("ai-assistant-general-") ? "general" : n.startsWith("ai-assistant-assistant-") ? "assistant" : null;
44
- }
45
- function m(e, t) {
46
- let n = {};
47
- return t?.accessToken && (n.authorization = `Bearer ${t.accessToken}`), t?.workspaceToken && (n["x-workspace-authorization"] = `Bearer ${t.workspaceToken}`), e && (n["x-workspace-id"] = e), t?.userId && (n["x-actor-id"] = t.userId, n["x-actor-type"] = "user"), t?.organizationId && (n["x-org-id"] = t.organizationId), Object.keys(n).length > 0 ? { headers: n } : void 0;
48
- }
49
- function h(e, t) {
50
- return {
51
- workspaceId: e,
52
- ...t?.organizationId ? { custom: { organizationId: t.organizationId } } : {}
53
- };
54
- }
55
- async function g(e) {
56
- let t = await fetch("/workspaces/graphql", {
57
- method: "POST",
58
- headers: {
59
- "Content-Type": "application/json",
60
- ...m(e.workspaceId, e.authContext)?.headers ?? {}
61
- },
62
- body: JSON.stringify({
63
- query: a(e.document),
64
- variables: e.variables
65
- })
66
- }), n = await t.json().catch(() => null);
67
- if (!t.ok) {
68
- let e = n?.errors?.map((e) => e.message).join(", "), r = Error(e || `Sandbox GraphQL HTTP ${t.status}`);
69
- throw r.statusCode = t.status, r.result = n ?? void 0, r;
70
- }
71
- if (!n) throw Error("Sandbox GraphQL returned empty response");
72
- if (n.errors?.length) throw Error(n.errors.map((e) => e.message).join(", "));
73
- if (!n.data) throw Error("Sandbox GraphQL returned no data");
74
- return n.data;
75
- }
76
- async function _(e, t, r, i) {
77
- return ((await g({
78
- document: n,
79
- variables: { context: h(t, i) },
80
- workspaceId: t,
81
- authContext: i
82
- })).getActiveSandboxes ?? []).find((e) => (e.status === "RUNNING" || e.status === "PROVISIONING" || e.status === "PENDING") && e.template === "AI_BUILDER" && p(e) === r && (!i?.userId || e.createdBy === i.userId) && e.metadata?.authStrategy === l && e.metadata?.imageTag === u(r))?.id ?? null;
83
- }
84
- async function v(t, n, r, i) {
85
- let a = f(n), o = [
86
- {
87
- name: "AI_ASSISTANT_MODE",
88
- value: n
89
- },
90
- {
91
- name: "HOSTNAME",
92
- value: "0.0.0.0"
93
- },
94
- {
95
- name: "WORKSPACE_ID",
96
- value: r
97
- },
98
- {
99
- name: "AI_ASSISTANT_PRODUCT",
100
- value: "housingvista"
101
- }
102
- ], s = await g({
103
- document: e,
104
- variables: { input: {
105
- name: `ai-assistant-${n}-${Date.now()}`,
106
- description: `AI Assistant sandbox (${n} mode)`,
107
- template: "AI_BUILDER",
108
- mode: "DEPLOYMENT",
109
- containers: [{
110
- name: "ai-assistant",
111
- image: d(n),
112
- ports: [{
113
- containerPort: 8080,
114
- name: "http"
115
- }],
116
- env: o
117
- }],
118
- resources: {
119
- cpuRequest: a.cpuRequest,
120
- cpuLimit: a.cpuLimit,
121
- memoryRequest: a.memoryRequest,
122
- memoryLimit: a.memoryLimit
123
- },
124
- ttlSeconds: 600,
125
- metadata: {
126
- assistantMode: n,
127
- assistantOwnerUserId: i?.userId ?? null,
128
- assistantOrganizationId: i?.organizationId ?? null,
129
- authStrategy: l,
130
- imageTag: u(n)
131
- },
132
- context: h(r, i)
133
- } },
134
- workspaceId: r,
135
- authContext: i
136
- });
137
- if (!s?.createSandbox?.id) throw Error("createSandbox returned empty response");
138
- return s.createSandbox.id;
139
- }
140
- async function y(e, t, n, i, a = 3e5, o) {
141
- let s = Date.now();
142
- for (; Date.now() - s < a;) {
143
- let e = await g({
144
- document: r,
145
- variables: {
146
- id: t,
147
- context: h(n, i)
148
- },
149
- workspaceId: n,
150
- authContext: i
151
- }), a = e?.getSandbox?.status, c = e?.getSandbox?.errorMessage;
152
- if (a === "RUNNING") return;
153
- if (a === "FAILED" || a === "STOPPED" || a === "EXPIRED") throw Error(c ? `Sandbox ${a.toLowerCase()}: ${c}` : `Sandbox ${a.toLowerCase()}`);
154
- let l = Math.max(1, Math.round((Date.now() - s) / 1e3));
155
- o?.(`Starting assistant environment... (${l}s)`), await new Promise((e) => setTimeout(e, 2e3));
156
- }
157
- throw Error("Sandbox startup timed out");
158
- }
159
- async function b(e, t, n, r, a, o, s) {
160
- let c = (await g({
161
- document: i,
162
- variables: { input: {
163
- sandboxId: t,
164
- path: r,
165
- method: a,
166
- body: o,
167
- context: h(n, s)
168
- } },
169
- workspaceId: n,
170
- authContext: s
171
- })).proxySandboxRequest;
172
- if (!c || c.status >= 400) {
173
- let e = c?.body;
174
- throw Error(e?.error ?? `Proxy error: ${c?.status ?? "unknown"}`);
175
- }
176
- return c.body;
177
- }
178
- async function x(e, t, n, r, i = 9e4, a) {
179
- let o = Date.now();
180
- for (; Date.now() - o < i;) {
181
- try {
182
- await b(e, t, n, "/health", "GET", void 0, r);
183
- return;
184
- } catch (e) {
185
- let t = e instanceof Error ? e.message : String(e);
186
- if (!/proxy error: 502|proxy error: 503|proxy error: 404|service not available/i.test(t)) throw e;
187
- }
188
- let i = Math.max(1, Math.round((Date.now() - o) / 1e3));
189
- a?.(`Connecting to assistant... (${i}s)`), await new Promise((e) => setTimeout(e, 2e3));
190
- }
191
- throw Error("Assistant service did not become healthy before timeout");
192
- }
193
- async function S(e, t, n, r, i) {
194
- return { sessionId: (await b(e, t, n, "/sessions", "POST", { mode: r }, i)).session.id };
195
- }
196
- async function C(e, t, n, r, i, a, o, s) {
197
- let c = {
198
- mode: a,
199
- prompt: i,
200
- pageContext: o ?? void 0
201
- };
202
- await b(e, t, n, `/sessions/${r}/prompt-async`, "POST", c, s);
203
- }
204
- async function w(e, t, n, r, i, a = 50) {
205
- return (await b(e, t, n, `/sessions/${r}/messages?limit=${a}`, "GET", void 0, i)).messages ?? [];
206
- }
207
- async function T(e, n, r, i = 600, a) {
208
- await g({
209
- document: t,
210
- variables: {
211
- id: n,
212
- additionalSeconds: i,
213
- context: h(r, a)
214
- },
215
- workspaceId: r,
216
- authContext: a
217
- });
218
- }
219
- //#endregion
220
- export { v as createAssistantSandbox, S as createAssistantSession, T as extendAssistantSandboxTTL, _ as findExistingSandbox, w as getAssistantMessages, C as sendAssistantPromptAsync, x as waitForAssistantServiceReady, y as waitForSandboxReady };
221
-
222
- //# sourceMappingURL=assistantApi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"assistantApi.js","names":[],"sources":["../../../src/housingvista/services/assistantApi.ts"],"sourcesContent":["/**\n * AI Assistant API service.\n *\n * All requests go through the wspace-public-gateway (GraphQL Federation):\n * Frontend → wspace-public-gateway → wspace-sandbox-svc → ai-assistant container\n *\n * Uses the host app's Apollo Client which already points to the gateway.\n */\n\nimport { type ApolloClient } from '@apollo/client';\nimport { print, type DocumentNode } from 'graphql';\nimport type { AssistantArtifact, AssistantMode } from '../types/assistant';\nimport type { PageContext } from '../utils/pageContext';\nimport {\n CreateSandboxDocument,\n GetSandboxDocument,\n GetActiveSandboxesDocument,\n ProxySandboxRequestDocument,\n ExtendSandboxTtlDocument,\n CheckAiCreditsDocument,\n ReportAiTokenUsageDocument,\n} from '#src/generated/wspace-operations';\n\n// ── Image registry ─────────────────────────────────────────────────\n\nconst CONTAINER_REGISTRY = 'burdenoffregistry.azurecr.io';\nconst DEFAULT_IMAGE_TAG = import.meta.env.VITE_APP_ENV === 'prod' ? 'prod' : 'alpha';\nconst GENERAL_IMAGE_TAG = import.meta.env.VITE_APP_ENV === 'prod' ? 'prod' : 'alpha-proxy-auth-v1';\nconst API_CALLS_IMAGE_TAG = import.meta.env.VITE_APP_ENV === 'prod' ? 'prod' : 'alpha-delegated-auth-v11';\nconst ASSISTANT_API_AUTH_STRATEGY = 'sandbox-app-client-headers-v1';\n\nfunction getImageTagForMode(mode: AssistantMode): string {\n switch (mode) {\n case 'general':\n return GENERAL_IMAGE_TAG;\n // The combined default mode runs in the api-calls image (it can make calls).\n case 'assistant':\n case 'api-calls':\n return API_CALLS_IMAGE_TAG;\n case 'vibe-plugins':\n return GENERAL_IMAGE_TAG;\n }\n}\n\nfunction getImageForMode(mode: AssistantMode): string {\n // `assistant` reuses the api-calls image — one image, mode selected at runtime\n // via AI_ASSISTANT_MODE. So the image segment is api-calls for both.\n const imageMode = mode === 'assistant' ? 'api-calls' : mode;\n return `${CONTAINER_REGISTRY}/wspace/ai-assistant-${imageMode}:${getImageTagForMode(mode)}`;\n}\n\nfunction getResourcesForMode(mode: AssistantMode): {\n cpuRequest: string;\n cpuLimit: string;\n memoryRequest: string;\n memoryLimit: string;\n} {\n switch (mode) {\n case 'general':\n return {\n cpuRequest: '100m',\n cpuLimit: '500m',\n memoryRequest: '256Mi',\n memoryLimit: '1Gi',\n };\n case 'vibe-plugins':\n return {\n cpuRequest: '150m',\n cpuLimit: '750m',\n memoryRequest: '384Mi',\n memoryLimit: '1536Mi',\n };\n case 'assistant':\n case 'api-calls':\n return {\n cpuRequest: '150m',\n cpuLimit: '750m',\n memoryRequest: '384Mi',\n memoryLimit: '1536Mi',\n };\n }\n}\n\nfunction resolveSandboxAssistantMode(sandbox: {\n metadata: Record<string, unknown> | null;\n name?: string | null;\n}): AssistantMode | null {\n const metadataMode = sandbox.metadata?.assistantMode;\n if (\n metadataMode === 'assistant' ||\n metadataMode === 'general' ||\n metadataMode === 'api-calls' ||\n metadataMode === 'vibe-plugins'\n ) {\n return metadataMode;\n }\n\n const name = sandbox.name ?? '';\n if (name.startsWith('ai-assistant-vibe-plugins-')) return 'vibe-plugins';\n if (name.startsWith('ai-assistant-api-calls-')) return 'api-calls';\n if (name.startsWith('ai-assistant-general-')) return 'general';\n if (name.startsWith('ai-assistant-assistant-')) return 'assistant';\n return null;\n}\n\n// ── Types ───────────────────────────────────────────────────────────\n\nexport interface AssistantPromptResult {\n response: string;\n tokens?: { input: number; output: number };\n artifacts?: AssistantArtifact[];\n}\n\nexport interface AssistantRawMessagePart {\n type?: string;\n text?: string;\n tool?: string;\n state?: {\n status?: string;\n input?: unknown;\n output?: unknown;\n raw?: unknown;\n };\n}\n\nexport interface AssistantRawMessage {\n info?: {\n id?: string;\n role?: string;\n providerID?: string;\n modelID?: string;\n tokens?: { input: number; output: number };\n time?: {\n created?: number;\n completed?: number;\n };\n };\n parts?: AssistantRawMessagePart[];\n}\n\nexport interface AssistantSandboxAuthContext {\n accessToken?: string | null;\n workspaceToken?: string | null;\n userId?: string | null;\n organizationId?: string | null;\n}\n\nexport interface AssistantSessionInfo {\n id: string;\n mode: string;\n}\n\ninterface GraphQLResponse<TData> {\n data?: TData;\n errors?: Array<{ message: string }>;\n}\n\nexport interface DownloadedAssistantArtifact {\n filename: string;\n mimeType: string;\n contentBase64: string;\n}\n\ninterface ProxyResponse {\n proxySandboxRequest: {\n status: number;\n body: Record<string, unknown>;\n };\n}\n\nfunction getGatewayRequestContext(\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): { headers?: Record<string, string> } | undefined {\n const headers: Record<string, string> = {};\n\n if (authContext?.accessToken) {\n headers.authorization = `Bearer ${authContext.accessToken}`;\n }\n\n if (authContext?.workspaceToken) {\n headers['x-workspace-authorization'] = `Bearer ${authContext.workspaceToken}`;\n }\n\n if (workspaceId) {\n headers['x-workspace-id'] = workspaceId;\n }\n\n if (authContext?.userId) {\n headers['x-actor-id'] = authContext.userId;\n headers['x-actor-type'] = 'user';\n }\n\n if (authContext?.organizationId) {\n headers['x-org-id'] = authContext.organizationId;\n }\n\n return Object.keys(headers).length > 0 ? { headers } : undefined;\n}\n\nfunction buildSandboxContextInput(\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): Record<string, unknown> {\n return {\n workspaceId,\n ...(authContext?.organizationId\n ? {\n custom: {\n organizationId: authContext.organizationId,\n },\n }\n : {}),\n };\n}\n\nasync function executeSandboxGraphQL<TData>(params: {\n document: DocumentNode;\n variables: Record<string, unknown>;\n workspaceId: string;\n authContext?: AssistantSandboxAuthContext;\n}): Promise<TData> {\n const response = await fetch('/workspaces/graphql', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(getGatewayRequestContext(params.workspaceId, params.authContext)?.headers ?? {}),\n },\n body: JSON.stringify({\n query: print(params.document),\n variables: params.variables,\n }),\n });\n\n const result = (await response.json().catch(() => null)) as GraphQLResponse<TData> | null;\n\n if (!response.ok) {\n // Preserve the HTTP status and parsed body so quota detection works.\n // The wspace public gateway returns 429 + errors[].extensions.code =\n // QUOTA_EXHAUSTED for @usage limits (createSandbox, checkAiCredits, …);\n // a bare `HTTP 429` Error would be invisible to isQuotaExhaustedError.\n const messages = result?.errors?.map((error: { message: string }) => error.message).join(', ');\n const httpError = new Error(messages || `Sandbox GraphQL HTTP ${response.status}`) as Error & {\n statusCode?: number;\n result?: unknown;\n };\n httpError.statusCode = response.status;\n httpError.result = result ?? undefined;\n throw httpError;\n }\n\n if (!result) {\n throw new Error('Sandbox GraphQL returned empty response');\n }\n\n if (result.errors?.length) {\n throw new Error(result.errors.map((error: { message: string }) => error.message).join(', '));\n }\n\n if (!result.data) {\n throw new Error('Sandbox GraphQL returned no data');\n }\n\n return result.data;\n}\n\n// ── Find existing sandbox for a mode ───────────────────────────────\n\nexport async function findExistingSandbox(\n _apollo: ApolloClient,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: AssistantSandboxAuthContext\n): Promise<string | null> {\n const data = await executeSandboxGraphQL<{\n getActiveSandboxes: Array<{\n id: string;\n name: string;\n status: string;\n metadata: Record<string, unknown> | null;\n template: string;\n createdBy: string;\n }>;\n }>({\n document: GetActiveSandboxesDocument,\n variables: { context: buildSandboxContextInput(workspaceId, authContext) },\n workspaceId,\n authContext,\n });\n const sandboxes = data.getActiveSandboxes ?? [];\n\n return (\n sandboxes.find(\n (s) =>\n (s.status === 'RUNNING' || s.status === 'PROVISIONING' || s.status === 'PENDING') &&\n s.template === 'AI_BUILDER' &&\n resolveSandboxAssistantMode(s) === mode &&\n (!authContext?.userId || s.createdBy === authContext.userId) &&\n s.metadata?.authStrategy === ASSISTANT_API_AUTH_STRATEGY &&\n s.metadata?.imageTag === getImageTagForMode(mode)\n )?.id ?? null\n );\n}\n\n// ── Sandbox lifecycle ──────────────────────────────────────────────\n\nexport async function createAssistantSandbox(\n _apollo: ApolloClient,\n mode: AssistantMode,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<string> {\n const resources = getResourcesForMode(mode);\n const env = [\n { name: 'AI_ASSISTANT_MODE', value: mode },\n { name: 'HOSTNAME', value: '0.0.0.0' },\n { name: 'WORKSPACE_ID', value: workspaceId },\n // Product the user is in — drives the agent's dynamic per-product docs fetch\n // (the docs repo is `<product>-docs`). Not a secret. This package is the\n // HousingVista MFE, so the product is housingvista.\n { name: 'AI_ASSISTANT_PRODUCT', value: 'housingvista' },\n ];\n\n const data = await executeSandboxGraphQL<{ createSandbox: { id: string } }>({\n document: CreateSandboxDocument,\n variables: {\n input: {\n name: `ai-assistant-${mode}-${Date.now()}`,\n description: `AI Assistant sandbox (${mode} mode)`,\n template: 'AI_BUILDER',\n mode: 'DEPLOYMENT',\n containers: [\n {\n name: 'ai-assistant',\n image: getImageForMode(mode),\n // The agent binds :8080; the sandbox svc proxies to this declared\n // containerPort, so it MUST be 8080.\n ports: [{ containerPort: 8080, name: 'http' }],\n env,\n },\n ],\n resources: {\n cpuRequest: resources.cpuRequest,\n cpuLimit: resources.cpuLimit,\n memoryRequest: resources.memoryRequest,\n memoryLimit: resources.memoryLimit,\n },\n ttlSeconds: 600,\n metadata: {\n assistantMode: mode,\n assistantOwnerUserId: authContext?.userId ?? null,\n assistantOrganizationId: authContext?.organizationId ?? null,\n authStrategy: ASSISTANT_API_AUTH_STRATEGY,\n imageTag: getImageTagForMode(mode),\n },\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n },\n workspaceId,\n authContext,\n });\n\n if (!data?.createSandbox?.id) {\n throw new Error('createSandbox returned empty response');\n }\n return data.createSandbox.id;\n}\n\nexport async function waitForSandboxReady(\n _apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n maxWaitMs = 300_000,\n onProgress?: (message: string) => void\n): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < maxWaitMs) {\n const data = await executeSandboxGraphQL<{\n getSandbox: { status?: string; errorMessage?: string } | null;\n }>({\n document: GetSandboxDocument,\n variables: { id: sandboxId, context: buildSandboxContextInput(workspaceId, authContext) },\n workspaceId,\n authContext,\n });\n const status = data?.getSandbox?.status;\n const errorMessage = data?.getSandbox?.errorMessage as string | undefined;\n if (status === 'RUNNING') return;\n if (status === 'FAILED' || status === 'STOPPED' || status === 'EXPIRED') {\n throw new Error(\n errorMessage ? `Sandbox ${status.toLowerCase()}: ${errorMessage}` : `Sandbox ${status.toLowerCase()}`\n );\n }\n const elapsedSeconds = Math.max(1, Math.round((Date.now() - start) / 1000));\n onProgress?.(`Starting assistant environment... (${elapsedSeconds}s)`);\n await new Promise((r) => setTimeout(r, 2000));\n }\n throw new Error('Sandbox startup timed out');\n}\n\n// ── Proxy calls to ai-assistant (via gateway → sandbox-svc) ───────\n\nasync function proxyToSandbox(\n _apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n path: string,\n method: string,\n body?: unknown,\n authContext?: AssistantSandboxAuthContext\n): Promise<Record<string, unknown>> {\n const result = await executeSandboxGraphQL<ProxyResponse>({\n document: ProxySandboxRequestDocument,\n variables: {\n input: {\n sandboxId,\n path,\n method,\n body,\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n },\n workspaceId,\n authContext,\n });\n\n const proxyResult = result.proxySandboxRequest;\n if (!proxyResult || proxyResult.status >= 400) {\n const errBody = proxyResult?.body as Record<string, unknown> | undefined;\n throw new Error((errBody?.error as string) ?? `Proxy error: ${proxyResult?.status ?? 'unknown'}`);\n }\n\n return proxyResult.body;\n}\n\nexport async function waitForAssistantServiceReady(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n maxWaitMs = 90_000,\n onProgress?: (message: string) => void\n): Promise<void> {\n const startedAt = Date.now();\n\n while (Date.now() - startedAt < maxWaitMs) {\n try {\n await proxyToSandbox(apollo, sandboxId, workspaceId, '/health', 'GET', undefined, authContext);\n return;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (!/proxy error: 502|proxy error: 503|proxy error: 404|service not available/i.test(message)) {\n throw error;\n }\n }\n\n const elapsedSeconds = Math.max(1, Math.round((Date.now() - startedAt) / 1000));\n onProgress?.(`Connecting to assistant... (${elapsedSeconds}s)`);\n\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n throw new Error('Assistant service did not become healthy before timeout');\n}\n\n// ── Session management ─────────────────────────────────────────────\n\nexport async function createAssistantSession(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: AssistantSandboxAuthContext\n): Promise<{ sessionId: string }> {\n const body = await proxyToSandbox(apollo, sandboxId, workspaceId, '/sessions', 'POST', { mode }, authContext);\n const session = body.session as Record<string, unknown>;\n return { sessionId: session.id as string };\n}\n\nexport async function getAssistantSession(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<AssistantSessionInfo> {\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}`,\n 'GET',\n undefined,\n authContext\n );\n const session = body.session as Record<string, unknown> | undefined;\n\n return {\n id: (session?.id as string | undefined) ?? sessionId,\n mode: (body.mode as string | undefined) ?? 'unknown',\n };\n}\n\n// ── Send prompt ────────────────────────────────────────────────────\n\nexport async function sendAssistantPrompt(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n prompt: string,\n mode: AssistantMode,\n pageContext?: PageContext,\n authContext?: AssistantSandboxAuthContext\n): Promise<AssistantPromptResult> {\n const requestBody = {\n mode,\n prompt,\n pageContext: pageContext\n ? {\n // Keys must match the agent's allowed-context-key contract.\n currentUrl: pageContext.currentUrl,\n currentPage: pageContext.currentPage,\n entityType: pageContext.entityType,\n entityId: pageContext.entityId,\n platform: pageContext.platform,\n version: pageContext.version,\n viewportSize: pageContext.viewportSize,\n }\n : undefined,\n };\n\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/prompt`,\n 'POST',\n requestBody,\n authContext\n );\n\n const message = body.message as Record<string, unknown> | undefined;\n const tokens = message?.tokens as { input: number; output: number } | undefined;\n\n return { response: body.text as string, tokens };\n}\n\nexport async function sendAssistantPromptAsync(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n prompt: string,\n mode: AssistantMode,\n pageContext?: PageContext,\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n const requestBody = {\n mode,\n prompt,\n pageContext: pageContext ?? undefined,\n };\n\n await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/prompt-async`,\n 'POST',\n requestBody,\n authContext\n );\n}\n\nexport async function getAssistantMessages(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext,\n limit = 50\n): Promise<AssistantRawMessage[]> {\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/messages?limit=${limit}`,\n 'GET',\n undefined,\n authContext\n );\n\n return (body.messages as AssistantRawMessage[] | undefined) ?? [];\n}\n\n// ── AI credits (per-token metering) ────────────────────────────────\n\n/**\n * Pre-flight AI-credit gate. Resolves to `true` when the caller still has\n * AI-credit budget; throws a quota error (HTTP 429 / QUOTA_EXHAUSTED, from\n * the wspace gateway's @usage check) when the monthly token budget is\n * depleted. Detect the rejection with `isQuotaExhaustedError()`.\n */\nexport async function checkAssistantAiCredits(\n _apollo: ApolloClient,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<boolean> {\n const data = await executeSandboxGraphQL<{ checkAiCredits: boolean }>({\n document: CheckAiCreditsDocument,\n variables: {},\n workspaceId,\n authContext,\n });\n return data.checkAiCredits;\n}\n\n/**\n * Post-turn charge. Reports the turn's raw input/output token counts + the\n * model so the svc computes COST-WEIGHTED credits server-side and charges them\n * against the product's AI credits. `messageId` makes the charge idempotent\n * (retries don't double-charge). No-ops when there are no tokens, or when the\n * model is unknown (the charge requires it). Best-effort — callers must not\n * block the displayed answer on it.\n */\nexport async function reportAssistantAiTokenUsage(\n _apollo: ApolloClient,\n workspaceId: string,\n sessionId: string,\n messageId: string,\n model: string | undefined,\n tokens: { input: number; output: number },\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n const inputTokens = Math.max(0, Math.round(tokens.input ?? 0));\n const outputTokens = Math.max(0, Math.round(tokens.output ?? 0));\n if (inputTokens + outputTokens === 0) return;\n // The svc requires a model to price the charge; skip rather than send a turn\n // that can't be priced (the meter under-counts that turn — acceptable).\n if (!model) return;\n\n await executeSandboxGraphQL<{ reportAiTokenUsage: boolean }>({\n document: ReportAiTokenUsageDocument,\n variables: {\n input: { sessionId, messageId, model, inputTokens, outputTokens },\n },\n workspaceId,\n authContext,\n });\n}\n\nexport async function getAssistantArtifacts(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<AssistantArtifact[]> {\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/artifacts`,\n 'GET',\n undefined,\n authContext\n );\n\n return ((body.artifacts as AssistantArtifact[] | undefined) ?? []).filter(\n (artifact) => !artifact.name.startsWith('.')\n );\n}\n\nexport async function downloadAssistantArtifact(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n artifactPath: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<DownloadedAssistantArtifact> {\n const encodedPath = encodeURIComponent(artifactPath);\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/artifacts/download?path=${encodedPath}`,\n 'GET',\n undefined,\n authContext\n );\n\n const artifact = body.artifact as Record<string, unknown> | undefined;\n if (!artifact) {\n throw new Error('Artifact download returned an empty response');\n }\n\n return {\n filename: artifact.filename as string,\n mimeType: artifact.mimeType as string,\n contentBase64: artifact.contentBase64 as string,\n };\n}\n\n// ── Heartbeat ───────────────────────────────────────────────────────\n\nexport async function sendHeartbeat(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/heartbeat`,\n 'POST',\n undefined,\n authContext\n );\n}\n\nexport async function extendAssistantSandboxTTL(\n _apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n additionalSeconds = 600,\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n await executeSandboxGraphQL<{ extendSandboxTTL: { id: string } }>({\n document: ExtendSandboxTtlDocument,\n variables: {\n id: sandboxId,\n additionalSeconds,\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n workspaceId,\n authContext,\n });\n}\n"],"mappings":";;;AAyBA,IAAM,IAAqB,gCAErB,IAAuE,uBACvE,IAAyE,4BACzE,IAA8B;AAEpC,SAAS,EAAmB,GAA6B;AACvD,SAAQ,GAAR;EACE,KAAK,UACH,QAAO;EAET,KAAK;EACL,KAAK,YACH,QAAO;EACT,KAAK,eACH,QAAO;;;AAIb,SAAS,EAAgB,GAA6B;AAIpD,QAAO,GAAG,EAAmB,uBADX,MAAS,cAAc,cAAc,EACO,GAAG,EAAmB,EAAK;;AAG3F,SAAS,EAAoB,GAK3B;AACA,SAAQ,GAAR;EACE,KAAK,UACH,QAAO;GACL,YAAY;GACZ,UAAU;GACV,eAAe;GACf,aAAa;GACd;EACH,KAAK,eACH,QAAO;GACL,YAAY;GACZ,UAAU;GACV,eAAe;GACf,aAAa;GACd;EACH,KAAK;EACL,KAAK,YACH,QAAO;GACL,YAAY;GACZ,UAAU;GACV,eAAe;GACf,aAAa;GACd;;;AAIP,SAAS,EAA4B,GAGZ;CACvB,IAAM,IAAe,EAAQ,UAAU;AACvC,KACE,MAAiB,eACjB,MAAiB,aACjB,MAAiB,eACjB,MAAiB,eAEjB,QAAO;CAGT,IAAM,IAAO,EAAQ,QAAQ;AAK7B,QAJI,EAAK,WAAW,6BAA6B,GAAS,iBACtD,EAAK,WAAW,0BAA0B,GAAS,cACnD,EAAK,WAAW,wBAAwB,GAAS,YACjD,EAAK,WAAW,0BAA0B,GAAS,cAChD;;AAoET,SAAS,EACP,GACA,GACkD;CAClD,IAAM,IAAkC,EAAE;AAuB1C,QArBI,GAAa,gBACf,EAAQ,gBAAgB,UAAU,EAAY,gBAG5C,GAAa,mBACf,EAAQ,+BAA+B,UAAU,EAAY,mBAG3D,MACF,EAAQ,oBAAoB,IAG1B,GAAa,WACf,EAAQ,gBAAgB,EAAY,QACpC,EAAQ,kBAAkB,SAGxB,GAAa,mBACf,EAAQ,cAAc,EAAY,iBAG7B,OAAO,KAAK,EAAQ,CAAC,SAAS,IAAI,EAAE,YAAS,GAAG,KAAA;;AAGzD,SAAS,EACP,GACA,GACyB;AACzB,QAAO;EACL;EACA,GAAI,GAAa,iBACb,EACE,QAAQ,EACN,gBAAgB,EAAY,gBAC7B,EACF,GACD,EAAE;EACP;;AAGH,eAAe,EAA6B,GAKzB;CACjB,IAAM,IAAW,MAAM,MAAM,uBAAuB;EAClD,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,GAAI,EAAyB,EAAO,aAAa,EAAO,YAAY,EAAE,WAAW,EAAE;GACpF;EACD,MAAM,KAAK,UAAU;GACnB,OAAO,EAAM,EAAO,SAAS;GAC7B,WAAW,EAAO;GACnB,CAAC;EACH,CAAC,EAEI,IAAU,MAAM,EAAS,MAAM,CAAC,YAAY,KAAK;AAEvD,KAAI,CAAC,EAAS,IAAI;EAKhB,IAAM,IAAW,GAAQ,QAAQ,KAAK,MAA+B,EAAM,QAAQ,CAAC,KAAK,KAAK,EACxF,IAAgB,MAAM,KAAY,wBAAwB,EAAS,SAAS;AAMlF,QAFA,EAAU,aAAa,EAAS,QAChC,EAAU,SAAS,KAAU,KAAA,GACvB;;AAGR,KAAI,CAAC,EACH,OAAU,MAAM,0CAA0C;AAG5D,KAAI,EAAO,QAAQ,OACjB,OAAU,MAAM,EAAO,OAAO,KAAK,MAA+B,EAAM,QAAQ,CAAC,KAAK,KAAK,CAAC;AAG9F,KAAI,CAAC,EAAO,KACV,OAAU,MAAM,mCAAmC;AAGrD,QAAO,EAAO;;AAKhB,eAAsB,EACpB,GACA,GACA,GACA,GACwB;AAkBxB,UAjBa,MAAM,EAShB;EACD,UAAU;EACV,WAAW,EAAE,SAAS,EAAyB,GAAa,EAAY,EAAE;EAC1E;EACA;EACD,CAAC,EACqB,sBAAsB,EAAE,EAGnC,MACP,OACE,EAAE,WAAW,aAAa,EAAE,WAAW,kBAAkB,EAAE,WAAW,cACvE,EAAE,aAAa,gBACf,EAA4B,EAAE,KAAK,MAClC,CAAC,GAAa,UAAU,EAAE,cAAc,EAAY,WACrD,EAAE,UAAU,iBAAiB,KAC7B,EAAE,UAAU,aAAa,EAAmB,EAAK,CACpD,EAAE,MAAM;;AAMb,eAAsB,EACpB,GACA,GACA,GACA,GACiB;CACjB,IAAM,IAAY,EAAoB,EAAK,EACrC,IAAM;EACV;GAAE,MAAM;GAAqB,OAAO;GAAM;EAC1C;GAAE,MAAM;GAAY,OAAO;GAAW;EACtC;GAAE,MAAM;GAAgB,OAAO;GAAa;EAI5C;GAAE,MAAM;GAAwB,OAAO;GAAgB;EACxD,EAEK,IAAO,MAAM,EAAyD;EAC1E,UAAU;EACV,WAAW,EACT,OAAO;GACL,MAAM,gBAAgB,EAAK,GAAG,KAAK,KAAK;GACxC,aAAa,yBAAyB,EAAK;GAC3C,UAAU;GACV,MAAM;GACN,YAAY,CACV;IACE,MAAM;IACN,OAAO,EAAgB,EAAK;IAG5B,OAAO,CAAC;KAAE,eAAe;KAAM,MAAM;KAAQ,CAAC;IAC9C;IACD,CACF;GACD,WAAW;IACT,YAAY,EAAU;IACtB,UAAU,EAAU;IACpB,eAAe,EAAU;IACzB,aAAa,EAAU;IACxB;GACD,YAAY;GACZ,UAAU;IACR,eAAe;IACf,sBAAsB,GAAa,UAAU;IAC7C,yBAAyB,GAAa,kBAAkB;IACxD,cAAc;IACd,UAAU,EAAmB,EAAK;IACnC;GACD,SAAS,EAAyB,GAAa,EAAY;GAC5D,EACF;EACD;EACA;EACD,CAAC;AAEF,KAAI,CAAC,GAAM,eAAe,GACxB,OAAU,MAAM,wCAAwC;AAE1D,QAAO,EAAK,cAAc;;AAG5B,eAAsB,EACpB,GACA,GACA,GACA,GACA,IAAY,KACZ,GACe;CACf,IAAM,IAAQ,KAAK,KAAK;AACxB,QAAO,KAAK,KAAK,GAAG,IAAQ,IAAW;EACrC,IAAM,IAAO,MAAM,EAEhB;GACD,UAAU;GACV,WAAW;IAAE,IAAI;IAAW,SAAS,EAAyB,GAAa,EAAY;IAAE;GACzF;GACA;GACD,CAAC,EACI,IAAS,GAAM,YAAY,QAC3B,IAAe,GAAM,YAAY;AACvC,MAAI,MAAW,UAAW;AAC1B,MAAI,MAAW,YAAY,MAAW,aAAa,MAAW,UAC5D,OAAU,MACR,IAAe,WAAW,EAAO,aAAa,CAAC,IAAI,MAAiB,WAAW,EAAO,aAAa,GACpG;EAEH,IAAM,IAAiB,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,KAAK,GAAG,KAAS,IAAK,CAAC;AAE3E,EADA,IAAa,sCAAsC,EAAe,IAAI,EACtE,MAAM,IAAI,SAAS,MAAM,WAAW,GAAG,IAAK,CAAC;;AAE/C,OAAU,MAAM,4BAA4B;;AAK9C,eAAe,EACb,GACA,GACA,GACA,GACA,GACA,GACA,GACkC;CAgBlC,IAAM,KAfS,MAAM,EAAqC;EACxD,UAAU;EACV,WAAW,EACT,OAAO;GACL;GACA;GACA;GACA;GACA,SAAS,EAAyB,GAAa,EAAY;GAC5D,EACF;EACD;EACA;EACD,CAAC,EAEyB;AAC3B,KAAI,CAAC,KAAe,EAAY,UAAU,KAAK;EAC7C,IAAM,IAAU,GAAa;AAC7B,QAAU,MAAO,GAAS,SAAoB,gBAAgB,GAAa,UAAU,YAAY;;AAGnG,QAAO,EAAY;;AAGrB,eAAsB,EACpB,GACA,GACA,GACA,GACA,IAAY,KACZ,GACe;CACf,IAAM,IAAY,KAAK,KAAK;AAE5B,QAAO,KAAK,KAAK,GAAG,IAAY,IAAW;AACzC,MAAI;AACF,SAAM,EAAe,GAAQ,GAAW,GAAa,WAAW,OAAO,KAAA,GAAW,EAAY;AAC9F;WACO,GAAO;GACd,IAAM,IAAU,aAAiB,QAAQ,EAAM,UAAU,OAAO,EAAM;AACtE,OAAI,CAAC,4EAA4E,KAAK,EAAQ,CAC5F,OAAM;;EAIV,IAAM,IAAiB,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,KAAK,GAAG,KAAa,IAAK,CAAC;AAG/E,EAFA,IAAa,+BAA+B,EAAe,IAAI,EAE/D,MAAM,IAAI,SAAS,MAAY,WAAW,GAAS,IAAK,CAAC;;AAG3D,OAAU,MAAM,0DAA0D;;AAK5E,eAAsB,EACpB,GACA,GACA,GACA,GACA,GACgC;AAGhC,QAAO,EAAE,YAFI,MAAM,EAAe,GAAQ,GAAW,GAAa,aAAa,QAAQ,EAAE,SAAM,EAAE,EAAY,EACxF,QACO,IAAc;;AAwE5C,eAAsB,EACpB,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACe;CACf,IAAM,IAAc;EAClB;EACA;EACA,aAAa,KAAe,KAAA;EAC7B;AAED,OAAM,EACJ,GACA,GACA,GACA,aAAa,EAAU,gBACvB,QACA,GACA,EACD;;AAGH,eAAsB,EACpB,GACA,GACA,GACA,GACA,GACA,IAAQ,IACwB;AAWhC,SAVa,MAAM,EACjB,GACA,GACA,GACA,aAAa,EAAU,kBAAkB,KACzC,OACA,KAAA,GACA,EACD,EAEY,YAAkD,EAAE;;AAoInE,eAAsB,EACpB,GACA,GACA,GACA,IAAoB,KACpB,GACe;AACf,OAAM,EAA4D;EAChE,UAAU;EACV,WAAW;GACT,IAAI;GACJ;GACA,SAAS,EAAyB,GAAa,EAAY;GAC5D;EACD;EACA;EACD,CAAC"}