@burdenoff/microfe-technospam 2026.1101.5 → 2026.1102.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/generated/wspace-types.d.ts +7468 -141
  2. package/dist/generated/wspace-types.d.ts.map +1 -1
  3. package/dist/index.js +5 -3
  4. package/dist/node_modules/@codemirror/autocomplete/dist/index.js +527 -0
  5. package/dist/node_modules/@codemirror/autocomplete/dist/index.js.map +1 -0
  6. package/dist/node_modules/@codemirror/commands/dist/index.js +1108 -0
  7. package/dist/node_modules/@codemirror/commands/dist/index.js.map +1 -0
  8. package/dist/node_modules/@codemirror/lang-go/dist/index.js +206 -0
  9. package/dist/node_modules/@codemirror/lang-go/dist/index.js.map +1 -0
  10. package/dist/node_modules/@codemirror/lang-javascript/dist/index.js +321 -0
  11. package/dist/node_modules/@codemirror/lang-javascript/dist/index.js.map +1 -0
  12. package/dist/node_modules/@codemirror/lang-python/dist/index.js +265 -0
  13. package/dist/node_modules/@codemirror/lang-python/dist/index.js.map +1 -0
  14. package/dist/node_modules/@codemirror/language/dist/index.js +957 -0
  15. package/dist/node_modules/@codemirror/language/dist/index.js.map +1 -0
  16. package/dist/node_modules/@codemirror/legacy-modes/mode/ruby.js +164 -0
  17. package/dist/node_modules/@codemirror/legacy-modes/mode/ruby.js.map +1 -0
  18. package/dist/node_modules/@codemirror/legacy-modes/mode/shell.js +109 -0
  19. package/dist/node_modules/@codemirror/legacy-modes/mode/shell.js.map +1 -0
  20. package/dist/node_modules/@codemirror/state/dist/index.js +1739 -0
  21. package/dist/node_modules/@codemirror/state/dist/index.js.map +1 -0
  22. package/dist/node_modules/@codemirror/streamparser/dist/index.js +70 -0
  23. package/dist/node_modules/@codemirror/streamparser/dist/index.js.map +1 -0
  24. package/dist/node_modules/@codemirror/view/dist/index.js +5427 -0
  25. package/dist/node_modules/@codemirror/view/dist/index.js.map +1 -0
  26. package/dist/node_modules/@lezer/common/dist/index.js +896 -0
  27. package/dist/node_modules/@lezer/common/dist/index.js.map +1 -0
  28. package/dist/node_modules/@lezer/go/dist/index.js +215 -0
  29. package/dist/node_modules/@lezer/go/dist/index.js.map +1 -0
  30. package/dist/node_modules/@lezer/highlight/dist/index.js +395 -0
  31. package/dist/node_modules/@lezer/highlight/dist/index.js.map +1 -0
  32. package/dist/node_modules/@lezer/javascript/dist/index.js +437 -0
  33. package/dist/node_modules/@lezer/javascript/dist/index.js.map +1 -0
  34. package/dist/node_modules/@lezer/lr/dist/index.js +842 -0
  35. package/dist/node_modules/@lezer/lr/dist/index.js.map +1 -0
  36. package/dist/node_modules/@lezer/python/dist/index.js +352 -0
  37. package/dist/node_modules/@lezer/python/dist/index.js.map +1 -0
  38. package/dist/node_modules/@marijn/find-cluster-break/src/index.js +66 -0
  39. package/dist/node_modules/@marijn/find-cluster-break/src/index.js.map +1 -0
  40. package/dist/node_modules/style-mod/src/style-mod.js +74 -0
  41. package/dist/node_modules/style-mod/src/style-mod.js.map +1 -0
  42. package/dist/node_modules/w3c-keyname/index.js +90 -0
  43. package/dist/node_modules/w3c-keyname/index.js.map +1 -0
  44. package/dist/stories/fixtures/technospamFixtures.d.ts.map +1 -1
  45. package/dist/stories/journeys/Problems.stories.d.ts.map +1 -1
  46. package/dist/technospam/api/technospamApi.d.ts +39 -0
  47. package/dist/technospam/api/technospamApi.d.ts.map +1 -1
  48. package/dist/technospam/api/technospamApi.js +120 -86
  49. package/dist/technospam/api/technospamApi.js.map +1 -1
  50. package/dist/technospam/components/CertificateVerifyLink.d.ts +11 -0
  51. package/dist/technospam/components/CertificateVerifyLink.d.ts.map +1 -0
  52. package/dist/technospam/components/CertificateVerifyLink.js +63 -0
  53. package/dist/technospam/components/CertificateVerifyLink.js.map +1 -0
  54. package/dist/technospam/components/SubmissionViews.d.ts +6 -2
  55. package/dist/technospam/components/SubmissionViews.d.ts.map +1 -1
  56. package/dist/technospam/components/SubmissionViews.js +6 -5
  57. package/dist/technospam/components/SubmissionViews.js.map +1 -1
  58. package/dist/technospam/components/TechnoSpamErrorBoundary.d.ts +6 -0
  59. package/dist/technospam/components/TechnoSpamErrorBoundary.d.ts.map +1 -1
  60. package/dist/technospam/components/TechnoSpamErrorBoundary.js +2 -2
  61. package/dist/technospam/components/TechnoSpamErrorBoundary.js.map +1 -1
  62. package/dist/technospam/components/editor/CodeEditor.d.ts +26 -0
  63. package/dist/technospam/components/editor/CodeEditor.d.ts.map +1 -0
  64. package/dist/technospam/components/editor/CodeEditor.js +102 -0
  65. package/dist/technospam/components/editor/CodeEditor.js.map +1 -0
  66. package/dist/technospam/components/editor/RunOutputPanel.d.ts +14 -0
  67. package/dist/technospam/components/editor/RunOutputPanel.d.ts.map +1 -0
  68. package/dist/technospam/components/editor/RunOutputPanel.js +127 -0
  69. package/dist/technospam/components/editor/RunOutputPanel.js.map +1 -0
  70. package/dist/technospam/components/editor/editorLanguages.d.ts +11 -0
  71. package/dist/technospam/components/editor/editorLanguages.d.ts.map +1 -0
  72. package/dist/technospam/components/editor/editorLanguages.js +30 -0
  73. package/dist/technospam/components/editor/editorLanguages.js.map +1 -0
  74. package/dist/technospam/components/editor/editorTheme.d.ts +11 -0
  75. package/dist/technospam/components/editor/editorTheme.d.ts.map +1 -0
  76. package/dist/technospam/components/editor/editorTheme.js +120 -0
  77. package/dist/technospam/components/editor/editorTheme.js.map +1 -0
  78. package/dist/technospam/components/index.d.ts +1 -0
  79. package/dist/technospam/components/index.d.ts.map +1 -1
  80. package/dist/technospam/components/index.js +1 -0
  81. package/dist/technospam/hooks/useSolutionRunner.d.ts +35 -0
  82. package/dist/technospam/hooks/useSolutionRunner.d.ts.map +1 -0
  83. package/dist/technospam/hooks/useSolutionRunner.js +66 -0
  84. package/dist/technospam/hooks/useSolutionRunner.js.map +1 -0
  85. package/dist/technospam/hooks/useTechnoSpamAnalytics.d.ts +1 -1
  86. package/dist/technospam/hooks/useTechnoSpamAnalytics.d.ts.map +1 -1
  87. package/dist/technospam/hooks/useTechnoSpamAnalytics.js.map +1 -1
  88. package/dist/technospam/index.d.ts +2 -0
  89. package/dist/technospam/index.d.ts.map +1 -1
  90. package/dist/technospam/index.js +2 -0
  91. package/dist/technospam/lib/certificateVerify.d.ts +71 -0
  92. package/dist/technospam/lib/certificateVerify.d.ts.map +1 -0
  93. package/dist/technospam/lib/certificateVerify.js +55 -0
  94. package/dist/technospam/lib/certificateVerify.js.map +1 -0
  95. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.d.ts.map +1 -1
  96. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js +416 -263
  97. package/dist/technospam/pages/ApplicationsProblemDetailsPagePage.js.map +1 -1
  98. package/dist/technospam/pages/CoursesCourseDetailsPagePage.d.ts.map +1 -1
  99. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js +236 -231
  100. package/dist/technospam/pages/CoursesCourseDetailsPagePage.js.map +1 -1
  101. package/dist/technospam/pages/CoursesMyLearningPagePage.d.ts.map +1 -1
  102. package/dist/technospam/pages/CoursesMyLearningPagePage.js +104 -96
  103. package/dist/technospam/pages/CoursesMyLearningPagePage.js.map +1 -1
  104. package/dist/technospam/pages/public/CertificateVerifyPage.d.ts +4 -0
  105. package/dist/technospam/pages/public/CertificateVerifyPage.d.ts.map +1 -0
  106. package/dist/technospam/pages/public/CertificateVerifyPage.js +257 -0
  107. package/dist/technospam/pages/public/CertificateVerifyPage.js.map +1 -0
  108. package/package.json +14 -4
