@burdenoff/microfe-buildmyiq 2026.1025.3 → 2026.1025.5

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 (42) hide show
  1. package/dist/buildmyiq/components/AccessibilityChecker.d.ts +21 -0
  2. package/dist/buildmyiq/components/AccessibilityChecker.d.ts.map +1 -0
  3. package/dist/buildmyiq/components/AccessibilityChecker.js +151 -0
  4. package/dist/buildmyiq/components/AccessibilityChecker.js.map +1 -0
  5. package/dist/buildmyiq/components/index.d.ts +1 -0
  6. package/dist/buildmyiq/components/index.d.ts.map +1 -1
  7. package/dist/buildmyiq/components/index.js +1 -0
  8. package/dist/buildmyiq/hooks/accessibilityDraft.d.ts +4 -0
  9. package/dist/buildmyiq/hooks/accessibilityDraft.d.ts.map +1 -0
  10. package/dist/buildmyiq/hooks/accessibilityDraft.js +6 -0
  11. package/dist/buildmyiq/hooks/accessibilityDraft.js.map +1 -0
  12. package/dist/buildmyiq/hooks/index.d.ts +1 -0
  13. package/dist/buildmyiq/hooks/index.d.ts.map +1 -1
  14. package/dist/buildmyiq/hooks/index.js +2 -0
  15. package/dist/buildmyiq/hooks/useBuiAccessibility.d.ts +21 -0
  16. package/dist/buildmyiq/hooks/useBuiAccessibility.d.ts.map +1 -0
  17. package/dist/buildmyiq/hooks/useBuiAccessibility.js +67 -0
  18. package/dist/buildmyiq/hooks/useBuiAccessibility.js.map +1 -0
  19. package/dist/buildmyiq/hooks/useBuiProctoring.d.ts.map +1 -1
  20. package/dist/buildmyiq/hooks/useBuiProctoring.js +1 -1
  21. package/dist/buildmyiq/hooks/useBuiProctoring.js.map +1 -1
  22. package/dist/buildmyiq/hooks/useBuildmyiqApi.d.ts.map +1 -1
  23. package/dist/buildmyiq/hooks/useBuildmyiqApi.js +1 -5
  24. package/dist/buildmyiq/hooks/useBuildmyiqApi.js.map +1 -1
  25. package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.d.ts.map +1 -1
  26. package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.js +154 -144
  27. package/dist/buildmyiq/pages/assessments/AssessmentDetailPage.js.map +1 -1
  28. package/dist/buildmyiq/pages/authoring/CourseAccessibilityTab.d.ts +5 -0
  29. package/dist/buildmyiq/pages/authoring/CourseAccessibilityTab.d.ts.map +1 -0
  30. package/dist/buildmyiq/pages/authoring/CourseAccessibilityTab.js +156 -0
  31. package/dist/buildmyiq/pages/authoring/CourseAccessibilityTab.js.map +1 -0
  32. package/dist/buildmyiq/pages/authoring/CourseBuilderPage.d.ts.map +1 -1
  33. package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js +91 -74
  34. package/dist/buildmyiq/pages/authoring/CourseBuilderPage.js.map +1 -1
  35. package/dist/buildmyiq/types/index.d.ts +48 -0
  36. package/dist/buildmyiq/types/index.d.ts.map +1 -1
  37. package/dist/buildmyiq/types/index.js.map +1 -1
  38. package/dist/buildmyiq/utils/wcag.d.ts +6 -0
  39. package/dist/buildmyiq/utils/wcag.d.ts.map +1 -0
  40. package/dist/buildmyiq/utils/wcag.js +21 -0
  41. package/dist/buildmyiq/utils/wcag.js.map +1 -0
  42. package/package.json +1 -1
