@burdenoff/fe-libs 2026.904.20 → 2026.904.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/node_modules/fflate/esm/browser.js +324 -0
  2. package/dist/node_modules/pdfjs-dist/build/pdf.js +15775 -0
  3. package/dist/node_modules/pdfjs-dist/build/pdf.worker.min.js +50952 -0
  4. package/dist/shared/assistant/aiCredits.d.ts +21 -0
  5. package/dist/shared/assistant/aiCredits.d.ts.map +1 -0
  6. package/dist/shared/assistant/aiCredits.js +15 -0
  7. package/dist/shared/assistant/createSandboxAssistantTransport.js +2 -1
  8. package/dist/shared/assistant/documentExtract.d.ts +22 -0
  9. package/dist/shared/assistant/documentExtract.d.ts.map +1 -0
  10. package/dist/shared/assistant/documentExtract.js +133 -0
  11. package/dist/shared/assistant/gatewayClient.d.ts +15 -1
  12. package/dist/shared/assistant/gatewayClient.d.ts.map +1 -1
  13. package/dist/shared/assistant/gatewayClient.js +6 -11
  14. package/dist/shared/assistant/index.d.ts +6 -0
  15. package/dist/shared/assistant/index.d.ts.map +1 -1
  16. package/dist/shared/assistant/quota.d.ts +65 -0
  17. package/dist/shared/assistant/quota.d.ts.map +1 -0
  18. package/dist/shared/assistant/quota.js +45 -0
  19. package/dist/shared/assistant/ui/composer/AssistantComposer.d.ts +50 -0
  20. package/dist/shared/assistant/ui/composer/AssistantComposer.d.ts.map +1 -0
  21. package/dist/shared/assistant/ui/composer/AssistantComposer.js +185 -0
  22. package/dist/shared/assistant/useAssistantAttachments.d.ts +26 -0
  23. package/dist/shared/assistant/useAssistantAttachments.d.ts.map +1 -0
  24. package/dist/shared/assistant/useAssistantAttachments.js +244 -0
  25. package/dist/shared/assistant/useWorkspaceWriteAccess.d.ts +29 -0
  26. package/dist/shared/assistant/useWorkspaceWriteAccess.d.ts.map +1 -0
  27. package/dist/shared/assistant/useWorkspaceWriteAccess.js +41 -0
  28. package/dist/shared/utils/imageDownscale.d.ts +91 -0
  29. package/dist/shared/utils/imageDownscale.d.ts.map +1 -0
  30. package/dist/shared/utils/imageDownscale.js +102 -0
  31. package/dist/shared/utils/index.d.ts +4 -3
  32. package/dist/shared/utils/index.d.ts.map +1 -1
  33. package/dist/shared-assistant.js +84 -78
  34. package/dist/shared-utils.js +6 -5
  35. package/dist/shared.js +94 -93
  36. package/dist/utils/index.js +1 -0
  37. package/package.json +13 -3