@@ -16,13 +16,13 @@ var r = class extends t {
16
16
  };
17
17
  }
18
18
  render() {
19
- return this.state.hasError ? /* @__PURE__ */ n("div", {
19
+ return this.state.hasError ? this.props.fallback === void 0 ? /* @__PURE__ */ n("div", {
20
20
  className: "flex h-full min-h-[50vh] items-center justify-center p-6",
21
21
  children: /* @__PURE__ */ n(e, {
22
22
  title: this.props.title ?? "Couldn't load this page",
23
23
  error: this.state.error ?? void 0
24
24
  })
25
- }) : this.props.children;
25
+ }) : this.props.fallback : this.props.children;
26
26
  }
27
27
  };
28
28
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"TechnoSpamErrorBoundary.js","names":[],"sources":["../../../src/technospam/components/TechnoSpamErrorBoundary.tsx"],"sourcesContent":["import { Component, type ReactNode } from 'react';\nimport { ErrorView } from './StateViews';\n\ninterface Props {\n children: ReactNode;\n title?: string;\n}\n\ninterface State {\n hasError: boolean;\n error: Error | null;\n}\n\n/**\n * Per-route error boundary for the TechnoSpam MFE.\n *\n * Catches render errors inside TechnoSpam pages (e.g. a GraphQL response with\n * an unexpectedly null connection field) and renders an explicit error state\n * inside the module chrome instead of letting the error bubble to the root\n * boundary or leaving the content area blank.\n */\nexport class TechnoSpamErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error };\n }\n\n render(): ReactNode {\n if (this.state.hasError) {\n return (\n <div className=\"flex h-full min-h-[50vh] items-center justify-center p-6\">\n <ErrorView\n title={this.props.title ?? \"Couldn't load this page\"}\n error={this.state.error ?? undefined}\n />\n </div>\n );\n }\n return this.props.children;\n }\n}\n"],"mappings":";;;;AAqBA,IAAa,IAAb,cAA6C,EAAwB;CACnE,YAAY,GAAc;AAExB,EADA,MAAM,EAAM,EACZ,KAAK,QAAQ;GAAE,UAAU;GAAO,OAAO;GAAM;;CAG/C,OAAO,yBAAyB,GAAqB;AACnD,SAAO;GAAE,UAAU;GAAM;GAAO;;CAGlC,SAAoB;AAWlB,SAVI,KAAK,MAAM,WAEX,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IACE,OAAO,KAAK,MAAM,SAAS;IAC3B,OAAO,KAAK,MAAM,SAAS,KAAA;IAC3B,CAAA;GACE,CAAA,GAGH,KAAK,MAAM"}
1
+ {"version":3,"file":"TechnoSpamErrorBoundary.js","names":[],"sources":["../../../src/technospam/components/TechnoSpamErrorBoundary.tsx"],"sourcesContent":["import { Component, type ReactNode } from 'react';\nimport { ErrorView } from './StateViews';\n\ninterface Props {\n children: ReactNode;\n title?: string;\n /**\n * Rendered instead of the default error view when a child throws. Used for\n * small, recoverable regions (for example a lazily loaded editor chunk that\n * failed to download) where a working fallback beats a page-level error.\n */\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n error: Error | null;\n}\n\n/**\n * Per-route error boundary for the TechnoSpam MFE.\n *\n * Catches render errors inside TechnoSpam pages (e.g. a GraphQL response with\n * an unexpectedly null connection field) and renders an explicit error state\n * inside the module chrome instead of letting the error bubble to the root\n * boundary or leaving the content area blank.\n */\nexport class TechnoSpamErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error };\n }\n\n render(): ReactNode {\n if (this.state.hasError) {\n if (this.props.fallback !== undefined) return this.props.fallback;\n return (\n <div className=\"flex h-full min-h-[50vh] items-center justify-center p-6\">\n <ErrorView\n title={this.props.title ?? \"Couldn't load this page\"}\n error={this.state.error ?? undefined}\n />\n </div>\n );\n }\n return this.props.children;\n }\n}\n"],"mappings":";;;;AA2BA,IAAa,IAAb,cAA6C,EAAwB;CACnE,YAAY,GAAc;AAExB,EADA,MAAM,EAAM,EACZ,KAAK,QAAQ;GAAE,UAAU;GAAO,OAAO;GAAM;;CAG/C,OAAO,yBAAyB,GAAqB;AACnD,SAAO;GAAE,UAAU;GAAM;GAAO;;CAGlC,SAAoB;AAYlB,SAXI,KAAK,MAAM,WACT,KAAK,MAAM,aAAa,KAAA,IAE1B,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IACE,OAAO,KAAK,MAAM,SAAS;IAC3B,OAAO,KAAK,MAAM,SAAS,KAAA;IAC3B,CAAA;GACE,CAAA,GAPsC,KAAK,MAAM,WAUpD,KAAK,MAAM"}
@@ -0,0 +1,26 @@
1
+ export interface CodeEditorProps {
2
+ value: string;
3
+ onChange: (value: string) => void;
4
+ /** Language slug, e.g. "python"; switches syntax highlighting in place. */
5
+ language: string;
6
+ /** Accessible name for the editing surface. */
7
+ ariaLabel: string;
8
+ placeholder?: string;
9
+ /** Mod-Enter (Ctrl/Cmd+Enter). */
10
+ onRun?: () => void;
11
+ /** Mod-Shift-Enter. */
12
+ onSubmit?: () => void;
13
+ className?: string;
14
+ }
15
+ /**
16
+ * A CodeMirror 6 code editor (BOFF-4078): line numbers, syntax highlighting
17
+ * for every grader language, bracket matching/closing, undo history and Tab
18
+ * indentation. Press Escape and then Tab to move focus out of the editor.
19
+ *
20
+ * The editor is created once per mount; `value` and `language` changes from
21
+ * the parent (switching language, resetting to the starter code) are applied
22
+ * as transactions so the learner's undo history and cursor survive.
23
+ */
24
+ export declare function CodeEditor({ value, onChange, language, ariaLabel, placeholder, onRun, onSubmit, className, }: CodeEditorProps): import("react").JSX.Element;
25
+ export default CodeEditor;
26
+ //# sourceMappingURL=CodeEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeEditor.d.ts","sourceRoot":"","sources":["../../../../src/technospam/components/editor/CodeEditor.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,WAAW,EACX,KAAK,EACL,QAAQ,EACR,SAAS,GACV,EAAE,eAAe,+BAkGjB;AAED,eAAe,UAAU,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ import { Compartment as t, EditorState as n, Prec as r } from "../../../node_modules/@codemirror/state/dist/index.js";
3
+ import { EditorView as i, drawSelection as a, highlightActiveLine as o, highlightActiveLineGutter as s, keymap as c, lineNumbers as l, placeholder as u } from "../../../node_modules/@codemirror/view/dist/index.js";
4
+ import { bracketMatching as d, indentOnInput as f, syntaxHighlighting as p } from "../../../node_modules/@codemirror/language/dist/index.js";
5
+ import { defaultKeymap as m, history as h, historyKeymap as g, indentWithTab as _ } from "../../../node_modules/@codemirror/commands/dist/index.js";
6
+ import { closeBrackets as v, closeBracketsKeymap as y } from "../../../node_modules/@codemirror/autocomplete/dist/index.js";
7
+ import { languageExtension as b } from "./editorLanguages.js";
8
+ import { technospamEditorTheme as x, technospamHighlightStyle as S } from "./editorTheme.js";
9
+ import { useEffect as C, useLayoutEffect as w, useRef as T } from "react";
10
+ import { jsx as E } from "react/jsx-runtime";
11
+ //#region src/technospam/components/editor/CodeEditor.tsx
12
+ function D({ value: D, onChange: O, language: k, ariaLabel: A, placeholder: j, onRun: M, onSubmit: N, className: P }) {
13
+ let F = T(null), I = T(null), L = T(new t()), R = T({
14
+ value: D,
15
+ language: k,
16
+ ariaLabel: A,
17
+ placeholder: j,
18
+ onChange: O,
19
+ onRun: M,
20
+ onSubmit: N
21
+ });
22
+ return w(() => {
23
+ R.current = {
24
+ value: D,
25
+ language: k,
26
+ ariaLabel: A,
27
+ placeholder: j,
28
+ onChange: O,
29
+ onRun: M,
30
+ onSubmit: N
31
+ };
32
+ }), C(() => {
33
+ let e = F.current;
34
+ if (!e) return;
35
+ let t = R.current, C = R, w = new i({
36
+ parent: e,
37
+ state: n.create({
38
+ doc: t.value,
39
+ extensions: [
40
+ l(),
41
+ s(),
42
+ h(),
43
+ a(),
44
+ f(),
45
+ d(),
46
+ v(),
47
+ o(),
48
+ n.tabSize.of(4),
49
+ p(S),
50
+ x,
51
+ L.current.of(b(t.language)),
52
+ t.placeholder ? u(t.placeholder) : [],
53
+ i.contentAttributes.of({
54
+ "aria-label": t.ariaLabel,
55
+ "aria-multiline": "true",
56
+ spellcheck: "false",
57
+ autocorrect: "off",
58
+ autocapitalize: "off"
59
+ }),
60
+ r.highest(c.of([{
61
+ key: "Mod-Enter",
62
+ run: () => (C.current.onRun?.(), !!C.current.onRun)
63
+ }, {
64
+ key: "Mod-Shift-Enter",
65
+ run: () => (C.current.onSubmit?.(), !!C.current.onSubmit)
66
+ }])),
67
+ c.of([
68
+ ...y,
69
+ ...m,
70
+ ...g,
71
+ _
72
+ ]),
73
+ i.updateListener.of((e) => {
74
+ e.docChanged && C.current.onChange(e.state.doc.toString());
75
+ })
76
+ ]
77
+ })
78
+ });
79
+ return I.current = w, () => {
80
+ w.destroy(), I.current = null;
81
+ };
82
+ }, []), C(() => {
83
+ let e = I.current;
84
+ if (!e) return;
85
+ let t = e.state.doc.toString();
86
+ t !== D && e.dispatch({ changes: {
87
+ from: 0,
88
+ to: t.length,
89
+ insert: D
90
+ } });
91
+ }, [D]), C(() => {
92
+ I.current?.dispatch({ effects: L.current.reconfigure(b(k)) });
93
+ }, [k]), /* @__PURE__ */ E("div", {
94
+ ref: F,
95
+ "data-testid": "code-editor",
96
+ className: e("font-mono [&_.cm-editor]:h-full [&_.cm-scroller]:overflow-auto", P)
97
+ });
98
+ }
99
+ //#endregion
100
+ export { D as CodeEditor, D as default };
101
+
102
+ //# sourceMappingURL=CodeEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeEditor.js","names":[],"sources":["../../../../src/technospam/components/editor/CodeEditor.tsx"],"sourcesContent":["import { useEffect, useLayoutEffect, useRef } from 'react';\nimport { Compartment, EditorState, Prec } from '@codemirror/state';\nimport {\n EditorView,\n drawSelection,\n highlightActiveLine,\n highlightActiveLineGutter,\n keymap,\n lineNumbers,\n placeholder as placeholderExtension,\n} from '@codemirror/view';\nimport { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands';\nimport { bracketMatching, indentOnInput, syntaxHighlighting } from '@codemirror/language';\nimport { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';\nimport { languageExtension } from './editorLanguages';\nimport { technospamEditorTheme, technospamHighlightStyle } from './editorTheme';\nimport { cn } from '../../utils/cn';\n\nexport interface CodeEditorProps {\n value: string;\n onChange: (value: string) => void;\n /** Language slug, e.g. \"python\"; switches syntax highlighting in place. */\n language: string;\n /** Accessible name for the editing surface. */\n ariaLabel: string;\n placeholder?: string;\n /** Mod-Enter (Ctrl/Cmd+Enter). */\n onRun?: () => void;\n /** Mod-Shift-Enter. */\n onSubmit?: () => void;\n className?: string;\n}\n\n/**\n * A CodeMirror 6 code editor (BOFF-4078): line numbers, syntax highlighting\n * for every grader language, bracket matching/closing, undo history and Tab\n * indentation. Press Escape and then Tab to move focus out of the editor.\n *\n * The editor is created once per mount; `value` and `language` changes from\n * the parent (switching language, resetting to the starter code) are applied\n * as transactions so the learner's undo history and cursor survive.\n */\nexport function CodeEditor({\n value,\n onChange,\n language,\n ariaLabel,\n placeholder,\n onRun,\n onSubmit,\n className,\n}: CodeEditorProps) {\n const hostRef = useRef<HTMLDivElement | null>(null);\n const viewRef = useRef<EditorView | null>(null);\n const languageCompartment = useRef(new Compartment());\n // Latest props, read by the editor's long-lived listeners and by the\n // one-time setup below (refs are written after render, never during it).\n const latest = useRef({ value, language, ariaLabel, placeholder, onChange, onRun, onSubmit });\n useLayoutEffect(() => {\n latest.current = { value, language, ariaLabel, placeholder, onChange, onRun, onSubmit };\n });\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return undefined;\n const initial = latest.current;\n const callbacks = latest;\n const view = new EditorView({\n parent: host,\n state: EditorState.create({\n doc: initial.value,\n extensions: [\n lineNumbers(),\n highlightActiveLineGutter(),\n history(),\n drawSelection(),\n indentOnInput(),\n bracketMatching(),\n closeBrackets(),\n highlightActiveLine(),\n EditorState.tabSize.of(4),\n syntaxHighlighting(technospamHighlightStyle),\n technospamEditorTheme,\n languageCompartment.current.of(languageExtension(initial.language)),\n initial.placeholder ? placeholderExtension(initial.placeholder) : [],\n EditorView.contentAttributes.of({\n 'aria-label': initial.ariaLabel,\n 'aria-multiline': 'true',\n spellcheck: 'false',\n autocorrect: 'off',\n autocapitalize: 'off',\n }),\n Prec.highest(\n keymap.of([\n {\n key: 'Mod-Enter',\n run: () => {\n callbacks.current.onRun?.();\n return Boolean(callbacks.current.onRun);\n },\n },\n {\n key: 'Mod-Shift-Enter',\n run: () => {\n callbacks.current.onSubmit?.();\n return Boolean(callbacks.current.onSubmit);\n },\n },\n ])\n ),\n keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, indentWithTab]),\n EditorView.updateListener.of((update) => {\n if (update.docChanged) callbacks.current.onChange(update.state.doc.toString());\n }),\n ],\n }),\n });\n viewRef.current = view;\n return () => {\n view.destroy();\n viewRef.current = null;\n };\n // Built once per mount on purpose: later `value`/`language` changes are\n // applied by the effects below as transactions, and the callbacks are read\n // through `latest.current`, so rebuilding would only lose undo history.\n }, []);\n\n useEffect(() => {\n const view = viewRef.current;\n if (!view) return;\n const current = view.state.doc.toString();\n if (current !== value) {\n view.dispatch({ changes: { from: 0, to: current.length, insert: value } });\n }\n }, [value]);\n\n useEffect(() => {\n viewRef.current?.dispatch({\n effects: languageCompartment.current.reconfigure(languageExtension(language)),\n });\n }, [language]);\n\n return (\n <div\n ref={hostRef}\n data-testid=\"code-editor\"\n className={cn('font-mono [&_.cm-editor]:h-full [&_.cm-scroller]:overflow-auto', className)}\n />\n );\n}\n\nexport default CodeEditor;\n"],"mappings":";;;;;;;;;;;AA0CA,SAAgB,EAAW,EACzB,UACA,aACA,aACA,cACA,aAAA,GACA,UACA,aACA,gBACkB;CAClB,IAAM,IAAU,EAA8B,KAAK,EAC7C,IAAU,EAA0B,KAAK,EACzC,IAAsB,EAAO,IAAI,GAAa,CAAC,EAG/C,IAAS,EAAO;EAAE;EAAO;EAAU;EAAW,aAAA;EAAa;EAAU;EAAO;EAAU,CAAC;AAqF7F,QApFA,QAAsB;AACpB,IAAO,UAAU;GAAE;GAAO;GAAU;GAAW,aAAA;GAAa;GAAU;GAAO;GAAU;GACvF,EAEF,QAAgB;EACd,IAAM,IAAO,EAAQ;AACrB,MAAI,CAAC,EAAM;EACX,IAAM,IAAU,EAAO,SACjB,IAAY,GACZ,IAAO,IAAI,EAAW;GAC1B,QAAQ;GACR,OAAO,EAAY,OAAO;IACxB,KAAK,EAAQ;IACb,YAAY;KACV,GAAa;KACb,GAA2B;KAC3B,GAAS;KACT,GAAe;KACf,GAAe;KACf,GAAiB;KACjB,GAAe;KACf,GAAqB;KACrB,EAAY,QAAQ,GAAG,EAAE;KACzB,EAAmB,EAAyB;KAC5C;KACA,EAAoB,QAAQ,GAAG,EAAkB,EAAQ,SAAS,CAAC;KACnE,EAAQ,cAAc,EAAqB,EAAQ,YAAY,GAAG,EAAE;KACpE,EAAW,kBAAkB,GAAG;MAC9B,cAAc,EAAQ;MACtB,kBAAkB;MAClB,YAAY;MACZ,aAAa;MACb,gBAAgB;MACjB,CAAC;KACF,EAAK,QACH,EAAO,GAAG,CACR;MACE,KAAK;MACL,YACE,EAAU,QAAQ,SAAS,EACpB,EAAQ,EAAU,QAAQ;MAEpC,EACD;MACE,KAAK;MACL,YACE,EAAU,QAAQ,YAAY,EACvB,EAAQ,EAAU,QAAQ;MAEpC,CACF,CAAC,CACH;KACD,EAAO,GAAG;MAAC,GAAG;MAAqB,GAAG;MAAe,GAAG;MAAe;MAAc,CAAC;KACtF,EAAW,eAAe,IAAI,MAAW;AACvC,MAAI,EAAO,cAAY,EAAU,QAAQ,SAAS,EAAO,MAAM,IAAI,UAAU,CAAC;OAC9E;KACH;IACF,CAAC;GACH,CAAC;AAEF,SADA,EAAQ,UAAU,SACL;AAEX,GADA,EAAK,SAAS,EACd,EAAQ,UAAU;;IAKnB,EAAE,CAAC,EAEN,QAAgB;EACd,IAAM,IAAO,EAAQ;AACrB,MAAI,CAAC,EAAM;EACX,IAAM,IAAU,EAAK,MAAM,IAAI,UAAU;AACzC,EAAI,MAAY,KACd,EAAK,SAAS,EAAE,SAAS;GAAE,MAAM;GAAG,IAAI,EAAQ;GAAQ,QAAQ;GAAO,EAAE,CAAC;IAE3E,CAAC,EAAM,CAAC,EAEX,QAAgB;AACd,IAAQ,SAAS,SAAS,EACxB,SAAS,EAAoB,QAAQ,YAAY,EAAkB,EAAS,CAAC,EAC9E,CAAC;IACD,CAAC,EAAS,CAAC,EAGZ,kBAAC,OAAD;EACE,KAAK;EACL,eAAY;EACZ,WAAW,EAAG,kEAAkE,EAAU;EAC1F,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { TecSolutionRun } from '../../api/technospamApi';
2
+
3
+ /**
4
+ * Output of the editor's Run button (BOFF-4078): a warm-up notice while the
5
+ * sandbox starts, the per-sample-case verdicts, or the raw stdout/stderr of a
6
+ * custom-input run.
7
+ */
8
+ export declare function RunOutputPanel({ run, running, warming, error, }: {
9
+ run: TecSolutionRun | null;
10
+ running: boolean;
11
+ warming: boolean;
12
+ error: string | null;
13
+ }): import("react").JSX.Element;
14
+ //# sourceMappingURL=RunOutputPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RunOutputPanel.d.ts","sourceRoot":"","sources":["../../../../src/technospam/components/editor/RunOutputPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAwB,MAAM,yBAAyB,CAAC;AAWpF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC7B,GAAG,EACH,OAAO,EACP,OAAO,EACP,KAAK,GACN,EAAE;IACD,GAAG,EAAE,cAAc,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,+BA0FA"}
@@ -0,0 +1,127 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ import { CodePanel as t, IoBlock as n, TestResultsPanel as r } from "../SubmissionViews.js";
3
+ import { AlertTriangle as i, Clock as a, Loader2 as o, Terminal as s } from "lucide-react";
4
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
5
+ //#region src/technospam/components/editor/RunOutputPanel.tsx
6
+ function u(e) {
7
+ return e.compileFailed ? {
8
+ ok: !1,
9
+ text: "Compile error"
10
+ } : e.timedOut ? {
11
+ ok: !1,
12
+ text: "Time limit exceeded"
13
+ } : e.memoryLimitExceeded ? {
14
+ ok: !1,
15
+ text: "Memory limit exceeded"
16
+ } : e.exitCode === 0 ? {
17
+ ok: !0,
18
+ text: "Ran successfully"
19
+ } : {
20
+ ok: !1,
21
+ text: `Exited with code ${e.exitCode}`
22
+ };
23
+ }
24
+ function d({ run: d, running: f, warming: p, error: m }) {
25
+ if (p) return /* @__PURE__ */ l("p", {
26
+ role: "status",
27
+ className: "inline-flex items-center gap-2 text-sm text-text-secondary",
28
+ "data-testid": "run-warming",
29
+ children: [/* @__PURE__ */ c(o, {
30
+ size: 14,
31
+ className: "animate-spin"
32
+ }), "Starting the code sandbox — your run will start automatically in a moment."]
33
+ });
34
+ if (f && !d) return /* @__PURE__ */ l("p", {
35
+ role: "status",
36
+ className: "inline-flex items-center gap-2 text-sm text-text-secondary",
37
+ children: [/* @__PURE__ */ c(o, {
38
+ size: 14,
39
+ className: "animate-spin"
40
+ }), " Running your code…"]
41
+ });
42
+ if (m) return /* @__PURE__ */ l("p", {
43
+ role: "alert",
44
+ className: "inline-flex items-start gap-2 text-sm text-status-error-text",
45
+ "data-testid": "run-error",
46
+ children: [
47
+ /* @__PURE__ */ c(i, {
48
+ size: 14,
49
+ className: "mt-0.5 shrink-0"
50
+ }),
51
+ " ",
52
+ m
53
+ ]
54
+ });
55
+ if (!d) return /* @__PURE__ */ c("p", {
56
+ className: "text-sm text-text-muted",
57
+ children: "Run your code against the sample test cases (or your own input) before you submit. Runs are not recorded and do not affect your score."
58
+ });
59
+ if (d.status !== "COMPLETED") return /* @__PURE__ */ l("p", {
60
+ role: "alert",
61
+ className: "inline-flex items-start gap-2 text-sm text-status-warning-text",
62
+ children: [/* @__PURE__ */ c(i, {
63
+ size: 14,
64
+ className: "mt-0.5 shrink-0"
65
+ }), "The code sandbox is not available right now. Please try again shortly."]
66
+ });
67
+ if (d.customOutput) {
68
+ let r = d.customOutput, i = u(r);
69
+ return /* @__PURE__ */ l("div", {
70
+ className: "space-y-3",
71
+ "data-testid": "run-custom-output",
72
+ children: [
73
+ /* @__PURE__ */ l("div", {
74
+ className: "flex flex-wrap items-center gap-x-3 gap-y-1",
75
+ children: [/* @__PURE__ */ l("span", {
76
+ className: e("inline-flex items-center gap-1.5 text-sm font-medium", i.ok ? "text-status-success-text" : "text-status-error-text"),
77
+ children: [
78
+ /* @__PURE__ */ c(s, { size: 14 }),
79
+ " ",
80
+ i.text
81
+ ]
82
+ }), /* @__PURE__ */ l("span", {
83
+ className: "inline-flex items-center gap-1 text-xs text-text-muted",
84
+ children: [
85
+ /* @__PURE__ */ c(a, { size: 12 }),
86
+ " ",
87
+ r.durationMs,
88
+ " ms"
89
+ ]
90
+ })]
91
+ }),
92
+ /* @__PURE__ */ l("div", {
93
+ className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
94
+ children: [/* @__PURE__ */ c(n, {
95
+ label: "Input",
96
+ value: r.stdin
97
+ }), /* @__PURE__ */ c(n, {
98
+ label: "Output",
99
+ value: r.stdout
100
+ })]
101
+ }),
102
+ r.stderr ? /* @__PURE__ */ c(t, {
103
+ label: "stderr",
104
+ bodyClassName: "max-h-48",
105
+ children: r.stderr
106
+ }) : null
107
+ ]
108
+ });
109
+ }
110
+ return d.verdict ? /* @__PURE__ */ c("div", {
111
+ "data-testid": "run-sample-results",
112
+ children: /* @__PURE__ */ c(r, {
113
+ submission: {
114
+ ...d,
115
+ verdict: d.verdict
116
+ },
117
+ caseNoun: "sample test cases"
118
+ })
119
+ }) : /* @__PURE__ */ c("p", {
120
+ className: "text-sm text-text-muted",
121
+ children: "Nothing ran."
122
+ });
123
+ }
124
+ //#endregion
125
+ export { d as RunOutputPanel };
126
+
127
+ //# sourceMappingURL=RunOutputPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RunOutputPanel.js","names":[],"sources":["../../../../src/technospam/components/editor/RunOutputPanel.tsx"],"sourcesContent":["import { AlertTriangle, Clock, Loader2, Terminal } from 'lucide-react';\nimport { CodePanel, IoBlock, TestResultsPanel } from '../SubmissionViews';\nimport type { TecSolutionRun, TecSolutionRunOutput } from '../../api/technospamApi';\nimport { cn } from '../../utils/cn';\n\nfunction customRunSummary(output: TecSolutionRunOutput): { ok: boolean; text: string } {\n if (output.compileFailed) return { ok: false, text: 'Compile error' };\n if (output.timedOut) return { ok: false, text: 'Time limit exceeded' };\n if (output.memoryLimitExceeded) return { ok: false, text: 'Memory limit exceeded' };\n if (output.exitCode !== 0) return { ok: false, text: `Exited with code ${output.exitCode}` };\n return { ok: true, text: 'Ran successfully' };\n}\n\n/**\n * Output of the editor's Run button (BOFF-4078): a warm-up notice while the\n * sandbox starts, the per-sample-case verdicts, or the raw stdout/stderr of a\n * custom-input run.\n */\nexport function RunOutputPanel({\n run,\n running,\n warming,\n error,\n}: {\n run: TecSolutionRun | null;\n running: boolean;\n warming: boolean;\n error: string | null;\n}) {\n if (warming) {\n return (\n <p\n role=\"status\"\n className=\"inline-flex items-center gap-2 text-sm text-text-secondary\"\n data-testid=\"run-warming\"\n >\n <Loader2 size={14} className=\"animate-spin\" />\n Starting the code sandbox — your run will start automatically in a moment.\n </p>\n );\n }\n if (running && !run) {\n return (\n <p role=\"status\" className=\"inline-flex items-center gap-2 text-sm text-text-secondary\">\n <Loader2 size={14} className=\"animate-spin\" /> Running your code…\n </p>\n );\n }\n if (error) {\n return (\n <p\n role=\"alert\"\n className=\"inline-flex items-start gap-2 text-sm text-status-error-text\"\n data-testid=\"run-error\"\n >\n <AlertTriangle size={14} className=\"mt-0.5 shrink-0\" /> {error}\n </p>\n );\n }\n if (!run) {\n return (\n <p className=\"text-sm text-text-muted\">\n Run your code against the sample test cases (or your own input) before you submit. Runs are\n not recorded and do not affect your score.\n </p>\n );\n }\n if (run.status !== 'COMPLETED') {\n return (\n <p role=\"alert\" className=\"inline-flex items-start gap-2 text-sm text-status-warning-text\">\n <AlertTriangle size={14} className=\"mt-0.5 shrink-0\" />\n The code sandbox is not available right now. Please try again shortly.\n </p>\n );\n }\n\n if (run.customOutput) {\n const output = run.customOutput;\n const summary = customRunSummary(output);\n return (\n <div className=\"space-y-3\" data-testid=\"run-custom-output\">\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1\">\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 text-sm font-medium',\n summary.ok ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n <Terminal size={14} /> {summary.text}\n </span>\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Clock size={12} /> {output.durationMs} ms\n </span>\n </div>\n <div className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n <IoBlock label=\"Input\" value={output.stdin} />\n <IoBlock label=\"Output\" value={output.stdout} />\n </div>\n {output.stderr ? (\n <CodePanel label=\"stderr\" bodyClassName=\"max-h-48\">\n {output.stderr}\n </CodePanel>\n ) : null}\n </div>\n );\n }\n\n if (run.verdict) {\n return (\n <div data-testid=\"run-sample-results\">\n <TestResultsPanel\n submission={{ ...run, verdict: run.verdict }}\n caseNoun=\"sample test cases\"\n />\n </div>\n );\n }\n return <p className=\"text-sm text-text-muted\">Nothing ran.</p>;\n}\n"],"mappings":";;;;;AAKA,SAAS,EAAiB,GAA6D;AAKrF,QAJI,EAAO,gBAAsB;EAAE,IAAI;EAAO,MAAM;EAAiB,GACjE,EAAO,WAAiB;EAAE,IAAI;EAAO,MAAM;EAAuB,GAClE,EAAO,sBAA4B;EAAE,IAAI;EAAO,MAAM;EAAyB,GAC/E,EAAO,aAAa,IACjB;EAAE,IAAI;EAAM,MAAM;EAAoB,GADX;EAAE,IAAI;EAAO,MAAM,oBAAoB,EAAO;EAAY;;AAS9F,SAAgB,EAAe,EAC7B,QACA,YACA,YACA,YAMC;AACD,KAAI,EACF,QACE,kBAAC,KAAD;EACE,MAAK;EACL,WAAU;EACV,eAAY;YAHd,CAKE,kBAAC,GAAD;GAAS,MAAM;GAAI,WAAU;GAAiB,CAAA,EAAA,6EAE5C;;AAGR,KAAI,KAAW,CAAC,EACd,QACE,kBAAC,KAAD;EAAG,MAAK;EAAS,WAAU;YAA3B,CACE,kBAAC,GAAD;GAAS,MAAM;GAAI,WAAU;GAAiB,CAAA,EAAA,sBAC5C;;AAGR,KAAI,EACF,QACE,kBAAC,KAAD;EACE,MAAK;EACL,WAAU;EACV,eAAY;YAHd;GAKE,kBAAC,GAAD;IAAe,MAAM;IAAI,WAAU;IAAoB,CAAA;;GAAE;GACvD;;AAGR,KAAI,CAAC,EACH,QACE,kBAAC,KAAD;EAAG,WAAU;YAA0B;EAGnC,CAAA;AAGR,KAAI,EAAI,WAAW,YACjB,QACE,kBAAC,KAAD;EAAG,MAAK;EAAQ,WAAU;YAA1B,CACE,kBAAC,GAAD;GAAe,MAAM;GAAI,WAAU;GAAoB,CAAA,EAAA,yEAErD;;AAIR,KAAI,EAAI,cAAc;EACpB,IAAM,IAAS,EAAI,cACb,IAAU,EAAiB,EAAO;AACxC,SACE,kBAAC,OAAD;GAAK,WAAU;GAAY,eAAY;aAAvC;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MACE,WAAW,EACT,wDACA,EAAQ,KAAK,6BAA6B,yBAC3C;gBAJH;OAME,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;;OAAE,EAAQ;OAC3B;SACP,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;;OAAE,EAAO;OAAW;OAClC;QACH;;IACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAS,OAAM;MAAQ,OAAO,EAAO;MAAS,CAAA,EAC9C,kBAAC,GAAD;MAAS,OAAM;MAAS,OAAO,EAAO;MAAU,CAAA,CAC5C;;IACL,EAAO,SACN,kBAAC,GAAD;KAAW,OAAM;KAAS,eAAc;eACrC,EAAO;KACE,CAAA,GACV;IACA;;;AAcV,QAVI,EAAI,UAEJ,kBAAC,OAAD;EAAK,eAAY;YACf,kBAAC,GAAD;GACE,YAAY;IAAE,GAAG;IAAK,SAAS,EAAI;IAAS;GAC5C,UAAS;GACT,CAAA;EACE,CAAA,GAGH,kBAAC,KAAD;EAAG,WAAU;YAA0B;EAAgB,CAAA"}
@@ -0,0 +1,11 @@
1
+ import { Extension } from '@codemirror/state';
2
+
3
+ /**
4
+ * Syntax support for every language slug the grading sandbox runs
5
+ * (wspace-technospam-svc `SUPPORTED_LANGUAGES`). Unknown slugs get plain-text
6
+ * editing — line numbers, brackets and history still work.
7
+ */
8
+ export declare function languageExtension(language: string): Extension;
9
+ /** Whether `languageExtension` highlights this slug (used by tests and the editor label). */
10
+ export declare function hasSyntaxSupport(language: string): boolean;
11
+ //# sourceMappingURL=editorLanguages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorLanguages.d.ts","sourceRoot":"","sources":["../../../../src/technospam/components/editor/editorLanguages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAQnD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAyB7D;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG1D"}
@@ -0,0 +1,30 @@
1
+ import { StreamLanguage as e } from "../../../node_modules/@codemirror/language/dist/index.js";
2
+ import { javascript as t } from "../../../node_modules/@codemirror/lang-javascript/dist/index.js";
3
+ import { python as n } from "../../../node_modules/@codemirror/lang-python/dist/index.js";
4
+ import { go as r } from "../../../node_modules/@codemirror/lang-go/dist/index.js";
5
+ import { ruby as i } from "../../../node_modules/@codemirror/legacy-modes/mode/ruby.js";
6
+ import { shell as a } from "../../../node_modules/@codemirror/legacy-modes/mode/shell.js";
7
+ //#region src/technospam/components/editor/editorLanguages.ts
8
+ function o(o) {
9
+ switch (o.trim().toLowerCase()) {
10
+ case "javascript":
11
+ case "js":
12
+ case "node": return t();
13
+ case "typescript":
14
+ case "ts": return t({ typescript: !0 });
15
+ case "python":
16
+ case "py": return n();
17
+ case "go":
18
+ case "golang": return r();
19
+ case "ruby":
20
+ case "rb": return e.define(i);
21
+ case "bash":
22
+ case "sh":
23
+ case "shell": return e.define(a);
24
+ default: return [];
25
+ }
26
+ }
27
+ //#endregion
28
+ export { o as languageExtension };
29
+
30
+ //# sourceMappingURL=editorLanguages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorLanguages.js","names":[],"sources":["../../../../src/technospam/components/editor/editorLanguages.ts"],"sourcesContent":["import type { Extension } from '@codemirror/state';\nimport { StreamLanguage } from '@codemirror/language';\nimport { javascript } from '@codemirror/lang-javascript';\nimport { python } from '@codemirror/lang-python';\nimport { go } from '@codemirror/lang-go';\nimport { ruby } from '@codemirror/legacy-modes/mode/ruby';\nimport { shell } from '@codemirror/legacy-modes/mode/shell';\n\n/**\n * Syntax support for every language slug the grading sandbox runs\n * (wspace-technospam-svc `SUPPORTED_LANGUAGES`). Unknown slugs get plain-text\n * editing — line numbers, brackets and history still work.\n */\nexport function languageExtension(language: string): Extension {\n switch (language.trim().toLowerCase()) {\n case 'javascript':\n case 'js':\n case 'node':\n return javascript();\n case 'typescript':\n case 'ts':\n return javascript({ typescript: true });\n case 'python':\n case 'py':\n return python();\n case 'go':\n case 'golang':\n return go();\n case 'ruby':\n case 'rb':\n return StreamLanguage.define(ruby);\n case 'bash':\n case 'sh':\n case 'shell':\n return StreamLanguage.define(shell);\n default:\n return [];\n }\n}\n\n/** Whether `languageExtension` highlights this slug (used by tests and the editor label). */\nexport function hasSyntaxSupport(language: string): boolean {\n const ext = languageExtension(language);\n return !(Array.isArray(ext) && ext.length === 0);\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,EAAkB,GAA6B;AAC7D,SAAQ,EAAS,MAAM,CAAC,aAAa,EAArC;EACE,KAAK;EACL,KAAK;EACL,KAAK,OACH,QAAO,GAAY;EACrB,KAAK;EACL,KAAK,KACH,QAAO,EAAW,EAAE,YAAY,IAAM,CAAC;EACzC,KAAK;EACL,KAAK,KACH,QAAO,GAAQ;EACjB,KAAK;EACL,KAAK,SACH,QAAO,GAAI;EACb,KAAK;EACL,KAAK,KACH,QAAO,EAAe,OAAO,EAAK;EACpC,KAAK;EACL,KAAK;EACL,KAAK,QACH,QAAO,EAAe,OAAO,EAAM;EACrC,QACE,QAAO,EAAE"}
@@ -0,0 +1,11 @@
1
+ import { HighlightStyle } from '@codemirror/language';
2
+
3
+ /**
4
+ * Syntax colours are Tailwind utility classes over the platform's semantic
5
+ * tokens (never raw colours), so the editor follows the active brand and
6
+ * light/dark theme like the rest of the app.
7
+ */
8
+ export declare const technospamHighlightStyle: HighlightStyle;
9
+ /** Editor chrome: inherits the surrounding panel and uses semantic token variables. */
10
+ export declare const technospamEditorTheme: import('@codemirror/state').Extension;
11
+ //# sourceMappingURL=editorTheme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorTheme.d.ts","sourceRoot":"","sources":["../../../../src/technospam/components/editor/editorTheme.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,gBAyBnC,CAAC;AAEH,uFAAuF;AACvF,eAAO,MAAM,qBAAqB,uCA+BhC,CAAC"}
@@ -0,0 +1,120 @@
1
+ import { EditorView as e } from "../../../node_modules/@codemirror/view/dist/index.js";
2
+ import { tags as t } from "../../../node_modules/@lezer/highlight/dist/index.js";
3
+ import { HighlightStyle as n } from "../../../node_modules/@codemirror/language/dist/index.js";
4
+ //#region src/technospam/components/editor/editorTheme.ts
5
+ var r = n.define([
6
+ {
7
+ tag: [
8
+ t.keyword,
9
+ t.controlKeyword,
10
+ t.moduleKeyword,
11
+ t.operatorKeyword
12
+ ],
13
+ class: "text-accent-purple"
14
+ },
15
+ {
16
+ tag: [t.definitionKeyword, t.modifier],
17
+ class: "text-accent-purple"
18
+ },
19
+ {
20
+ tag: [
21
+ t.string,
22
+ t.special(t.string),
23
+ t.regexp
24
+ ],
25
+ class: "text-status-success-text"
26
+ },
27
+ {
28
+ tag: [
29
+ t.number,
30
+ t.bool,
31
+ t.null,
32
+ t.atom
33
+ ],
34
+ class: "text-status-warning-text"
35
+ },
36
+ {
37
+ tag: [
38
+ t.comment,
39
+ t.lineComment,
40
+ t.blockComment,
41
+ t.docComment
42
+ ],
43
+ class: "italic text-text-secondary"
44
+ },
45
+ {
46
+ tag: [
47
+ t.function(t.variableName),
48
+ t.function(t.propertyName),
49
+ t.definition(t.function(t.variableName))
50
+ ],
51
+ class: "text-accent-primary"
52
+ },
53
+ {
54
+ tag: [
55
+ t.typeName,
56
+ t.className,
57
+ t.namespace
58
+ ],
59
+ class: "text-accent-teal"
60
+ },
61
+ {
62
+ tag: [t.propertyName, t.attributeName],
63
+ class: "text-accent-indigo"
64
+ },
65
+ {
66
+ tag: [t.self, t.special(t.variableName)],
67
+ class: "text-accent-purple"
68
+ },
69
+ {
70
+ tag: [
71
+ t.operator,
72
+ t.punctuation,
73
+ t.bracket
74
+ ],
75
+ class: "text-text-secondary"
76
+ },
77
+ {
78
+ tag: t.invalid,
79
+ class: "text-status-error-text"
80
+ }
81
+ ]), i = e.theme({
82
+ "&": {
83
+ backgroundColor: "inherit",
84
+ color: "var(--color-text-primary)",
85
+ fontSize: "12px",
86
+ height: "100%"
87
+ },
88
+ "&.cm-focused": { outline: "none" },
89
+ ".cm-scroller": {
90
+ fontFamily: "inherit",
91
+ lineHeight: "1.65"
92
+ },
93
+ ".cm-content": {
94
+ caretColor: "var(--color-text-primary)",
95
+ padding: "12px 0"
96
+ },
97
+ ".cm-cursor, .cm-dropCursor": { borderLeftColor: "var(--color-text-primary)" },
98
+ ".cm-gutters": {
99
+ backgroundColor: "inherit",
100
+ color: "var(--color-text-muted)",
101
+ border: "none",
102
+ borderRight: "1px solid var(--color-border-subtle)"
103
+ },
104
+ ".cm-lineNumbers .cm-gutterElement": { padding: "0 10px 0 12px" },
105
+ ".cm-activeLine": { backgroundColor: "var(--color-bg-surface)" },
106
+ ".cm-activeLineGutter": {
107
+ backgroundColor: "var(--color-bg-surface)",
108
+ color: "var(--color-text-primary)"
109
+ },
110
+ ".cm-selectionBackground, &.cm-focused .cm-selectionBackground, ::selection": { backgroundColor: "var(--color-bg-accent)" },
111
+ ".cm-matchingBracket": {
112
+ backgroundColor: "var(--color-bg-accent)",
113
+ outline: "1px solid var(--color-border-strong)"
114
+ },
115
+ ".cm-placeholder": { color: "var(--color-text-placeholder)" }
116
+ });
117
+ //#endregion
118
+ export { i as technospamEditorTheme, r as technospamHighlightStyle };
119
+
120
+ //# sourceMappingURL=editorTheme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorTheme.js","names":[],"sources":["../../../../src/technospam/components/editor/editorTheme.ts"],"sourcesContent":["import { EditorView } from '@codemirror/view';\nimport { HighlightStyle } from '@codemirror/language';\nimport { tags as t } from '@lezer/highlight';\n\n/**\n * Syntax colours are Tailwind utility classes over the platform's semantic\n * tokens (never raw colours), so the editor follows the active brand and\n * light/dark theme like the rest of the app.\n */\nexport const technospamHighlightStyle = HighlightStyle.define([\n {\n tag: [t.keyword, t.controlKeyword, t.moduleKeyword, t.operatorKeyword],\n class: 'text-accent-purple',\n },\n { tag: [t.definitionKeyword, t.modifier], class: 'text-accent-purple' },\n { tag: [t.string, t.special(t.string), t.regexp], class: 'text-status-success-text' },\n { tag: [t.number, t.bool, t.null, t.atom], class: 'text-status-warning-text' },\n {\n tag: [t.comment, t.lineComment, t.blockComment, t.docComment],\n class: 'italic text-text-secondary',\n },\n {\n tag: [\n t.function(t.variableName),\n t.function(t.propertyName),\n t.definition(t.function(t.variableName)),\n ],\n class: 'text-accent-primary',\n },\n { tag: [t.typeName, t.className, t.namespace], class: 'text-accent-teal' },\n { tag: [t.propertyName, t.attributeName], class: 'text-accent-indigo' },\n { tag: [t.self, t.special(t.variableName)], class: 'text-accent-purple' },\n { tag: [t.operator, t.punctuation, t.bracket], class: 'text-text-secondary' },\n { tag: t.invalid, class: 'text-status-error-text' },\n]);\n\n/** Editor chrome: inherits the surrounding panel and uses semantic token variables. */\nexport const technospamEditorTheme = EditorView.theme({\n '&': {\n backgroundColor: 'inherit',\n color: 'var(--color-text-primary)',\n fontSize: '12px',\n height: '100%',\n },\n '&.cm-focused': { outline: 'none' },\n '.cm-scroller': { fontFamily: 'inherit', lineHeight: '1.65' },\n '.cm-content': { caretColor: 'var(--color-text-primary)', padding: '12px 0' },\n '.cm-cursor, .cm-dropCursor': { borderLeftColor: 'var(--color-text-primary)' },\n '.cm-gutters': {\n backgroundColor: 'inherit',\n color: 'var(--color-text-muted)',\n border: 'none',\n borderRight: '1px solid var(--color-border-subtle)',\n },\n '.cm-lineNumbers .cm-gutterElement': { padding: '0 10px 0 12px' },\n '.cm-activeLine': { backgroundColor: 'var(--color-bg-surface)' },\n '.cm-activeLineGutter': {\n backgroundColor: 'var(--color-bg-surface)',\n color: 'var(--color-text-primary)',\n },\n '.cm-selectionBackground, &.cm-focused .cm-selectionBackground, ::selection': {\n backgroundColor: 'var(--color-bg-accent)',\n },\n '.cm-matchingBracket': {\n backgroundColor: 'var(--color-bg-accent)',\n outline: '1px solid var(--color-border-strong)',\n },\n '.cm-placeholder': { color: 'var(--color-text-placeholder)' },\n});\n"],"mappings":";;;;AASA,IAAa,IAA2B,EAAe,OAAO;CAC5D;EACE,KAAK;GAAC,EAAE;GAAS,EAAE;GAAgB,EAAE;GAAe,EAAE;GAAgB;EACtE,OAAO;EACR;CACD;EAAE,KAAK,CAAC,EAAE,mBAAmB,EAAE,SAAS;EAAE,OAAO;EAAsB;CACvE;EAAE,KAAK;GAAC,EAAE;GAAQ,EAAE,QAAQ,EAAE,OAAO;GAAE,EAAE;GAAO;EAAE,OAAO;EAA4B;CACrF;EAAE,KAAK;GAAC,EAAE;GAAQ,EAAE;GAAM,EAAE;GAAM,EAAE;GAAK;EAAE,OAAO;EAA4B;CAC9E;EACE,KAAK;GAAC,EAAE;GAAS,EAAE;GAAa,EAAE;GAAc,EAAE;GAAW;EAC7D,OAAO;EACR;CACD;EACE,KAAK;GACH,EAAE,SAAS,EAAE,aAAa;GAC1B,EAAE,SAAS,EAAE,aAAa;GAC1B,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,CAAC;GACzC;EACD,OAAO;EACR;CACD;EAAE,KAAK;GAAC,EAAE;GAAU,EAAE;GAAW,EAAE;GAAU;EAAE,OAAO;EAAoB;CAC1E;EAAE,KAAK,CAAC,EAAE,cAAc,EAAE,cAAc;EAAE,OAAO;EAAsB;CACvE;EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAC;EAAE,OAAO;EAAsB;CACzE;EAAE,KAAK;GAAC,EAAE;GAAU,EAAE;GAAa,EAAE;GAAQ;EAAE,OAAO;EAAuB;CAC7E;EAAE,KAAK,EAAE;EAAS,OAAO;EAA0B;CACpD,CAAC,EAGW,IAAwB,EAAW,MAAM;CACpD,KAAK;EACH,iBAAiB;EACjB,OAAO;EACP,UAAU;EACV,QAAQ;EACT;CACD,gBAAgB,EAAE,SAAS,QAAQ;CACnC,gBAAgB;EAAE,YAAY;EAAW,YAAY;EAAQ;CAC7D,eAAe;EAAE,YAAY;EAA6B,SAAS;EAAU;CAC7E,8BAA8B,EAAE,iBAAiB,6BAA6B;CAC9E,eAAe;EACb,iBAAiB;EACjB,OAAO;EACP,QAAQ;EACR,aAAa;EACd;CACD,qCAAqC,EAAE,SAAS,iBAAiB;CACjE,kBAAkB,EAAE,iBAAiB,2BAA2B;CAChE,wBAAwB;EACtB,iBAAiB;EACjB,OAAO;EACR;CACD,8EAA8E,EAC5E,iBAAiB,0BAClB;CACD,uBAAuB;EACrB,iBAAiB;EACjB,SAAS;EACV;CACD,mBAAmB,EAAE,OAAO,iCAAiC;CAC9D,CAAC"}
@@ -12,4 +12,5 @@ export { CodePanel, IoBlock, TestResultsPanel } from './SubmissionViews';
12
12
  export { SubmissionReviewPanel } from './SubmissionReviewPanel';