@@ -0,0 +1,21 @@
1
+ import { FC } from 'react';
2
+ import { BuiAccessibilityIssue, BuiAccessibilityReport, BuiCheckContentAccessibilityInput } from '../types';
3
+ export declare const AccessibilityIssueList: FC<{
4
+ issues: BuiAccessibilityIssue[];
5
+ className?: string;
6
+ }>;
7
+ /** One-line result summary, e.g. "2 errors · 1 warning". */
8
+ export declare const useAccessibilitySummary: () => ((report: Pick<BuiAccessibilityReport, "errorCount" | "warningCount">) => string);
9
+ interface AccessibilityCheckerProps {
10
+ /** Draft to check; re-checked 600 ms after it stops changing. */
11
+ input: BuiCheckContentAccessibilityInput;
12
+ id?: string;
13
+ className?: string;
14
+ }
15
+ /**
16
+ * Live accessibility check for an authoring form. Advisory: it never blocks
17
+ * saving, it tells the author what to fix and why (with the WCAG criterion).
18
+ */
19
+ export declare const AccessibilityChecker: FC<AccessibilityCheckerProps>;
20
+ export {};
21
+ //# sourceMappingURL=AccessibilityChecker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessibilityChecker.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/components/AccessibilityChecker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAShC,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EAEtB,iCAAiC,EAClC,MAAM,UAAU,CAAC;AAyFlB,eAAO,MAAM,sBAAsB,EAAE,EAAE,CAAC;IACtC,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAMA,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,uBAAuB,QAAO,CAAC,CAC1C,MAAM,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,cAAc,CAAC,KAChE,MAAM,CAyBV,CAAC;AAyBF,UAAU,yBAAyB;IACjC,iEAAiE;IACjE,KAAK,EAAE,iCAAiC,CAAC;IACzC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAmF9D,CAAC"}
@@ -0,0 +1,151 @@
1
+ import { useTr as e } from "../shared/hooks/useTr.js";
2
+ import { cn as t } from "../utils/cn.js";
3
+ import { hasCheckableContent as n } from "../hooks/accessibilityDraft.js";
4
+ import { useBuiCheckContentAccessibility as r, useDebouncedValue as i } from "../hooks/useBuiAccessibility.js";
5
+ import { wcagUnderstandingUrl as a } from "../utils/wcag.js";
6
+ import { AlertTriangle as o, CheckCircle2 as s, ExternalLink as c, Loader2 as l, XCircle as u } from "lucide-react";
7
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
8
+ //#region src/buildmyiq/components/AccessibilityChecker.tsx
9
+ var p = 600, m = {
10
+ IMAGE_ALT_MISSING: "Image without alt text",
11
+ IMAGE_ALT_EMPTY: "Image marked decorative",
12
+ IMAGE_ALT_NOT_DESCRIPTIVE: "Alt text is not descriptive",
13
+ LINK_TEXT_EMPTY: "Link without text",
14
+ LINK_TEXT_NOT_DESCRIPTIVE: "Vague link text",
15
+ LINK_TEXT_RAW_URL: "Raw URL as link text",
16
+ HEADING_EMPTY: "Empty heading",
17
+ HEADING_LEVEL_SKIPPED: "Skipped heading level",
18
+ TABLE_HEADER_MISSING: "Table without headers",
19
+ MEDIA_CAPTIONS_MISSING: "Video without captions",
20
+ MEDIA_AUTOPLAY: "Autoplaying media",
21
+ MEDIA_TRANSCRIPT_MISSING: "No transcript",
22
+ IFRAME_TITLE_MISSING: "Embed without a title",
23
+ MOVING_CONTENT: "Moving or blinking text",
24
+ COLOR_STYLING: "Inline text colour",
25
+ SENSORY_INSTRUCTION: "Colour or position-only instruction",
26
+ OPTION_LABEL_EMPTY: "Answer option without a label",
27
+ OPTION_LABEL_DUPLICATE: "Duplicate answer options"
28
+ }, h = ({ issue: n }) => {
29
+ let r = e(), i = n.severity === "ERROR", s = i ? u : o, l = a(n.wcag), p = r("buildmyiq.accessibility.wcagLink", "WCAG {{criterion}} (Level {{level}})", {
30
+ criterion: n.wcag,
31
+ level: n.wcagLevel
32
+ });
33
+ return /* @__PURE__ */ f("li", {
34
+ className: "flex gap-2.5 py-2.5 first:pt-0 last:pb-0",
35
+ children: [/* @__PURE__ */ d(s, {
36
+ "aria-hidden": "true",
37
+ className: t("mt-0.5 h-4 w-4 shrink-0", i ? "text-status-error-text" : "text-status-warning-text")
38
+ }), /* @__PURE__ */ f("div", {
39
+ className: "min-w-0 flex-1",
40
+ children: [
41
+ /* @__PURE__ */ f("p", {
42
+ className: "text-sm font-medium text-text-primary",
43
+ children: [
44
+ /* @__PURE__ */ f("span", {
45
+ className: "sr-only",
46
+ children: [i ? r("buildmyiq.accessibility.severity.error", "Error:") : r("buildmyiq.accessibility.severity.warning", "Warning:"), " "]
47
+ }),
48
+ r(`buildmyiq.accessibility.rules.${n.rule}`, m[n.rule] ?? n.rule),
49
+ n.line != null && /* @__PURE__ */ d("span", {
50
+ className: "ml-1.5 text-xs font-normal text-text-secondary",
51
+ children: r("buildmyiq.accessibility.line", "line {{line}}", { line: n.line })
52
+ })
53
+ ]
54
+ }),
55
+ /* @__PURE__ */ d("p", {
56
+ className: "mt-0.5 text-sm text-text-secondary",
57
+ children: r(`buildmyiq.accessibility.messages.${n.rule}`, n.message)
58
+ }),
59
+ n.excerpt && /* @__PURE__ */ d("code", {
60
+ className: "mt-1 block truncate rounded bg-bg-sunken px-1.5 py-0.5 font-mono text-xs text-text-secondary",
61
+ children: n.excerpt
62
+ }),
63
+ l ? /* @__PURE__ */ f("a", {
64
+ href: l,
65
+ target: "_blank",
66
+ rel: "noreferrer noopener",
67
+ className: "mt-1 inline-flex items-center gap-1 text-xs text-text-secondary underline underline-offset-2 hover:text-text-primary",
68
+ children: [
69
+ p,
70
+ /* @__PURE__ */ d(c, {
71
+ "aria-hidden": "true",
72
+ className: "h-3 w-3"
73
+ }),
74
+ /* @__PURE__ */ d("span", {
75
+ className: "sr-only",
76
+ children: r("buildmyiq.accessibility.opensNewTab", "(opens in a new tab)")
77
+ })
78
+ ]
79
+ }) : /* @__PURE__ */ d("span", {
80
+ className: "mt-1 block text-xs text-text-secondary",
81
+ children: p
82
+ })
83
+ ]
84
+ })]
85
+ });
86
+ }, g = ({ issues: e, className: n }) => /* @__PURE__ */ d("ul", {
87
+ className: t("divide-y divide-border-seam", n),
88
+ children: e.map((e, t) => /* @__PURE__ */ d(h, { issue: e }, `${e.rule}-${e.line ?? "x"}-${t}`))
89
+ }), _ = () => {
90
+ let t = e();
91
+ return (e) => {
92
+ if (e.errorCount === 0 && e.warningCount === 0) return t("buildmyiq.accessibility.noIssues", "No accessibility issues found");
93
+ let n = [];
94
+ return e.errorCount > 0 && n.push(e.errorCount === 1 ? t("buildmyiq.accessibility.oneError", "1 error") : t("buildmyiq.accessibility.errors", "{{count}} errors", { count: e.errorCount })), e.warningCount > 0 && n.push(e.warningCount === 1 ? t("buildmyiq.accessibility.oneWarning", "1 warning") : t("buildmyiq.accessibility.warnings", "{{count}} warnings", { count: e.warningCount })), n.join(" · ");
95
+ };
96
+ }, v = {
97
+ checking: l,
98
+ error: u,
99
+ warning: o,
100
+ clean: s
101
+ }, y = {
102
+ checking: "motion-safe:animate-spin",
103
+ error: "text-status-error-text",
104
+ warning: "text-status-warning-text",
105
+ clean: "text-status-success-text"
106
+ }, b = (e, t) => e || !t ? "checking" : t.errorCount > 0 ? "error" : t.warningCount > 0 ? "warning" : "clean", x = ({ input: a, id: o = "accessibility-check", className: s }) => {
107
+ let c = e(), l = _(), u = i(a, p), m = r(u), h = n(a), x = h ? m.data : void 0, S = JSON.stringify(a) !== JSON.stringify(u) || m.isFetching || m.isPlaceholderData, C = h && !S && m.isError, w = !h, T = `${o}-heading`, E;
108
+ E = w ? c("buildmyiq.accessibility.idle", "Start writing and the content will be checked for accessibility.") : C ? c("buildmyiq.accessibility.unavailable", "Accessibility check is unavailable right now.") : S || !x ? c("buildmyiq.accessibility.checking", "Checking accessibility…") : l(x);
109
+ let D = w || S || !x && !C ? "" : E, O = b(S, x), k = v[O];
110
+ return /* @__PURE__ */ f("section", {
111
+ "aria-labelledby": T,
112
+ "data-testid": "accessibility-checker",
113
+ className: t("rounded-xl border border-border-seam bg-bg-sunken/40 p-3", s),
114
+ children: [
115
+ /* @__PURE__ */ f("div", {
116
+ className: "flex items-center justify-between gap-2",
117
+ children: [
118
+ /* @__PURE__ */ d("h3", {
119
+ id: T,
120
+ className: "text-sm font-semibold text-text-primary",
121
+ children: c("buildmyiq.accessibility.title", "Accessibility check")
122
+ }),
123
+ /* @__PURE__ */ f("p", {
124
+ "aria-hidden": "true",
125
+ "data-testid": "accessibility-checker-status",
126
+ className: "inline-flex items-center gap-1.5 text-xs text-text-secondary",
127
+ children: [!w && !C && /* @__PURE__ */ d(k, { className: t("h-3.5 w-3.5", y[O]) }), E]
128
+ }),
129
+ /* @__PURE__ */ d("p", {
130
+ role: "status",
131
+ "aria-live": "polite",
132
+ className: "sr-only",
133
+ children: D
134
+ })
135
+ ]
136
+ }),
137
+ x && !C && x.issues.length > 0 && /* @__PURE__ */ d(g, {
138
+ issues: x.issues,
139
+ className: "mt-3"
140
+ }),
141
+ x?.truncated && /* @__PURE__ */ d("p", {
142
+ className: "mt-2 text-xs text-text-secondary",
143
+ children: c("buildmyiq.accessibility.truncated", "Only the first part of this content was checked because it is very long.")
144
+ })
145
+ ]
146
+ });
147
+ };
148
+ //#endregion
149
+ export { x as AccessibilityChecker, g as AccessibilityIssueList, _ as useAccessibilitySummary };
150
+
151
+ //# sourceMappingURL=AccessibilityChecker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessibilityChecker.js","names":[],"sources":["../../../src/buildmyiq/components/AccessibilityChecker.tsx"],"sourcesContent":["/**\n * Accessibility checker UI (BOFF-4423).\n * @module buildmyiq/components/AccessibilityChecker\n *\n * - `AccessibilityChecker` — live, debounced check of a draft inside an\n * authoring form (lesson body, question prompt/options/explanation).\n * - `AccessibilityIssueList` — the issue list, shared with the course-level\n * report on the Course builder's Accessibility tab.\n *\n * Rules run server-side (`buiCheckContentAccessibility`); this only renders.\n * Status changes are announced through a polite live region so screen-reader\n * authors hear the result without losing their place in the form.\n */\n\nimport type { FC } from 'react';\nimport { AlertTriangle, CheckCircle2, ExternalLink, Loader2, XCircle } from 'lucide-react';\n\nimport {\n hasCheckableContent,\n useBuiCheckContentAccessibility,\n useDebouncedValue,\n} from '../hooks/useBuiAccessibility';\nimport { useTr } from '../shared/hooks/useTr';\nimport type {\n BuiAccessibilityIssue,\n BuiAccessibilityReport,\n BuiAccessibilityRule,\n BuiCheckContentAccessibilityInput,\n} from '../types';\nimport { cn } from '../utils/cn';\nimport { wcagUnderstandingUrl } from '../utils/wcag';\n\nconst DEBOUNCE_MS = 600;\n\n/** Short English title per rule (translatable via `buildmyiq.accessibility.rules.<RULE>`). */\nconst RULE_TITLES: Record<BuiAccessibilityRule, string> = {\n IMAGE_ALT_MISSING: 'Image without alt text',\n IMAGE_ALT_EMPTY: 'Image marked decorative',\n IMAGE_ALT_NOT_DESCRIPTIVE: 'Alt text is not descriptive',\n LINK_TEXT_EMPTY: 'Link without text',\n LINK_TEXT_NOT_DESCRIPTIVE: 'Vague link text',\n LINK_TEXT_RAW_URL: 'Raw URL as link text',\n HEADING_EMPTY: 'Empty heading',\n HEADING_LEVEL_SKIPPED: 'Skipped heading level',\n TABLE_HEADER_MISSING: 'Table without headers',\n MEDIA_CAPTIONS_MISSING: 'Video without captions',\n MEDIA_AUTOPLAY: 'Autoplaying media',\n MEDIA_TRANSCRIPT_MISSING: 'No transcript',\n IFRAME_TITLE_MISSING: 'Embed without a title',\n MOVING_CONTENT: 'Moving or blinking text',\n COLOR_STYLING: 'Inline text colour',\n SENSORY_INSTRUCTION: 'Colour or position-only instruction',\n OPTION_LABEL_EMPTY: 'Answer option without a label',\n OPTION_LABEL_DUPLICATE: 'Duplicate answer options',\n};\n\nconst IssueRow: FC<{ issue: BuiAccessibilityIssue }> = ({ issue }) => {\n const tr = useTr();\n const isError = issue.severity === 'ERROR';\n const Icon = isError ? XCircle : AlertTriangle;\n const url = wcagUnderstandingUrl(issue.wcag);\n const wcagLabel = tr('buildmyiq.accessibility.wcagLink', 'WCAG {{criterion}} (Level {{level}})', {\n criterion: issue.wcag,\n level: issue.wcagLevel,\n });\n return (\n <li className=\"flex gap-2.5 py-2.5 first:pt-0 last:pb-0\">\n <Icon\n aria-hidden=\"true\"\n className={cn(\n 'mt-0.5 h-4 w-4 shrink-0',\n isError ? 'text-status-error-text' : 'text-status-warning-text'\n )}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n <span className=\"sr-only\">\n {isError\n ? tr('buildmyiq.accessibility.severity.error', 'Error:')\n : tr('buildmyiq.accessibility.severity.warning', 'Warning:')}{' '}\n </span>\n {tr(`buildmyiq.accessibility.rules.${issue.rule}`, RULE_TITLES[issue.rule] ?? issue.rule)}\n {issue.line != null && (\n <span className=\"ml-1.5 text-xs font-normal text-text-secondary\">\n {tr('buildmyiq.accessibility.line', 'line {{line}}', { line: issue.line })}\n </span>\n )}\n </p>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n {tr(`buildmyiq.accessibility.messages.${issue.rule}`, issue.message)}\n </p>\n {issue.excerpt && (\n <code className=\"mt-1 block truncate rounded bg-bg-sunken px-1.5 py-0.5 font-mono text-xs text-text-secondary\">\n {issue.excerpt}\n </code>\n )}\n {url ? (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"mt-1 inline-flex items-center gap-1 text-xs text-text-secondary underline underline-offset-2 hover:text-text-primary\"\n >\n {wcagLabel}\n <ExternalLink aria-hidden=\"true\" className=\"h-3 w-3\" />\n <span className=\"sr-only\">\n {tr('buildmyiq.accessibility.opensNewTab', '(opens in a new tab)')}\n </span>\n </a>\n ) : (\n <span className=\"mt-1 block text-xs text-text-secondary\">{wcagLabel}</span>\n )}\n </div>\n </li>\n );\n};\n\nexport const AccessibilityIssueList: FC<{\n issues: BuiAccessibilityIssue[];\n className?: string;\n}> = ({ issues, className }) => (\n <ul className={cn('divide-y divide-border-seam', className)}>\n {issues.map((issue, index) => (\n <IssueRow key={`${issue.rule}-${issue.line ?? 'x'}-${index}`} issue={issue} />\n ))}\n </ul>\n);\n\n/** One-line result summary, e.g. \"2 errors · 1 warning\". */\nexport const useAccessibilitySummary = (): ((\n report: Pick<BuiAccessibilityReport, 'errorCount' | 'warningCount'>\n) => string) => {\n const tr = useTr();\n return (report) => {\n if (report.errorCount === 0 && report.warningCount === 0) {\n return tr('buildmyiq.accessibility.noIssues', 'No accessibility issues found');\n }\n const parts: string[] = [];\n if (report.errorCount > 0) {\n parts.push(\n report.errorCount === 1\n ? tr('buildmyiq.accessibility.oneError', '1 error')\n : tr('buildmyiq.accessibility.errors', '{{count}} errors', { count: report.errorCount })\n );\n }\n if (report.warningCount > 0) {\n parts.push(\n report.warningCount === 1\n ? tr('buildmyiq.accessibility.oneWarning', '1 warning')\n : tr('buildmyiq.accessibility.warnings', '{{count}} warnings', {\n count: report.warningCount,\n })\n );\n }\n return parts.join(' · ');\n };\n};\n\ntype StatusTone = 'checking' | 'error' | 'warning' | 'clean';\n\nconst STATUS_ICONS = {\n checking: Loader2,\n error: XCircle,\n warning: AlertTriangle,\n clean: CheckCircle2,\n} as const;\n\nconst STATUS_TONE_CLASS: Record<StatusTone, string> = {\n checking: 'motion-safe:animate-spin',\n error: 'text-status-error-text',\n warning: 'text-status-warning-text',\n clean: 'text-status-success-text',\n};\n\nconst statusTone = (stale: boolean, report: BuiAccessibilityReport | undefined): StatusTone => {\n if (stale || !report) return 'checking';\n if (report.errorCount > 0) return 'error';\n if (report.warningCount > 0) return 'warning';\n return 'clean';\n};\n\ninterface AccessibilityCheckerProps {\n /** Draft to check; re-checked 600 ms after it stops changing. */\n input: BuiCheckContentAccessibilityInput;\n id?: string;\n className?: string;\n}\n\n/**\n * Live accessibility check for an authoring form. Advisory: it never blocks\n * saving, it tells the author what to fix and why (with the WCAG criterion).\n */\nexport const AccessibilityChecker: FC<AccessibilityCheckerProps> = ({\n input,\n id = 'accessibility-check',\n className,\n}) => {\n const tr = useTr();\n const summarise = useAccessibilitySummary();\n const debounced = useDebouncedValue(input, DEBOUNCE_MS);\n const query = useBuiCheckContentAccessibility(debounced);\n // A cleared draft is idle again: never show the previous draft's result.\n const checkable = hasCheckableContent(input);\n const report = checkable ? query.data : undefined;\n // The shown report belongs to an older draft while the author is still\n // typing (debounce pending), while a request is in flight, or while React\n // Query is showing the previous key's data as a placeholder.\n const stale =\n JSON.stringify(input) !== JSON.stringify(debounced) ||\n query.isFetching ||\n query.isPlaceholderData;\n const failed = checkable && !stale && query.isError;\n const idle = !checkable;\n const headingId = `${id}-heading`;\n\n let status: string;\n if (idle) {\n status = tr(\n 'buildmyiq.accessibility.idle',\n 'Start writing and the content will be checked for accessibility.'\n );\n } else if (failed) {\n status = tr(\n 'buildmyiq.accessibility.unavailable',\n 'Accessibility check is unavailable right now.'\n );\n } else if (stale || !report) {\n status = tr('buildmyiq.accessibility.checking', 'Checking accessibility…');\n } else {\n status = summarise(report);\n }\n // Screen readers only hear settled results, never the transient \"checking\"\n // state, so typing does not trigger two announcements per pause.\n const announcement = idle || stale || (!report && !failed) ? '' : status;\n\n const tone = statusTone(stale, report);\n const StatusIcon = STATUS_ICONS[tone];\n\n return (\n <section\n aria-labelledby={headingId}\n data-testid=\"accessibility-checker\"\n className={cn('rounded-xl border border-border-seam bg-bg-sunken/40 p-3', className)}\n >\n <div className=\"flex items-center justify-between gap-2\">\n <h3 id={headingId} className=\"text-sm font-semibold text-text-primary\">\n {tr('buildmyiq.accessibility.title', 'Accessibility check')}\n </h3>\n <p\n aria-hidden=\"true\"\n data-testid=\"accessibility-checker-status\"\n className=\"inline-flex items-center gap-1.5 text-xs text-text-secondary\"\n >\n {!idle && !failed && (\n <StatusIcon className={cn('h-3.5 w-3.5', STATUS_TONE_CLASS[tone])} />\n )}\n {status}\n </p>\n <p role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n {announcement}\n </p>\n </div>\n {report && !failed && report.issues.length > 0 && (\n <AccessibilityIssueList issues={report.issues} className=\"mt-3\" />\n )}\n {report?.truncated && (\n <p className=\"mt-2 text-xs text-text-secondary\">\n {tr(\n 'buildmyiq.accessibility.truncated',\n 'Only the first part of this content was checked because it is very long.'\n )}\n </p>\n )}\n </section>\n );\n};\n"],"mappings":"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"}
@@ -21,4 +21,5 @@ export { TutorPanel } from './TutorPanel';
21
21
  export { BuiTags } from './BuiTags';