@@ -0,0 +1,21 @@
1
+ import { QuotaKind } from './quota';
2
+ /**
3
+ * Fired after a successful AI-token charge so a live credits meter could refetch
4
+ * its balance.
5
+ *
6
+ * ★ Namespaced by product, like the quota event. Nothing listens for it in any
7
+ * product today — verified across the repo — because no product mounts a meter.
8
+ * The dispatch is kept as the cheap half of that feature, not as a live path.
9
+ */
10
+ export declare function aiCreditsUpdatedEventName(product: string): string;
11
+ export declare function notifyAiCreditsUpdated(product: string): void;
12
+ /**
13
+ * Opens a quota dialog for an assistant quota wall.
14
+ *
15
+ * The assistant's prompt and sandbox calls go through a raw fetch rather than an
16
+ * Apollo mutation, so they cannot rely on the Apollo error link that normally
17
+ * dispatches this — they call here directly. `kind` is `ai-credits` for the
18
+ * per-token gate and `sandbox` for the sandbox-environment limit.
19
+ */
20
+ export declare function dispatchAssistantQuotaExhausted(product: string, kind: QuotaKind): void;
21
+ //# sourceMappingURL=aiCredits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiCredits.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/aiCredits.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,SAAS,CAAC;AAEjB;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAG5D;AAED;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,GACd,IAAI,CASN"}
@@ -0,0 +1,15 @@
1
+ import { quotaExhaustedEventName as e } from "./quota.js";
2
+ //#region src/shared/assistant/aiCredits.ts
3
+ function t(e) {
4
+ return `${e}:ai-credits-updated`;
5
+ }
6
+ function n(e) {
7
+ typeof window > "u" || window.dispatchEvent(new CustomEvent(t(e)));
8
+ }
9
+ function r(t, n) {
10
+ if (typeof window > "u") return;
11
+ let r = { kind: n };
12
+ window.dispatchEvent(new CustomEvent(e(t), { detail: r }));
13
+ }
14
+ //#endregion
15
+ export { t as aiCreditsUpdatedEventName, r as dispatchAssistantQuotaExhausted, n as notifyAiCreditsUpdated };
@@ -1,4 +1,5 @@
1
- import { isQuotaExhaustedError as e } from "./gatewayClient.js";
1
+ import { isQuotaExhaustedError as e } from "./quota.js";
2
+ import "./gatewayClient.js";
2
3
  import { checkAssistantAiCredits as t, getAssistantMessages as n, getAssistantStreamAccess as r, reportAssistantAiTokenUsage as i, sendAssistantPromptAsync as a, stopReapedAssistantSandbox as o } from "./api.js";
3
4
  import { AssistantRuntimeManager as s } from "./runtime.js";
4
5
  import { buildProgress as c, isReapedSandboxConnectionError as l, isRecoverable as u, mergeMessagesById as d, sanitize as f } from "./progress.js";