13
13
  export { TechnoSpamErrorBoundary } from './TechnoSpamErrorBoundary';
14
14
  export { CardOpenButton } from './CardOpenButton';
15
+ export { CertificateVerifyLink } from './CertificateVerifyLink';
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/technospam/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -12,3 +12,4 @@ import "./SubmissionViews.js";
12
12
  import "./SubmissionReviewPanel.js";
13
13
  import "./TechnoSpamErrorBoundary.js";
14
14
  import "./CardOpenButton.js";
15
+ import "./CertificateVerifyLink.js";
@@ -0,0 +1,35 @@
1
+ import { TecSolutionRun } from '../api/technospamApi';
2
+
3
+ /**
4
+ * A cold code sandbox can take a few minutes to start. While the API answers
5
+ * WARMING the run is retried on this interval, giving up after the budget so
6
+ * the learner can retry by hand.
7
+ */
8
+ export declare const RUN_WARMING_RETRY_MS = 4000;
9
+ export declare const RUN_WARMING_BUDGET_MS: number;
10
+ export interface SolutionRunRequest {
11
+ problemId: string;
12
+ language: string;
13
+ code: string;
14
+ /** Custom stdin; omit to run the sample cases. */
15
+ stdin?: string | null;
16
+ }
17
+ export interface SolutionRunner {
18
+ /** The latest finished (or given-up) run. */
19
+ run: TecSolutionRun | null;
20
+ /** A request is in flight. */
21
+ running: boolean;
22
+ /** The sandbox is starting; the run is being retried automatically. */
23
+ warming: boolean;
24
+ /** Why the last run was refused (quota, bad input…), shown inline. */
25
+ error: string | null;
26
+ execute: (request: SolutionRunRequest) => void;
27
+ reset: () => void;
28
+ }
29
+ /**
30
+ * Drives `tecRunSolution` for the problem editor (BOFF-4078): sends the run,
31
+ * keeps retrying while the sandbox warms up, and exposes the result. Starting
32
+ * a new run cancels any pending warm-up retry.
33
+ */
34
+ export declare function useSolutionRunner(): SolutionRunner;
35
+ //# sourceMappingURL=useSolutionRunner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSolutionRunner.d.ts","sourceRoot":"","sources":["../../../src/technospam/hooks/useSolutionRunner.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3E;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,OAAQ,CAAC;AAC1C,eAAO,MAAM,qBAAqB,QAAa,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,GAAG,EAAE,cAAc,GAAG,IAAI,CAAC;IAC3B,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;IACjB,sEAAsE;IACtE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC/C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CA6GlD"}