22
22
  export { BuiPermissionButton, type BuiPermissionButtonProps } from './BuiPermissionButton';
23
23
  export { OfflineLessonControl } from './OfflineLessonControl';
24
+ export { AccessibilityChecker, AccessibilityIssueList, useAccessibilitySummary, } from './AccessibilityChecker';
24
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/components/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/components/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC"}
@@ -17,3 +17,4 @@ import "./TutorPanel.js";
17
17
  import "./BuiTags.js";
18
18
  import "./BuiPermissionButton.js";
19
19
  import "./OfflineLessonControl.js";
20
+ import "./AccessibilityChecker.js";
@@ -0,0 +1,4 @@
1
+ import { BuiCheckContentAccessibilityInput } from '../types';
2
+ /** True when a draft has anything worth checking. */
3
+ export declare const hasCheckableContent: (input: BuiCheckContentAccessibilityInput) => boolean;
4
+ //# sourceMappingURL=accessibilityDraft.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibilityDraft.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/accessibilityDraft.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,UAAU,CAAC;AAElE,qDAAqD;AACrD,eAAO,MAAM,mBAAmB,GAAI,OAAO,iCAAiC,KAAG,OAM5E,CAAC"}
@@ -0,0 +1,6 @@
1
+ //#region src/buildmyiq/hooks/accessibilityDraft.ts
2
+ var e = (e) => !!(e.content?.trim() || e.explanation?.trim() || (e.options?.some((e) => e.label.trim().length > 0) ?? !1) || e.hasMedia && (e.lessonType === "VIDEO" || e.lessonType === "LIVE_SESSION"));
3
+ //#endregion
4
+ export { e as hasCheckableContent };
5
+
6
+ //# sourceMappingURL=accessibilityDraft.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibilityDraft.js","names":[],"sources":["../../../src/buildmyiq/hooks/accessibilityDraft.ts"],"sourcesContent":["/**\n * Pure helpers for the authoring-time accessibility checker (BOFF-4423).\n * @module buildmyiq/hooks/accessibilityDraft\n */\n\nimport type { BuiCheckContentAccessibilityInput } from '../types';\n\n/** True when a draft has anything worth checking. */\nexport const hasCheckableContent = (input: BuiCheckContentAccessibilityInput): boolean =>\n Boolean(\n input.content?.trim() ||\n input.explanation?.trim() ||\n (input.options?.some((o) => o.label.trim().length > 0) ?? false) ||\n (input.hasMedia && (input.lessonType === 'VIDEO' || input.lessonType === 'LIVE_SESSION'))\n );\n"],"mappings":";AAQA,IAAa,KAAuB,MAClC,GACE,EAAM,SAAS,KAAK,KACpB,EAAM,aAAa,KAAK,MACvB,EAAM,SAAS,MAAM,MAAM,EAAE,MAAM,KAAK,EAAE,SAAS,CAAC,KAAK,OACzD,EAAM,aAAa,EAAM,eAAe,WAAW,EAAM,eAAe"}
@@ -11,4 +11,5 @@ export * from './useBuiPermissions';
11
11
  export * from './useBuiProctoring';