@@ -0,0 +1,22 @@
1
+ import { DocumentExtraction } from './documentText';
2
+ import { DocumentFormat } from './attachments';
3
+ export interface ExtractedDocument {
4
+ extraction: DocumentExtraction;
5
+ /** Already trimmed to `MAX_INLINE_CHARS_PER_FILE`. Absent unless status is 'ok'. */
6
+ textContent?: string;
7
+ /** True when `textContent` is a prefix of what the document actually holds. */
8
+ textTruncated?: boolean;
9
+ /** Page-per-entry text, for the shared budget's page-aligned re-trim. PDFs only. */
10
+ documentPages?: string[];
11
+ }
12
+ /**
13
+ * Pull text out of a document, never throwing.
14
+ *
15
+ * A failure here must not fail the ATTACHMENT: the file still uploads, the
16
+ * model still gets its URL, and the reason we could not read it becomes a
17
+ * sentence in the prompt. Throwing would instead surface as the composer's
18
+ * generic 'unreadable' rejection, and the user would lose the file over
19
+ * something that is only a partial loss.
20
+ */
21
+ export declare function extractDocumentText(file: File, format: DocumentFormat): Promise<ExtractedDocument>;
22
+ //# sourceMappingURL=documentExtract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"documentExtract.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/documentExtract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAUL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAA6B,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAK/E,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oFAAoF;IACpF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AA0ND;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,iBAAiB,CAAC,CAM5B"}
@@ -0,0 +1,133 @@
1
+ import { MAX_EXTRACTED_CHARS as e, docxXmlToText as t, fitPdfPages as n, joinSheets as r, parseSharedStrings as i, parseWorkbookSheets as a, pdfTextItemsToPage as o, sheetXmlToRows as s } from "./documentText.js";
2
+ import { MAX_INLINE_CHARS_PER_FILE as c } from "./attachments.js";
3
+ //#region src/shared/assistant/documentExtract.ts
4
+ var l = [
5
+ 208,
6
+ 207,
7
+ 17,
8
+ 224,
9
+ 161,
10
+ 177,
11
+ 26,
12
+ 225
13
+ ];
14
+ function u(e) {
15
+ return l.every((t, n) => e[n] === t);
16
+ }
17
+ function d(e) {
18
+ return (e instanceof Error ? e.message : String(e)).replace(/\s+/g, " ").slice(0, 160);
19
+ }
20
+ async function f() {
21
+ let [e, t] = await Promise.all([import("../../node_modules/pdfjs-dist/build/pdf.js"), import("../../node_modules/pdfjs-dist/build/pdf.worker.min.js")]);
22
+ return globalThis.pdfjsWorker = t, e;
23
+ }
24
+ async function p(e) {
25
+ let t = (await f()).getDocument({
26
+ data: e,
27
+ disableFontFace: !0,
28
+ useSystemFonts: !1
29
+ }), r;
30
+ try {
31
+ r = await t.promise;
32
+ } catch (e) {
33
+ return await t.destroy().catch(() => void 0), (e instanceof Error ? e.name : "") === "PasswordException" ? { extraction: { status: "encrypted" } } : { extraction: {
34
+ status: "corrupt",
35
+ detail: d(e)
36
+ } };
37
+ }
38
+ let i = r.numPages, a = Math.min(i, 100), s = [];
39
+ try {
40
+ let e = 0;
41
+ for (let t = 1; t <= a; t += 1) {
42
+ let n = await r.getPage(t), i = o((await n.getTextContent()).items);
43
+ if (n.cleanup(), s.push(i), e += i.length, e >= 2e5) break;
44
+ }
45
+ } catch (e) {
46
+ if (s.length === 0) return { extraction: {
47
+ status: "corrupt",
48
+ detail: d(e)
49
+ } };
50
+ } finally {
51
+ await t.destroy().catch(() => void 0);
52
+ }
53
+ return n(s, i, a, c);
54
+ }
55
+ async function m(e, t) {
56
+ let { unzipSync: n, strFromU8: r } = await import("../../node_modules/fflate/esm/browser.js"), i = n(e, { filter: (e) => t(e.name) }), a = {};
57
+ for (let [e, t] of Object.entries(i)) a[e] = r(t);
58
+ return a;
59
+ }
60
+ async function h(n) {
61
+ if (u(n)) return { extraction: {
62
+ status: "corrupt",
63
+ detail: "not an Office Open XML file — an OLE container, i.e. password-protected or a legacy .doc"
64
+ } };
65
+ let r;
66
+ try {
67
+ r = await m(n, (e) => e === "word/document.xml");
68
+ } catch (e) {
69
+ return { extraction: {
70
+ status: "corrupt",
71
+ detail: d(e)
72
+ } };
73
+ }
74
+ let i = r["word/document.xml"];
75
+ return i ? _(t(i).slice(0, e)) : { extraction: {
76
+ status: "corrupt",
77
+ detail: "no word/document.xml inside the file"
78
+ } };
79
+ }
80
+ async function g(t) {
81
+ if (u(t)) return { extraction: {
82
+ status: "corrupt",
83
+ detail: "not an Office Open XML file — an OLE container, i.e. password-protected or a legacy .xls"
84
+ } };
85
+ let n;
86
+ try {
87
+ n = await m(t, (e) => e === "xl/workbook.xml" || e === "xl/_rels/workbook.xml.rels" || e === "xl/sharedStrings.xml" || e.startsWith("xl/worksheets/"));
88
+ } catch (e) {
89
+ return { extraction: {
90
+ status: "corrupt",
91
+ detail: d(e)
92
+ } };
93
+ }
94
+ let o = n["xl/workbook.xml"];
95
+ if (!o) return { extraction: {
96
+ status: "corrupt",
97
+ detail: "no xl/workbook.xml inside the file"
98
+ } };
99
+ let c = i(n["xl/sharedStrings.xml"] ?? ""), l = a(o, n["xl/_rels/workbook.xml.rels"] ?? "").map((e) => ({
100
+ name: e.name,
101
+ rows: e.path && n[e.path] ? s(n[e.path], c) : []
102
+ })), f = _(r(l).slice(0, e)), p = l.filter((e) => e.rows.length > 0).map((e) => e.name);
103
+ return p.length > 0 && (f.extraction.sheetNames = p), f;
104
+ }
105
+ function _(e) {
106
+ if (e.trim() === "") return { extraction: { status: "no-text" } };
107
+ let t = e.length > c, n = e.slice(0, c), r = n.lastIndexOf("\n");
108
+ return {
109
+ extraction: {
110
+ status: "ok",
111
+ sourceChars: e.length
112
+ },
113
+ textContent: t && r > 8e3 * .5 ? n.slice(0, r) : n,
114
+ textTruncated: t
115
+ };
116
+ }
117
+ async function v(e, t) {
118
+ let n = await y(e, t);
119
+ return n.extraction.format = t, n;
120
+ }
121
+ async function y(e, t) {
122
+ try {
123
+ let n = new Uint8Array(await e.arrayBuffer());
124
+ return t === "pdf" ? await p(n) : t === "docx" ? await h(n) : await g(n);
125
+ } catch (e) {
126
+ return { extraction: {
127
+ status: "corrupt",
128
+ detail: d(e)
129
+ } };
130
+ }
131
+ }
132
+ //#endregion
133
+ export { v as extractDocumentText };
@@ -1,5 +1,19 @@
1
1
  import { AssistantSandboxAuthContext } from './types';