12
12
  export * from './proctoringState';
13
13
  export * from './useBuiCredentials';
14
+ export * from './useBuiAccessibility';
14
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC"}
@@ -7,3 +7,5 @@ import "./useBuiPermissions.js";
7
7
  import "./useBuiProctoring.js";
8
8
  import "./proctoringState.js";
9
9
  import "./useBuiCredentials.js";
10
+ import "./accessibilityDraft.js";
11
+ import "./useBuiAccessibility.js";
@@ -0,0 +1,21 @@
1
+ import { BuiAccessibilityReport, BuiCheckContentAccessibilityInput, BuiCourseAccessibilityReport } from '../types';
2
+ import { hasCheckableContent } from './accessibilityDraft';
3
+ export { hasCheckableContent };
4
+ export declare const accessibilityKeys: {
5
+ draft: (input: BuiCheckContentAccessibilityInput) => readonly ["buildmyiq", "accessibility", "draft", BuiCheckContentAccessibilityInput];
6
+ course: (courseId: string) => readonly ["buildmyiq", "accessibility", "course", string];
7
+ };
8
+ /**
9
+ * Returns a JSON-serialisable `value` once it has stopped changing for
10
+ * `delayMs`. Changes are detected structurally, so callers may pass a fresh
11
+ * object literal on every render without restarting the timer or looping.
12
+ */
13
+ export declare function useDebouncedValue<T>(value: T, delayMs: number): T;
14
+ /**
15
+ * Checks a draft (debounced by the caller). Disabled while the draft is empty,
16
+ * so an untouched form makes no request.
17
+ */
18
+ export declare const useBuiCheckContentAccessibility: (input: BuiCheckContentAccessibilityInput) => import('@tanstack/react-query').UseQueryResult<NoInfer<BuiAccessibilityReport>, Error>;
19
+ /** Checks every saved piece of authored content in one course. */
20
+ export declare const useBuiCourseAccessibilityReport: (courseId: string | undefined) => import('@tanstack/react-query').UseQueryResult<NoInfer<BuiCourseAccessibilityReport>, Error>;
21
+ //# sourceMappingURL=useBuiAccessibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBuiAccessibility.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/useBuiAccessibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EACV,sBAAsB,EACtB,iCAAiC,EACjC,4BAA4B,EAC7B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAU/B,eAAO,MAAM,iBAAiB;mBACb,iCAAiC;uBAE7B,MAAM;CAC1B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CASjE;AAED;;;GAGG;AACH,eAAO,MAAM,+BAA+B,GAAI,OAAO,iCAAiC,2FA0BvF,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,+BAA+B,GAAI,UAAU,MAAM,GAAG,SAAS,iGA2B3E,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { useBuildmyiq as e } from "../context/BuildmyiqContext.js";
2
+ import "../context/index.js";
3
+ import { wspaceFetch as t } from "./useBuiFiles.js";
4
+ import { hasCheckableContent as n } from "./accessibilityDraft.js";
5
+ import { useEffect as r, useMemo as i, useState as a } from "react";
6
+ import { useQuery as o } from "@tanstack/react-query";
7
+ //#region src/buildmyiq/hooks/useBuiAccessibility.ts
8
+ var s = "\n passed\n errorCount\n warningCount\n truncated\n issues { rule severity wcag wcagLevel message excerpt line }\n", c = {
9
+ draft: (e) => [
10
+ "buildmyiq",
11
+ "accessibility",
12
+ "draft",
13
+ e
14
+ ],
15
+ course: (e) => [
16
+ "buildmyiq",
17
+ "accessibility",
18
+ "course",
19
+ e
20
+ ]
21
+ };
22
+ function l(e, t) {
23
+ let n = JSON.stringify(e) ?? "null", [o, s] = a(n);
24
+ return r(() => {
25
+ let e = setTimeout(() => s(n), t);
26
+ return () => clearTimeout(e);
27
+ }, [n, t]), i(() => JSON.parse(o), [o]);
28
+ }
29
+ var u = (r) => {
30
+ let { apiGatewayUrl: i } = e();
31
+ return o({
32
+ queryKey: c.draft(r),
33
+ enabled: n(r),
34
+ placeholderData: (e) => e,
35
+ gcTime: 3e4,
36
+ retry: 1,
37
+ staleTime: Infinity,
38
+ refetchOnWindowFocus: !1,
39
+ refetchOnReconnect: !1,
40
+ queryFn: async () => (await t(`query BuiCheckContentAccessibility($input: BuiCheckContentAccessibilityInput!) {
41
+ buiCheckContentAccessibility(input: $input) { ${s} }
42
+ }`, { input: r }, i)).buiCheckContentAccessibility
43
+ });
44
+ }, d = (n) => {
45
+ let { apiGatewayUrl: r } = e();
46
+ return o({
47
+ queryKey: n ? c.course(n) : [
48
+ "buildmyiq",
49
+ "accessibility",
50
+ "course",
51
+ "nil"
52
+ ],
53
+ enabled: !!n,
54
+ staleTime: 0,
55
+ refetchOnWindowFocus: !1,
56
+ queryFn: async () => (await t(`query BuiCourseAccessibilityReport($courseId: ID!) {
57
+ buiCourseAccessibilityReport(courseId: $courseId) {
58
+ courseId passed errorCount warningCount itemsChecked itemsWithIssues truncated generatedAt
59
+ items { targetType targetId parentId title report { ${s} } }
60
+ }
61
+ }`, { courseId: n }, r)).buiCourseAccessibilityReport
62
+ });
63
+ };
64
+ //#endregion
65
+ export { c as accessibilityKeys, u as useBuiCheckContentAccessibility, d as useBuiCourseAccessibilityReport, l as useDebouncedValue };
66
+
67
+ //# sourceMappingURL=useBuiAccessibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBuiAccessibility.js","names":[],"sources":["../../../src/buildmyiq/hooks/useBuiAccessibility.ts"],"sourcesContent":["/**\n * Buildmyiq — authoring-time accessibility checker hooks (BOFF-4423).\n * @module buildmyiq/hooks/useBuiAccessibility\n *\n * Wraps the two read-only `wspace-buildmyiq-svc` queries:\n * - `buiCheckContentAccessibility` — checks a draft while the author types.\n * - `buiCourseAccessibilityReport` — checks every saved item in a course.\n *\n * The rules themselves live server-side (one source of truth shared with the\n * CLI/MCP surfaces); this file only transports them.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { useQuery } from '@tanstack/react-query';\n\nimport { useBuildmyiq } from '../context';\nimport type {\n BuiAccessibilityReport,\n BuiCheckContentAccessibilityInput,\n BuiCourseAccessibilityReport,\n} from '../types';\nimport { hasCheckableContent } from './accessibilityDraft';\nimport { wspaceFetch } from './useBuiFiles';\n\nexport { hasCheckableContent };\n\nconst REPORT_FIELDS = `\n passed\n errorCount\n warningCount\n truncated\n issues { rule severity wcag wcagLevel message excerpt line }\n`;\n\nexport const accessibilityKeys = {\n draft: (input: BuiCheckContentAccessibilityInput) =>\n ['buildmyiq', 'accessibility', 'draft', input] as const,\n course: (courseId: string) => ['buildmyiq', 'accessibility', 'course', courseId] as const,\n};\n\n/**\n * Returns a JSON-serialisable `value` once it has stopped changing for\n * `delayMs`. Changes are detected structurally, so callers may pass a fresh\n * object literal on every render without restarting the timer or looping.\n */\nexport function useDebouncedValue<T>(value: T, delayMs: number): T {\n const key = JSON.stringify(value) ?? 'null';\n const [debouncedKey, setDebouncedKey] = useState(key);\n useEffect(() => {\n const handle = setTimeout(() => setDebouncedKey(key), delayMs);\n return () => clearTimeout(handle);\n }, [key, delayMs]);\n // The key round-trips the same JSON-serialisable shape the caller passed in.\n return useMemo(() => JSON.parse(debouncedKey) as T, [debouncedKey]);\n}\n\n/**\n * Checks a draft (debounced by the caller). Disabled while the draft is empty,\n * so an untouched form makes no request.\n */\nexport const useBuiCheckContentAccessibility = (input: BuiCheckContentAccessibilityInput) => {\n const { apiGatewayUrl } = useBuildmyiq();\n return useQuery({\n queryKey: accessibilityKeys.draft(input),\n enabled: hasCheckableContent(input),\n placeholderData: (previous) => previous,\n // Every debounced draft is its own key: keep old drafts briefly, and fail\n // fast so the author sees \"unavailable\" instead of a long retry spinner.\n gcTime: 30_000,\n retry: 1,\n // A draft's result never changes for the same input: do not refetch it on\n // focus or reconnect (that would flash \"Checking…\" and re-announce).\n staleTime: Number.POSITIVE_INFINITY,\n refetchOnWindowFocus: false,\n refetchOnReconnect: false,\n queryFn: async () => {\n const data = await wspaceFetch<{ buiCheckContentAccessibility: BuiAccessibilityReport }>(\n `query BuiCheckContentAccessibility($input: BuiCheckContentAccessibilityInput!) {\n buiCheckContentAccessibility(input: $input) { ${REPORT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return data.buiCheckContentAccessibility;\n },\n });\n};\n\n/** Checks every saved piece of authored content in one course. */\nexport const useBuiCourseAccessibilityReport = (courseId: string | undefined) => {\n const { apiGatewayUrl } = useBuildmyiq();\n return useQuery({\n queryKey: courseId\n ? accessibilityKeys.course(courseId)\n : ['buildmyiq', 'accessibility', 'course', 'nil'],\n enabled: Boolean(courseId),\n // Fresh on every visit to the tab (authors fix content elsewhere), but no\n // background refetch on focus: the tab has an explicit \"Check again\".\n staleTime: 0,\n refetchOnWindowFocus: false,\n queryFn: async () => {\n const data = await wspaceFetch<{\n buiCourseAccessibilityReport: BuiCourseAccessibilityReport;\n }>(\n `query BuiCourseAccessibilityReport($courseId: ID!) {\n buiCourseAccessibilityReport(courseId: $courseId) {\n courseId passed errorCount warningCount itemsChecked itemsWithIssues truncated generatedAt\n items { targetType targetId parentId title report { ${REPORT_FIELDS} } }\n }\n }`,\n { courseId },\n apiGatewayUrl\n );\n return data.buiCourseAccessibilityReport;\n },\n });\n};\n"],"mappings":";;;;;;;AA0BA,IAAM,IAAgB,2HAQT,IAAoB;CAC/B,QAAQ,MACN;EAAC;EAAa;EAAiB;EAAS;CAAK;CAC/C,SAAS,MAAqB;EAAC;EAAa;EAAiB;EAAU;CAAQ;AACjF;AAOA,SAAgB,EAAqB,GAAU,GAAoB;CACjE,IAAM,IAAM,KAAK,UAAU,CAAK,KAAK,QAC/B,CAAC,GAAc,KAAmB,EAAS,CAAG;CAMpD,OALA,QAAgB;EACd,IAAM,IAAS,iBAAiB,EAAgB,CAAG,GAAG,CAAO;EAC7D,aAAa,aAAa,CAAM;CAClC,GAAG,CAAC,GAAK,CAAO,CAAC,GAEV,QAAc,KAAK,MAAM,CAAY,GAAQ,CAAC,CAAY,CAAC;AACpE;AAMA,IAAa,KAAmC,MAA6C;CAC3F,IAAM,EAAE,qBAAkB,EAAa;CACvC,OAAO,EAAS;EACd,UAAU,EAAkB,MAAM,CAAK;EACvC,SAAS,EAAoB,CAAK;EAClC,kBAAkB,MAAa;EAG/B,QAAQ;EACR,OAAO;EAGP,WAAW;EACX,sBAAsB;EACtB,oBAAoB;EACpB,SAAS,aAQA,MAPY,EACjB;0DACkD,EAAc;YAEhE,EAAE,SAAM,GACR,CACF,GACY;CAEhB,CAAC;AACH,GAGa,KAAmC,MAAiC;CAC/E,IAAM,EAAE,qBAAkB,EAAa;CACvC,OAAO,EAAS;EACd,UAAU,IACN,EAAkB,OAAO,CAAQ,IACjC;GAAC;GAAa;GAAiB;GAAU;EAAK;EAClD,SAAS,EAAQ;EAGjB,WAAW;EACX,sBAAsB;EACtB,SAAS,aAaA,MAZY,EAGjB;;;kEAG0D,EAAc;;YAGxE,EAAE,YAAS,GACX,CACF,GACY;CAEhB,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"useBuiProctoring.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/useBuiProctoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,+BAA+B,EAC/B,gCAAgC,EACjC,MAAM,UAAU,CAAC;AAgBlB;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAAI,cAAc,MAAM,GAAG,SAAS,EAAE,iBAAc,gGAwBzF,CAAC;AAEF,eAAO,MAAM,4BAA4B,uGAkBxC,CAAC;AAEF,eAAO,MAAM,8BAA8B;QAIR,MAAM;WAAS,gCAAgC;WAejF,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,+BAA+B,uGAkB3C,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,wBAAwB,GACnC,MAAM;IAAE,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAC7E,iBAAc,wGAuBf,CAAC;AAEF,eAAO,MAAM,6BAA6B;QAIP,MAAM;WAAS,+BAA+B;WAYhF,CAAC"}
1
+ {"version":3,"file":"useBuiProctoring.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/useBuiProctoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,+BAA+B,EAC/B,gCAAgC,EACjC,MAAM,UAAU,CAAC;AAoBlB;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAAI,cAAc,MAAM,GAAG,SAAS,EAAE,iBAAc,gGAwBzF,CAAC;AAEF,eAAO,MAAM,4BAA4B,uGAkBxC,CAAC;AAEF,eAAO,MAAM,8BAA8B;QAIR,MAAM;WAAS,gCAAgC;WAejF,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,+BAA+B,uGAkB3C,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,wBAAwB,GACnC,MAAM;IAAE,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAC7E,iBAAc,wGAuBf,CAAC;AAEF,eAAO,MAAM,6BAA6B;QAIP,MAAM;WAAS,+BAA+B;WAYhF,CAAC"}
@@ -3,7 +3,7 @@ import "../context/index.js";
3
3
  import { wspaceFetch as t } from "./useBuiFiles.js";
4
4
  import { useMutation as n, useQuery as r, useQueryClient as i } from "@tanstack/react-query";
5
5
  //#region src/buildmyiq/hooks/useBuiProctoring.ts
6
- var a = "\n id workspaceId assessmentId learnerId status lockdownAcknowledgedAt violationCount\n reviewedById reviewedAt reviewNotes expiresAt createdAt updatedAt\n identityFile { id name downloadUrl mimeType }\n", o = {
6
+ var a = "\n id workspaceId assessmentId learnerId status lockdownAcknowledgedAt violationCount\n reviewedById reviewedAt reviewNotes expiresAt createdAt updatedAt\n identityFile { id }\n", o = {
7
7
  mine: (e) => [
8
8
  "buildmyiq",
9
9
  "proctoring",
@@ -1 +1 @@
1
- {"version":3,"file":"useBuiProctoring.js","names":[],"sources":["../../../src/buildmyiq/hooks/useBuiProctoring.ts"],"sourcesContent":["/**\n * Buildmyiq — high-stakes exam proctoring hooks (BOFF-4431).\n * @module buildmyiq/hooks/useBuiProctoring\n *\n * Wired to the `wspace-buildmyiq-svc` proctoring contract:\n * - learner (self-scoped): `buiMyProctoringSession`, `buiStartProctoringSession`,\n * `buiSubmitProctoringIdentity`, `buiReportProctoringViolation`\n * - reviewer (workspace-scoped): `buiListProctoringSessions`,\n * `buiReviewProctoringSession`\n *\n * The backend is the gate: `buiSubmitAssessment` refuses a `requiresProctoring`\n * assessment unless the learner's latest session is APPROVED and unexpired.\n * These hooks only drive the UI through that lifecycle.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { useBuildmyiq } from '../context';\nimport { wspaceFetch } from './useBuiFiles';\nimport type {\n BuiConnection,\n BuiProctoringSession,\n BuiProctoringStatus,\n BuiReviewProctoringSessionInput,\n BuiSubmitProctoringIdentityInput,\n} from '../types';\n\nconst PROCTORING_SESSION_FIELDS = `\n id workspaceId assessmentId learnerId status lockdownAcknowledgedAt violationCount\n reviewedById reviewedAt reviewNotes expiresAt createdAt updatedAt\n identityFile { id name downloadUrl mimeType }\n`;\n\nconst PROCTORING_KEY = {\n mine: (assessmentId: string) => ['buildmyiq', 'proctoring', 'mine', assessmentId] as const,\n queue: ['buildmyiq', 'proctoring', 'queue'] as const,\n};\n\n/** How often the learner's waiting screen re-checks for a reviewer decision. */\nconst AWAITING_REVIEW_POLL_MS = 15_000;\n\n/**\n * The calling learner's most recent proctoring session for an assessment\n * (null when they have never started one). Polls while a reviewer decision\n * is pending so the exam unlocks without a manual refresh.\n */\nexport const useBuiMyProctoringSession = (assessmentId: string | undefined, enabled = true) => {\n const { apiGatewayUrl } = useBuildmyiq();\n return useQuery({\n queryKey: assessmentId\n ? PROCTORING_KEY.mine(assessmentId)\n : ['buildmyiq', 'proctoring', 'mine', 'nil'],\n enabled: Boolean(assessmentId) && enabled,\n queryFn: async () => {\n const data = await wspaceFetch<{ buiMyProctoringSession: BuiProctoringSession | null }>(\n `query BuiMyProctoringSession($assessmentId: ID!) {\n buiMyProctoringSession(assessmentId: $assessmentId) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n { assessmentId },\n apiGatewayUrl\n );\n return data.buiMyProctoringSession;\n },\n refetchInterval: (query) => {\n const status = query.state.data?.status;\n return status === 'UNDER_REVIEW' || status === 'IDENTITY_SUBMITTED'\n ? AWAITING_REVIEW_POLL_MS\n : false;\n },\n });\n};\n\nexport const useBuiStartProctoringSession = () => {\n const { apiGatewayUrl } = useBuildmyiq();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (assessmentId: string) => {\n const data = await wspaceFetch<{ buiStartProctoringSession: BuiProctoringSession }>(\n `mutation BuiStartProctoringSession($assessmentId: ID!) {\n buiStartProctoringSession(assessmentId: $assessmentId) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n { assessmentId },\n apiGatewayUrl\n );\n return data.buiStartProctoringSession;\n },\n onSuccess: (session) => {\n qc.setQueryData(PROCTORING_KEY.mine(session.assessmentId), session);\n },\n });\n};\n\nexport const useBuiSubmitProctoringIdentity = () => {\n const { apiGatewayUrl } = useBuildmyiq();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; input: BuiSubmitProctoringIdentityInput }) => {\n const data = await wspaceFetch<{ buiSubmitProctoringIdentity: BuiProctoringSession }>(\n `mutation BuiSubmitProctoringIdentity($id: ID!, $input: BuiSubmitProctoringIdentityInput!) {\n buiSubmitProctoringIdentity(id: $id, input: $input) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n args,\n apiGatewayUrl\n );\n return data.buiSubmitProctoringIdentity;\n },\n onSuccess: (session) => {\n qc.setQueryData(PROCTORING_KEY.mine(session.assessmentId), session);\n void qc.invalidateQueries({ queryKey: PROCTORING_KEY.queue });\n },\n });\n};\n\n/** Records one lockdown violation (tab switch, window blur, fullscreen exit, copy/paste). */\nexport const useBuiReportProctoringViolation = () => {\n const { apiGatewayUrl } = useBuildmyiq();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await wspaceFetch<{ buiReportProctoringViolation: BuiProctoringSession }>(\n `mutation BuiReportProctoringViolation($id: ID!) {\n buiReportProctoringViolation(id: $id) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return data.buiReportProctoringViolation;\n },\n onSuccess: (session) => {\n qc.setQueryData(PROCTORING_KEY.mine(session.assessmentId), session);\n },\n });\n};\n\n/** Reviewer queue: proctoring sessions in the workspace, optionally filtered by status. */\nexport const useBuiProctoringSessions = (\n args: { status?: BuiProctoringStatus; assessmentId?: string; limit?: number },\n enabled = true\n) => {\n const { apiGatewayUrl } = useBuildmyiq();\n const { status, assessmentId, limit = 50 } = args;\n return useQuery({\n queryKey: [...PROCTORING_KEY.queue, status ?? 'ALL', assessmentId ?? 'ALL', limit],\n enabled,\n queryFn: async () => {\n const data = await wspaceFetch<{\n buiListProctoringSessions: BuiConnection<BuiProctoringSession>;\n }>(\n `query BuiListProctoringSessions($assessmentId: ID, $status: BuiProctoringStatus, $pagination: PaginationInput) {\n buiListProctoringSessions(assessmentId: $assessmentId, status: $status, pagination: $pagination) {\n items { ${PROCTORING_SESSION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { assessmentId, status, pagination: { limit } },\n apiGatewayUrl\n );\n return data.buiListProctoringSessions;\n },\n });\n};\n\nexport const useBuiReviewProctoringSession = () => {\n const { apiGatewayUrl } = useBuildmyiq();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; input: BuiReviewProctoringSessionInput }) => {\n const data = await wspaceFetch<{ buiReviewProctoringSession: BuiProctoringSession }>(\n `mutation BuiReviewProctoringSession($id: ID!, $input: BuiReviewProctoringSessionInput!) {\n buiReviewProctoringSession(id: $id, input: $input) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n args,\n apiGatewayUrl\n );\n return data.buiReviewProctoringSession;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: PROCTORING_KEY.queue }),\n });\n};\n"],"mappings":";;;;;AA2BA,IAAM,IAA4B,kNAM5B,IAAiB;CACrB,OAAO,MAAyB;EAAC;EAAa;EAAc;EAAQ;CAAY;CAChF,OAAO;EAAC;EAAa;EAAc;CAAO;AAC5C,GAGM,IAA0B,MAOnB,KAA6B,GAAkC,IAAU,OAAS;CAC7F,IAAM,EAAE,qBAAkB,EAAa;CACvC,OAAO,EAAS;EACd,UAAU,IACN,EAAe,KAAK,CAAY,IAChC;GAAC;GAAa;GAAc;GAAQ;EAAK;EAC7C,SAAS,EAAQ,KAAiB;EAClC,SAAS,aAQA,MAPY,EACjB;kEAC0D,EAA0B;YAEpF,EAAE,gBAAa,GACf,CACF,GACY;EAEd,kBAAkB,MAAU;GAC1B,IAAM,IAAS,EAAM,MAAM,MAAM;GACjC,OAAO,MAAW,kBAAkB,MAAW,uBAC3C,IACA;EACN;CACF,CAAC;AACH,GAEa,UAAqC;CAChD,IAAM,EAAE,qBAAkB,EAAa,GACjC,IAAK,EAAe;CAC1B,OAAO,EAAY;EACjB,YAAY,OAAO,OAQV,MAPY,EACjB;qEAC6D,EAA0B;YAEvF,EAAE,gBAAa,GACf,CACF,GACY;EAEd,YAAY,MAAY;GACtB,EAAG,aAAa,EAAe,KAAK,EAAQ,YAAY,GAAG,CAAO;EACpE;CACF,CAAC;AACH,GAEa,UAAuC;CAClD,IAAM,EAAE,qBAAkB,EAAa,GACjC,IAAK,EAAe;CAC1B,OAAO,EAAY;EACjB,YAAY,OAAO,OAQV,MAPY,EACjB;kEAC0D,EAA0B;YAEpF,GACA,CACF,GACY;EAEd,YAAY,MAAY;GAEtB,AADA,EAAG,aAAa,EAAe,KAAK,EAAQ,YAAY,GAAG,CAAO,GAClE,EAAQ,kBAAkB,EAAE,UAAU,EAAe,MAAM,CAAC;EAC9D;CACF,CAAC;AACH,GAGa,UAAwC;CACnD,IAAM,EAAE,qBAAkB,EAAa,GACjC,IAAK,EAAe;CAC1B,OAAO,EAAY;EACjB,YAAY,OAAO,OAQV,MAPY,EACjB;oDAC4C,EAA0B;YAEtE,EAAE,MAAG,GACL,CACF,GACY;EAEd,YAAY,MAAY;GACtB,EAAG,aAAa,EAAe,KAAK,EAAQ,YAAY,GAAG,CAAO;EACpE;CACF,CAAC;AACH,GAGa,KACX,GACA,IAAU,OACP;CACH,IAAM,EAAE,qBAAkB,EAAa,GACjC,EAAE,WAAQ,iBAAc,WAAQ,OAAO;CAC7C,OAAO,EAAS;EACd,UAAU;GAAC,GAAG,EAAe;GAAO,KAAU;GAAO,KAAgB;GAAO;EAAK;EACjF;EACA,SAAS,aAaA,MAZY,EAGjB;;sBAEc,EAA0B;;;YAIxC;GAAE;GAAc;GAAQ,YAAY,EAAE,SAAM;EAAE,GAC9C,CACF,GACY;CAEhB,CAAC;AACH,GAEa,UAAsC;CACjD,IAAM,EAAE,qBAAkB,EAAa,GACjC,IAAK,EAAe;CAC1B,OAAO,EAAY;EACjB,YAAY,OAAO,OAQV,MAPY,EACjB;iEACyD,EAA0B;YAEnF,GACA,CACF,GACY;EAEd,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAe,MAAM,CAAC;CAC1E,CAAC;AACH"}
1
+ {"version":3,"file":"useBuiProctoring.js","names":[],"sources":["../../../src/buildmyiq/hooks/useBuiProctoring.ts"],"sourcesContent":["/**\n * Buildmyiq — high-stakes exam proctoring hooks (BOFF-4431).\n * @module buildmyiq/hooks/useBuiProctoring\n *\n * Wired to the `wspace-buildmyiq-svc` proctoring contract:\n * - learner (self-scoped): `buiMyProctoringSession`, `buiStartProctoringSession`,\n * `buiSubmitProctoringIdentity`, `buiReportProctoringViolation`\n * - reviewer (workspace-scoped): `buiListProctoringSessions`,\n * `buiReviewProctoringSession`\n *\n * The backend is the gate: `buiSubmitAssessment` refuses a `requiresProctoring`\n * assessment unless the learner's latest session is APPROVED and unexpired.\n * These hooks only drive the UI through that lifecycle.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { useBuildmyiq } from '../context';\nimport { wspaceFetch } from './useBuiFiles';\nimport type {\n BuiConnection,\n BuiProctoringSession,\n BuiProctoringStatus,\n BuiReviewProctoringSessionInput,\n BuiSubmitProctoringIdentityInput,\n} from '../types';\n\n// `identityFile` selects ONLY `id`: wspace-files-svc's File entity has no\n// __resolveReference, so any other field on a federated File stub fails the\n// whole operation. The reviewer page resolves the file through the files\n// graph's root `getFile` (FileLink) instead.\nconst PROCTORING_SESSION_FIELDS = `\n id workspaceId assessmentId learnerId status lockdownAcknowledgedAt violationCount\n reviewedById reviewedAt reviewNotes expiresAt createdAt updatedAt\n identityFile { id }\n`;\n\nconst PROCTORING_KEY = {\n mine: (assessmentId: string) => ['buildmyiq', 'proctoring', 'mine', assessmentId] as const,\n queue: ['buildmyiq', 'proctoring', 'queue'] as const,\n};\n\n/** How often the learner's waiting screen re-checks for a reviewer decision. */\nconst AWAITING_REVIEW_POLL_MS = 15_000;\n\n/**\n * The calling learner's most recent proctoring session for an assessment\n * (null when they have never started one). Polls while a reviewer decision\n * is pending so the exam unlocks without a manual refresh.\n */\nexport const useBuiMyProctoringSession = (assessmentId: string | undefined, enabled = true) => {\n const { apiGatewayUrl } = useBuildmyiq();\n return useQuery({\n queryKey: assessmentId\n ? PROCTORING_KEY.mine(assessmentId)\n : ['buildmyiq', 'proctoring', 'mine', 'nil'],\n enabled: Boolean(assessmentId) && enabled,\n queryFn: async () => {\n const data = await wspaceFetch<{ buiMyProctoringSession: BuiProctoringSession | null }>(\n `query BuiMyProctoringSession($assessmentId: ID!) {\n buiMyProctoringSession(assessmentId: $assessmentId) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n { assessmentId },\n apiGatewayUrl\n );\n return data.buiMyProctoringSession;\n },\n refetchInterval: (query) => {\n const status = query.state.data?.status;\n return status === 'UNDER_REVIEW' || status === 'IDENTITY_SUBMITTED'\n ? AWAITING_REVIEW_POLL_MS\n : false;\n },\n });\n};\n\nexport const useBuiStartProctoringSession = () => {\n const { apiGatewayUrl } = useBuildmyiq();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (assessmentId: string) => {\n const data = await wspaceFetch<{ buiStartProctoringSession: BuiProctoringSession }>(\n `mutation BuiStartProctoringSession($assessmentId: ID!) {\n buiStartProctoringSession(assessmentId: $assessmentId) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n { assessmentId },\n apiGatewayUrl\n );\n return data.buiStartProctoringSession;\n },\n onSuccess: (session) => {\n qc.setQueryData(PROCTORING_KEY.mine(session.assessmentId), session);\n },\n });\n};\n\nexport const useBuiSubmitProctoringIdentity = () => {\n const { apiGatewayUrl } = useBuildmyiq();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; input: BuiSubmitProctoringIdentityInput }) => {\n const data = await wspaceFetch<{ buiSubmitProctoringIdentity: BuiProctoringSession }>(\n `mutation BuiSubmitProctoringIdentity($id: ID!, $input: BuiSubmitProctoringIdentityInput!) {\n buiSubmitProctoringIdentity(id: $id, input: $input) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n args,\n apiGatewayUrl\n );\n return data.buiSubmitProctoringIdentity;\n },\n onSuccess: (session) => {\n qc.setQueryData(PROCTORING_KEY.mine(session.assessmentId), session);\n void qc.invalidateQueries({ queryKey: PROCTORING_KEY.queue });\n },\n });\n};\n\n/** Records one lockdown violation (tab switch, window blur, fullscreen exit, copy/paste). */\nexport const useBuiReportProctoringViolation = () => {\n const { apiGatewayUrl } = useBuildmyiq();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await wspaceFetch<{ buiReportProctoringViolation: BuiProctoringSession }>(\n `mutation BuiReportProctoringViolation($id: ID!) {\n buiReportProctoringViolation(id: $id) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return data.buiReportProctoringViolation;\n },\n onSuccess: (session) => {\n qc.setQueryData(PROCTORING_KEY.mine(session.assessmentId), session);\n },\n });\n};\n\n/** Reviewer queue: proctoring sessions in the workspace, optionally filtered by status. */\nexport const useBuiProctoringSessions = (\n args: { status?: BuiProctoringStatus; assessmentId?: string; limit?: number },\n enabled = true\n) => {\n const { apiGatewayUrl } = useBuildmyiq();\n const { status, assessmentId, limit = 50 } = args;\n return useQuery({\n queryKey: [...PROCTORING_KEY.queue, status ?? 'ALL', assessmentId ?? 'ALL', limit],\n enabled,\n queryFn: async () => {\n const data = await wspaceFetch<{\n buiListProctoringSessions: BuiConnection<BuiProctoringSession>;\n }>(\n `query BuiListProctoringSessions($assessmentId: ID, $status: BuiProctoringStatus, $pagination: PaginationInput) {\n buiListProctoringSessions(assessmentId: $assessmentId, status: $status, pagination: $pagination) {\n items { ${PROCTORING_SESSION_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { assessmentId, status, pagination: { limit } },\n apiGatewayUrl\n );\n return data.buiListProctoringSessions;\n },\n });\n};\n\nexport const useBuiReviewProctoringSession = () => {\n const { apiGatewayUrl } = useBuildmyiq();\n const qc = useQueryClient();\n return useMutation({\n mutationFn: async (args: { id: string; input: BuiReviewProctoringSessionInput }) => {\n const data = await wspaceFetch<{ buiReviewProctoringSession: BuiProctoringSession }>(\n `mutation BuiReviewProctoringSession($id: ID!, $input: BuiReviewProctoringSessionInput!) {\n buiReviewProctoringSession(id: $id, input: $input) { ${PROCTORING_SESSION_FIELDS} }\n }`,\n args,\n apiGatewayUrl\n );\n return data.buiReviewProctoringSession;\n },\n onSuccess: () => qc.invalidateQueries({ queryKey: PROCTORING_KEY.queue }),\n });\n};\n"],"mappings":";;;;;AA+BA,IAAM,IAA4B,wLAM5B,IAAiB;CACrB,OAAO,MAAyB;EAAC;EAAa;EAAc;EAAQ;CAAY;CAChF,OAAO;EAAC;EAAa;EAAc;CAAO;AAC5C,GAGM,IAA0B,MAOnB,KAA6B,GAAkC,IAAU,OAAS;CAC7F,IAAM,EAAE,qBAAkB,EAAa;CACvC,OAAO,EAAS;EACd,UAAU,IACN,EAAe,KAAK,CAAY,IAChC;GAAC;GAAa;GAAc;GAAQ;EAAK;EAC7C,SAAS,EAAQ,KAAiB;EAClC,SAAS,aAQA,MAPY,EACjB;kEAC0D,EAA0B;YAEpF,EAAE,gBAAa,GACf,CACF,GACY;EAEd,kBAAkB,MAAU;GAC1B,IAAM,IAAS,EAAM,MAAM,MAAM;GACjC,OAAO,MAAW,kBAAkB,MAAW,uBAC3C,IACA;EACN;CACF,CAAC;AACH,GAEa,UAAqC;CAChD,IAAM,EAAE,qBAAkB,EAAa,GACjC,IAAK,EAAe;CAC1B,OAAO,EAAY;EACjB,YAAY,OAAO,OAQV,MAPY,EACjB;qEAC6D,EAA0B;YAEvF,EAAE,gBAAa,GACf,CACF,GACY;EAEd,YAAY,MAAY;GACtB,EAAG,aAAa,EAAe,KAAK,EAAQ,YAAY,GAAG,CAAO;EACpE;CACF,CAAC;AACH,GAEa,UAAuC;CAClD,IAAM,EAAE,qBAAkB,EAAa,GACjC,IAAK,EAAe;CAC1B,OAAO,EAAY;EACjB,YAAY,OAAO,OAQV,MAPY,EACjB;kEAC0D,EAA0B;YAEpF,GACA,CACF,GACY;EAEd,YAAY,MAAY;GAEtB,AADA,EAAG,aAAa,EAAe,KAAK,EAAQ,YAAY,GAAG,CAAO,GAClE,EAAQ,kBAAkB,EAAE,UAAU,EAAe,MAAM,CAAC;EAC9D;CACF,CAAC;AACH,GAGa,UAAwC;CACnD,IAAM,EAAE,qBAAkB,EAAa,GACjC,IAAK,EAAe;CAC1B,OAAO,EAAY;EACjB,YAAY,OAAO,OAQV,MAPY,EACjB;oDAC4C,EAA0B;YAEtE,EAAE,MAAG,GACL,CACF,GACY;EAEd,YAAY,MAAY;GACtB,EAAG,aAAa,EAAe,KAAK,EAAQ,YAAY,GAAG,CAAO;EACpE;CACF,CAAC;AACH,GAGa,KACX,GACA,IAAU,OACP;CACH,IAAM,EAAE,qBAAkB,EAAa,GACjC,EAAE,WAAQ,iBAAc,WAAQ,OAAO;CAC7C,OAAO,EAAS;EACd,UAAU;GAAC,GAAG,EAAe;GAAO,KAAU;GAAO,KAAgB;GAAO;EAAK;EACjF;EACA,SAAS,aAaA,MAZY,EAGjB;;sBAEc,EAA0B;;;YAIxC;GAAE;GAAc;GAAQ,YAAY,EAAE,SAAM;EAAE,GAC9C,CACF,GACY;CAEhB,CAAC;AACH,GAEa,UAAsC;CACjD,IAAM,EAAE,qBAAkB,EAAa,GACjC,IAAK,EAAe;CAC1B,OAAO,EAAY;EACjB,YAAY,OAAO,OAQV,MAPY,EACjB;iEACyD,EAA0B;YAEnF,GACA,CACF,GACY;EAEd,iBAAiB,EAAG,kBAAkB,EAAE,UAAU,EAAe,MAAM,CAAC;CAC1E,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"useBuildmyiqApi.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/useBuildmyiqApi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useBuildmyiqApi.d.ts","sourceRoot":"","sources":["../../../src/buildmyiq/hooks/useBuildmyiqApi.ts"],"names":[],"mappings":"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"}
@@ -94,11 +94,7 @@ var o = () => {
94
94
  ${S}
95
95
  cohort { ${b} }
96
96
  lessonProgress { items { ${x} } }
97
- `, C = `
98
- id workspaceId courseId learnerId enrollmentId serial status issuedAt expiresAt
99
- revokedAt finalScore verificationCode recipientNameSnapshot createdAt updatedAt
100
- file { ${d} }
101
- `, w = "\n id workspaceId sessionId role content groundingLessonIds adaptiveLevel createdAt\n", T = `
97
+ `, C = "\n id workspaceId courseId learnerId enrollmentId serial status issuedAt expiresAt\n revokedAt finalScore verificationCode recipientNameSnapshot createdAt updatedAt\n file { id }\n", w = "\n id workspaceId sessionId role content groundingLessonIds adaptiveLevel createdAt\n", T = `
102
98
  id workspaceId courseId lessonId learnerId createdAt updatedAt
103
99
  messages { ${w} }
104
100
  `, ie = (e) => ({