2
- export declare function isQuotaExhaustedError(error: unknown): boolean;
2
+ /**
3
+ * ★★ Delegates to `./quota`, which is the canonical classifier.
4
+ *
5
+ * This function used to return true for ANY 429. That conflated two refusals
6
+ * the gateway sends with the same status: `QUOTA_EXHAUSTED` — the workspace has
7
+ * the quota and used it up, so upgrading fixes it — and `QUOTA_NOT_PROVISIONED`,
8
+ * where the workspace has no assignment row at all and nothing the user does
9
+ * helps. BOFF-6302 exists because those two were shown to people with the same
10
+ * words, sending them to buy something that would not have helped.
11
+ *
12
+ * Behaviour is otherwise unchanged: a bare 429 with no code still classifies as
13
+ * exhausted (the raw-fetch transport surfaces those), and an explicit code still
14
+ * wins over the status.
15
+ */
16
+ export { isQuotaExhaustedError } from './quota';
3
17
  export declare function buildSandboxContextInput(workspaceId: string, authContext?: AssistantSandboxAuthContext): Record<string, unknown>;
4
18
  export declare function executeSandboxGraphQL<TData>(params: {
5
19
  query: string;
@@ -1 +1 @@
1
- {"version":3,"file":"gatewayClient.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/gatewayClient.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,SAAS,CAAC;AAe3D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAO7D;AAED,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,2BAA2B,GACxC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOzB;AAuCD,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,2BAA2B,CAAC;CAC3C,GAAG,OAAO,CAAC,KAAK,CAAC,CAqBjB"}
1
+ {"version":3,"file":"gatewayClient.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/gatewayClient.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,SAAS,CAAC;AAe3D;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEhD,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,2BAA2B,GACxC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOzB;AAuCD,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,2BAA2B,CAAC;CAC3C,GAAG,OAAO,CAAC,KAAK,CAAC,CAyBjB"}
@@ -1,5 +1,6 @@
1
1
  import { graphqlFetch as e } from "../graphql/fetch.js";
2
2
  import "../../shared-graphql.js";
3
+ import "./quota.js";
3
4
  //#region src/shared/assistant/gatewayClient.ts
4
5
  function t() {
5
6
  try {
@@ -8,19 +9,13 @@ function t() {
8
9
  return `bf-assistant-${Date.now()}-${Math.random().toString(36).slice(2)}`;
9
10
  }
10
11
  }
11
- function n(e) {
12
- let t = e;
13
- if (t?.statusCode === 429 || t?.extensions?.code === "QUOTA_EXHAUSTED") return !0;
14
- let n = t instanceof Error ? t.message.toLowerCase() : String(t).toLowerCase();
15
- return n.includes("quota") && (n.includes("exhaust") || n.includes("exceeded"));
16
- }
17
- function r(e, t) {
12
+ function n(e, t) {
18
13
  return {
19
14
  workspaceId: e,
20
15
  ...t?.organizationId ? { custom: { organizationId: t.organizationId } } : {}
21
16
  };
22
17
  }
23
- async function i(n) {
18
+ async function r(n) {
24
19
  let r = await e({
25
20
  gateway: "workspace",
26
21
  query: n.query,
@@ -40,10 +35,10 @@ async function i(n) {
40
35
  if (r.data == null) throw Error("Sandbox GraphQL returned no data");
41
36
  return r.data;
42
37
  }
43
- async function a(e) {
38
+ async function i(e) {
44
39
  let t;
45
40
  for (let n = 0; n < 3; n++) try {
46
- return await i(e);
41
+ return await r(e);
47
42
  } catch (e) {
48
43
  t = e;
49
44
  let r = e instanceof Error ? e.message.toLowerCase() : String(e).toLowerCase();
@@ -53,4 +48,4 @@ async function a(e) {
53
48
  throw t;
54
49
  }
55
50
  //#endregion
56
- export { r as buildSandboxContextInput, a as executeSandboxGraphQL, n as isQuotaExhaustedError };
51
+ export { n as buildSandboxContextInput, i as executeSandboxGraphQL };
@@ -110,4 +110,10 @@ export * from './ui/voice/AssistantVoiceSession';
110
110
  export * from './useAssistantApiAccess';
111
111
  export * from './useConversationTurns';
112
112
  export * from './transportErrors';
113
+ export * from './quota';
114
+ export * from './aiCredits';
115
+ export * from './useWorkspaceWriteAccess';
116
+ export * from './documentExtract';
117
+ export * from './useAssistantAttachments';
118
+ export * from './ui/composer/AssistantComposer';
113
119
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AAGxB,cAAc,wBAAwB,CAAC;AAKvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,gBAAgB,CAAC;AAK/B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,4BAA4B,CAAC;AAG3C,cAAc,QAAQ,CAAC;AAEvB,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAG/B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AAGrC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,oCAAoC,CAAC;AACnD,cAAc,sCAAsC,CAAC;AACrD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wCAAwC,CAAC;AACvD,cAAc,yBAAyB,CAAC;AACxC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC;AAGzC,cAAc,WAAW,CAAC;AAE1B,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AAErC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAE1C,cAAc,kCAAkC,CAAC;AAEjD,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AAGxB,cAAc,wBAAwB,CAAC;AAKvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAG9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,gBAAgB,CAAC;AAK/B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,4BAA4B,CAAC;AAG3C,cAAc,QAAQ,CAAC;AAEvB,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAG/B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AAGrC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,oCAAoC,CAAC;AACnD,cAAc,sCAAsC,CAAC;AACrD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wCAAwC,CAAC;AACvD,cAAc,yBAAyB,CAAC;AACxC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,0BAA0B,CAAC;AAGzC,cAAc,WAAW,CAAC;AAE1B,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AAErC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAE1C,cAAc,kCAAkC,CAAC;AAEjD,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAElC,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,2BAA2B,CAAC;AAE1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAE1C,cAAc,iCAAiC,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Quota-error detection for the assistant's raw-fetch transport.
3
+ *
4
+ * The assistant talks to the wspace gateway over `fetch` (not Apollo), so it
5
+ * can't rely on the Apollo error link. `isQuotaExhaustedError` inspects the
6
+ * thrown error for the gateway's 429 / QUOTA_EXHAUSTED signal across the shapes
7
+ * `executeSandboxGraphQL` surfaces (Error.message, `.statusCode`, `.result`).
8
+ *
9
+ * Only the assistant's two quota walls are modelled: `sandbox` (the
10
+ * sandboxes-created @usage limit hit during provisioning) and `ai-credits`
11
+ * (per-token budget).
12
+ */
13
+ /**
14
+ * Whether this error is an EXHAUSTED quota specifically.
15
+ *
16
+ * ★ BOFF-6302 — this used to match any HTTP 429, and a workspace with no assignment row is refused
17
+ * `429 QUOTA_NOT_PROVISIONED`. That is not exhaustion: the farmer has not used anything up, their
18
+ * plan was never granted, and "you have reached your limit" sends them to buy an upgrade that would
19
+ * not unblock them. {@link classifyQuotaError} now owns the distinction and this delegates to it.
20
+ */
21
+ export declare function isQuotaExhaustedError(error: unknown): boolean;
22
+ /**
23
+ * The two ways the gateway refuses a metered mutation. They are NOT the same thing and must not be
24
+ * shown to a farmer with the same words (BOFF-6302).
25
+ *
26
+ * - `exhausted` — the workspace has the quota and has used it up. Deleting something, or upgrading,
27
+ * fixes it. Actionable by the user.
28
+ * - `not-provisioned` — the workspace has **no assignment row for that quota at all**, so the
29
+ * gateway fails closed. Nothing the user does fixes it: they have not hit a limit, their plan was
30
+ * never granted. Measured in prod 2026-08-13, this is why `createHealthyBowlFarm` returns
31
+ * `429 QUOTA_NOT_PROVISIONED` on several workspaces — the core create path is simply dead there.
32
+ *
33
+ * ★ Keyed on `extensions.code`, never on the HTTP status or the message text. Both refusals are
34
+ * `429`, so status alone cannot tell them apart — which is exactly how "no active subscription
35
+ * covers this" would otherwise be reported to a farmer as "you have reached your limit".
36
+ */
37
+ export type QuotaRefusal = "exhausted" | "not-provisioned";
38
+ /**
39
+ * Which refusal this is, or null when the error is not a quota wall at all.
40
+ *
41
+ * `not-provisioned` wins when both appear: it is the more specific and the more serious of the two,
42
+ * and telling someone to upgrade when their plan was never granted sends them to buy something that
43
+ * would not help.
44
+ */
45
+ export declare function classifyQuotaError(error: unknown): QuotaRefusal | null;
46
+ export type QuotaKind = "sandbox" | "ai-credits" | "generic";
47
+ /**
48
+ * Event the assistant dispatches on a quota wall, namespaced by product.
49
+ *
50
+ * ★ A function rather than a constant: the shared code owns the mechanism, the
51
+ * product owns its namespace — the same rule as translation keys. Passing the
52
+ * product keeps HealthyBowl's existing `healthybowl:quota-exhausted` byte for
53
+ * byte, and stops two products in one page colliding.
54
+ *
55
+ * ★ Nothing listens for it yet, in any product — verified across the repo. The
56
+ * chat area surfaces the wall inline instead. Kept because the dispatch is the
57
+ * cheap half of a future upgrade dialog, but do not mistake it for a live path.
58
+ */
59
+ export declare function quotaExhaustedEventName(product: string): string;
60
+ export interface QuotaExhaustedEventDetail {
61
+ kind: QuotaKind;
62
+ message?: string;
63
+ operationName?: string | null;
64
+ }
65
+ //# sourceMappingURL=quota.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/quota.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAmBH;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAmB7D;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,iBAAiB,CAAC;AA0C3D;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAStE;AAED,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAAC;AAE7D;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B"}
@@ -0,0 +1,45 @@
1
+ //#region src/shared/assistant/quota.ts
2
+ function e(e, t) {
3
+ if (!e || typeof e != "object") return;
4
+ let n = e[t];
5
+ return Array.isArray(n) ? n : void 0;
6
+ }
7
+ function t(e) {
8
+ let t = i(e);
9
+ if (t) return t === "exhausted";
10
+ if (!(e instanceof Error)) return !1;
11
+ let n = e.message.toLowerCase();
12
+ return n.includes("quota") && (n.includes("exhaust") || n.includes("exceeded"));
13
+ }
14
+ var n = {
15
+ QUOTA_EXHAUSTED: "exhausted",
16
+ QUOTA_NOT_PROVISIONED: "not-provisioned"
17
+ };
18
+ function r(t) {
19
+ if (!t || typeof t != "object") return [];
20
+ let r = [
21
+ t,
22
+ t.result,
23
+ t.networkError
24
+ ], i = [];
25
+ for (let t of r) {
26
+ let n = t?.extensions;
27
+ n?.code && i.push(n.code), n?.errorCode && i.push(n.errorCode);
28
+ for (let n of e(t, "errors") ?? []) n.extensions?.code && i.push(n.extensions.code), n.extensions?.errorCode && i.push(n.extensions.errorCode);
29
+ }
30
+ let a = t.bodyText, o = t instanceof Error ? t.message : void 0;
31
+ for (let e of [a, o]) if (typeof e == "string") for (let t of Object.keys(n)) e.includes(t) && i.push(t);
32
+ return i;
33
+ }
34
+ function i(e) {
35
+ let t = r(e);
36
+ if (t.includes("QUOTA_NOT_PROVISIONED")) return "not-provisioned";
37
+ if (t.includes("QUOTA_EXHAUSTED")) return "exhausted";
38
+ let n = e?.statusCode;
39
+ return typeof n == "number" && n === 429 ? "exhausted" : null;
40
+ }
41
+ function a(e) {
42
+ return `${e}:quota-exhausted`;
43
+ }
44
+ //#endregion
45
+ export { i as classifyQuotaError, t as isQuotaExhaustedError, a as quotaExhaustedEventName };
@@ -0,0 +1,50 @@
1
+ import { FC } from 'react';
2
+ import { AssistantModeConfig } from '../../conversation';
3
+ import { AssistantMode } from '../../types';
4
+ import { AssistantAttachment } from '../../attachments';
5
+ interface Props {
6
+ /**
7
+ * Writes would be refused in this workspace. Advisory only — the mode stays
8
+ * fully usable for planning; this exists so the refusal is known BEFORE the
9
+ * user invests a turn in it, not after.
10
+ */
11
+ writeAccessDenied?: boolean;
12
+ /**
13
+ * Send the message. `attachments` are already uploaded and ready; the chat
14
+ * area folds them into the prompt and onto the user bubble.
15
+ */
16
+ onSend: (message: string, attachments: AssistantAttachment[]) => void;
17
+ /** True while a turn is in-flight (assistant busy) — disables send + shows the spinner. */
18
+ disabled?: boolean;
19
+ placeholder?: string;
20
+ mode: AssistantMode;
21
+ /** Role-filtered list of modes the user may pick. */
22
+ availableModes: AssistantModeConfig[];
23
+ onModeChange: (mode: AssistantMode) => void;
24
+ /**
25
+ * Opens the hands-free voice conversation. Omitted where a voice session
26
+ * cannot work at all (no speech input, or nothing able to speak the reply),
27
+ * which is what hides the control rather than offering a dead button.
28
+ */
29
+ onStartVoiceSession?: () => void;
30
+ }
31
+ /**
32
+ * AssistantComposer — the v2 input surface (per the ai-assistant-v2 mockups).
33
+ *
34
+ * A rounded card with, on the input row: a leading circular "+" attach control,
35
+ * an auto-growing textarea, a microphone, and a prominent filled forest-green
36
+ * circular send button. BELOW the input sit the mode pills ("Ask" active-green /
37
+ * "Take action" outline); ABOVE it, chips for any pending attachments.
38
+ *
39
+ * Multimodal input (Workstreams 2–3) arrives through three converging paths —
40
+ * the attach button, drag-and-drop onto the card, and paste (a screenshot from
41
+ * the clipboard is the single most common way a user shares one) — plus voice
42
+ * dictation, which appends recognised speech to the draft so it can still be
43
+ * edited before sending.
44
+ *
45
+ * Fully controlled (React state for the text) with auto-grow via a layout
46
+ * effect. Enter sends, Shift+Enter inserts a newline.
47
+ */
48
+ export declare const AssistantComposer: FC<Props>;
49
+ export {};
50
+ //# sourceMappingURL=AssistantComposer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssistantComposer.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/composer/AssistantComposer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,EAAE,EAER,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQjD,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,mBAAmB,CAAC;AAQ3B,UAAU,KAAK;IACb;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,KAAK,IAAI,CAAC;IACtE,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,aAAa,CAAC;IACpB,qDAAqD;IACrD,cAAc,EAAE,mBAAmB,EAAE,CAAC;IACtC,YAAY,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5C;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,KAAK,CA4ZvC,CAAC"}