@q9labsai/chalk-whiteboard 4.1.16 → 5.0.0

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.
@@ -35,18 +35,6 @@ export type ChalkEmbeddedWhiteboardTransportEvent = {
35
35
  readonly reason: "scene_changed" | "cursor_expired" | "gap";
36
36
  };
37
37
  export interface ChalkEmbeddedWhiteboardFileTransport {
38
- readonly initiateUpload: (input: {
39
- readonly fileId: string;
40
- readonly mimeType: string;
41
- readonly byteLength: number;
42
- readonly sha256: string;
43
- }) => Promise<{
44
- readonly uploadId: string;
45
- readonly method: "PUT";
46
- readonly uploadUrl: string;
47
- readonly headers: Readonly<Record<string, string>>;
48
- }>;
49
- readonly finalizeUpload: (uploadId: string) => Promise<void>;
50
38
  readonly getDownloadUrl: (fileId: string) => Promise<{
51
39
  readonly downloadUrl: string;
52
40
  }>;
@@ -1,7 +1,3 @@
1
- // src/embedded/controller.ts
2
- import { sha256 } from "@noble/hashes/sha2.js";
3
- import { bytesToHex } from "@noble/hashes/utils.js";
4
-
5
1
  // src/embedded/protocol.ts
6
2
  var CHALK_EMBEDDED_WHITEBOARD_BRIDGE_VERSION = 1;
7
3
  var CHALK_EMBEDDED_WHITEBOARD_EXCALIDRAW_VERSION = "0.18.1";
@@ -337,32 +333,7 @@ var ChalkWhiteboardController = class {
337
333
  async #writeFile(message) {
338
334
  const payload = requireFileWrite(message.payload);
339
335
  await this.#operation(payload.requestId, async () => {
340
- if (!this.#effectiveCanDraw()) throw new Error("whiteboard file upload is not permitted");
341
- const abortController = this.#beginFileTransfer(payload.requestId);
342
- try {
343
- const blob = await this.#dataURLBlob(payload.dataURL);
344
- if (blob.size !== payload.byteLength) throw new Error("whiteboard file byte length does not match");
345
- const validated = await validateFileBlob(blob, payload.mimeType);
346
- if (bytesToHex(sha256(validated.bytes)) !== payload.sha256.toLowerCase()) {
347
- throw new Error("whiteboard file digest does not match");
348
- }
349
- const upload = await this.options.transport.files.initiateUpload({
350
- fileId: payload.fileId,
351
- mimeType: validated.mimeType,
352
- byteLength: payload.byteLength,
353
- sha256: payload.sha256
354
- });
355
- const response = await this.#fetch(upload.uploadUrl, {
356
- method: upload.method,
357
- headers: upload.headers,
358
- body: blob,
359
- signal: abortController.signal
360
- });
361
- if (!response.ok) throw new Error(`whiteboard file upload failed with HTTP ${response.status}`);
362
- await this.options.transport.files.finalizeUpload(upload.uploadId);
363
- } finally {
364
- this.#finishFileTransfer(payload.requestId, abortController);
365
- }
336
+ throw new Error("Board uploads are unavailable.");
366
337
  });
367
338
  }
368
339
  async #readFile(message) {
@@ -516,28 +487,6 @@ var ChalkWhiteboardController = class {
516
487
  const message = safeErrorMessage(cause);
517
488
  this.options.onError?.({ code: "invalid_renderer_message", message, recoverable: false });
518
489
  }
519
- async #dataURLBlob(dataURL) {
520
- if (!dataURL.startsWith("data:") || dataURL.length > Math.ceil(MAX_FILE_BYTES * 4 / 3) + 1024) {
521
- throw new Error("whiteboard file data is invalid");
522
- }
523
- const separator = dataURL.indexOf(",");
524
- if (separator < 0) throw new Error("whiteboard file data is invalid");
525
- const metadata = dataURL.slice(5, separator).split(";");
526
- const mimeType = normalizeMimeType(metadata[0] ?? "");
527
- if (metadata.length !== 2 || metadata[1]?.toLowerCase() !== "base64") {
528
- throw new Error("whiteboard file data must use base64 encoding");
529
- }
530
- let decoded;
531
- try {
532
- decoded = atob(dataURL.slice(separator + 1));
533
- } catch {
534
- throw new Error("whiteboard file data is not valid base64");
535
- }
536
- const bytes = Uint8Array.from(decoded, (character) => character.charCodeAt(0));
537
- const blob = new Blob([bytes], { type: mimeType });
538
- if (blob.size > MAX_FILE_BYTES) throw new Error("whiteboard file exceeds the renderer transfer limit");
539
- return blob;
540
- }
541
490
  #beginFileTransfer(requestId) {
542
491
  if (this.#fileTransfers.has(requestId)) throw new Error("whiteboard file request is already active");
543
492
  const abortController = new AbortController();
@@ -614,8 +563,8 @@ function requireRequest(value) {
614
563
  function requireFileWrite(value) {
615
564
  const record = requireRecord(value, ["requestId", "fileId", "mimeType", "byteLength", "sha256", "dataURL"]);
616
565
  const byteLength = record.byteLength;
617
- const sha2562 = requireString(record.sha256, "file digest");
618
- if (!Number.isSafeInteger(byteLength) || Number(byteLength) <= 0 || Number(byteLength) > MAX_FILE_BYTES || !/^[\da-f]{64}$/iu.test(sha2562)) {
566
+ const sha256 = requireString(record.sha256, "file digest");
567
+ if (!Number.isSafeInteger(byteLength) || Number(byteLength) <= 0 || Number(byteLength) > MAX_FILE_BYTES || !/^[\da-f]{64}$/iu.test(sha256)) {
619
568
  throw new Error("embedded whiteboard file metadata is invalid");
620
569
  }
621
570
  return {
@@ -623,7 +572,7 @@ function requireFileWrite(value) {
623
572
  fileId: requireString(record.fileId, "file ID"),
624
573
  mimeType: normalizeMimeType(requireString(record.mimeType, "MIME type")),
625
574
  byteLength: Number(byteLength),
626
- sha256: sha2562.toLowerCase(),
575
+ sha256: sha256.toLowerCase(),
627
576
  dataURL: requireString(record.dataURL, "file data", Math.ceil(MAX_FILE_BYTES * 4 / 3) + 1024)
628
577
  };
629
578
  }
@@ -22,13 +22,6 @@ export declare class ChalkEmbeddedWhiteboardRendererBridge {
22
22
  }): Promise<WhiteboardCommit>;
23
23
  requestSnapshot(): Promise<void>;
24
24
  clear(): Promise<WhiteboardCommit>;
25
- uploadFile(input: {
26
- readonly fileId: string;
27
- readonly mimeType: string;
28
- readonly byteLength: number;
29
- readonly sha256: string;
30
- readonly dataURL: string;
31
- }): Promise<void>;
32
25
  downloadFile(fileId: string): Promise<{
33
26
  readonly mimeType: string;
34
27
  readonly dataURL: string;
@@ -14,7 +14,6 @@ export declare function createCollaborationBridge(rendererBridge: ChalkEmbeddedW
14
14
  requestSnapshot: () => Promise<void>;
15
15
  clear: () => Promise<import("..").WhiteboardCommit>;
16
16
  fileTransfer: {
17
- upload: (input: Parameters<ChalkEmbeddedWhiteboardRendererBridge["uploadFile"]>[0]) => Promise<void>;
18
17
  download: (fileId: string) => Promise<{
19
18
  readonly mimeType: string;
20
19
  readonly dataURL: string;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ExcalidrawCollabEngine
3
- } from "./chunk-F4B4ANIZ.js";
3
+ } from "./chunk-6ZV7GBAC.js";
4
4
  export {
5
5
  ExcalidrawCollabEngine
6
6
  };
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  mergeWhiteboardElements
3
- } from "./chunk-4XG2ABSP.js";
3
+ } from "./chunk-W4FLPXAX.js";
4
4
  import {
5
5
  fromWireElement,
6
6
  isWireElement,
7
7
  toWireElement
8
- } from "./chunk-F4B4ANIZ.js";
8
+ } from "./chunk-6ZV7GBAC.js";
9
9
  export {
10
10
  fromWireElement,
11
11
  isWireElement,
@@ -42,6 +42,8 @@ export interface WhiteboardCanvasProps {
42
42
  onExcalidrawApiReady?: (api: ExcalidrawImperativeAPI) => void;
43
43
  onLoadError?: (error: Error) => void;
44
44
  }
45
+ /** Starts loading the board's stylesheet before anyone opens the board, so the board opens without waiting for it. */
46
+ export declare function preloadWhiteboardStylesheet(href?: string): void;
45
47
  declare function WhiteboardCanvasBase(props: WhiteboardCanvasProps): React.JSX.Element;
46
48
  export declare const WhiteboardCanvas: import("react").MemoExoticComponent<typeof WhiteboardCanvasBase>;
47
49
  export {};
@@ -1,4 +1,4 @@
1
- export { WhiteboardCanvas } from "./WhiteboardCanvas.js";
1
+ export { WhiteboardCanvas, preloadWhiteboardStylesheet } from "./WhiteboardCanvas.js";
2
2
  export type { WhiteboardCanvasClassNames, WhiteboardCanvasIcons, WhiteboardCanvasProps, WhiteboardCollaborationOptions } from "./WhiteboardCanvas.js";
3
3
  export { appendOrReplaceMathElement, CHALK_MATH_CUSTOM_DATA_KEY, CHALK_MATH_RENDERER, createMathFileId, createMathImageAsset, getChalkMathData, getInsertionPoint, getSelectedMathElement, isChalkMathElement, svgToDataUrl } from "./math-elements.js";
4
4
  export type { ChalkMathCustomData, MathImageAsset } from "./math-elements.js";
@@ -294,28 +294,48 @@ function useWhiteboardCanvasConfiguration(props) {
294
294
  function valueOr(value, fallback) {
295
295
  return value === void 0 ? fallback : value;
296
296
  }
297
- function useExternalStylesheet(id, href) {
297
+ var STYLESHEET_ID = "chalk-excalidraw-styles";
298
+ function preloadWhiteboardStylesheet(href = DEFAULT_EXCALIDRAW_CSS) {
299
+ if (typeof document !== "undefined") boardStylesheet(href);
300
+ }
301
+ function boardStylesheet(href) {
302
+ const existing = document.getElementById(STYLESHEET_ID) ?? document.querySelector('link[href*="excalidraw"], style[data-href*="excalidraw"]');
303
+ if (existing) return existing;
304
+ const link = document.createElement("link");
305
+ link.id = STYLESHEET_ID;
306
+ link.rel = "stylesheet";
307
+ link.href = href;
308
+ link.addEventListener("load", () => link.dataset.state = "loaded");
309
+ link.addEventListener("error", () => link.dataset.state = "failed");
310
+ document.head.appendChild(link);
311
+ return link;
312
+ }
313
+ function isManagedStylesheet(element) {
314
+ return element instanceof HTMLLinkElement && element.id === STYLESHEET_ID;
315
+ }
316
+ function useExternalStylesheet(href) {
298
317
  const [loaded, setLoaded] = useState2(false);
299
318
  const [error, setError] = useState2(null);
300
319
  useEffect(() => {
301
- if (typeof document === "undefined") return;
302
- const existing = document.getElementById(id);
303
- if (existing || document.querySelector('link[href*="excalidraw"], style[data-href*="excalidraw"]')) {
320
+ const element = boardStylesheet(href);
321
+ const fail = () => setError(`Failed to load ${href}`);
322
+ const ownLink = isManagedStylesheet(element);
323
+ if (!ownLink || element.dataset.state === "loaded") {
304
324
  setLoaded(true);
305
325
  return;
306
326
  }
307
- const link = document.createElement("link");
308
- link.id = id;
309
- link.rel = "stylesheet";
310
- link.href = href;
311
- link.onload = () => setLoaded(true);
312
- link.onerror = () => setError(`Failed to load ${href}`);
313
- document.head.appendChild(link);
327
+ if (element.dataset.state === "failed") {
328
+ fail();
329
+ return;
330
+ }
331
+ const load = () => setLoaded(true);
332
+ element.addEventListener("load", load);
333
+ element.addEventListener("error", fail);
314
334
  return () => {
315
- link.onload = null;
316
- link.onerror = null;
335
+ element.removeEventListener("load", load);
336
+ element.removeEventListener("error", fail);
317
337
  };
318
- }, [href, id]);
338
+ }, [href]);
319
339
  return { error, loaded };
320
340
  }
321
341
  function useExcalidrawModule(onLoadError, setLoadError) {
@@ -347,7 +367,7 @@ function useWhiteboardInitialData(theme, localParticipantColor) {
347
367
  [localParticipantColor, theme]
348
368
  );
349
369
  }
350
- function useWhiteboardUiOptions(canDraw) {
370
+ function useWhiteboardUiOptions() {
351
371
  return useMemo(
352
372
  () => ({
353
373
  canvasActions: {
@@ -359,16 +379,16 @@ function useWhiteboardUiOptions(canDraw) {
359
379
  saveToActiveFile: false,
360
380
  toggleTheme: false
361
381
  },
362
- tools: { image: canDraw },
382
+ tools: { image: false },
363
383
  welcomeScreen: false
364
384
  }),
365
- [canDraw]
385
+ []
366
386
  );
367
387
  }
368
388
  function useWhiteboardCollaboration(options) {
369
389
  const apiRef = useRef(null);
370
390
  const refs = useCollaborationRefs(options.collab, options.canDraw);
371
- const initializeEngine = useCollaborationEngineLoader(refs, options.onLoadError, options.setLoadError);
391
+ const initializeEngine = useCollaborationEngineLoader(refs, apiRef, options.onLoadError, options.setLoadError);
372
392
  const handleApiReady = useExcalidrawApiReady(apiRef, initializeEngine, options.onExcalidrawApiReady);
373
393
  const handlers = useExcalidrawSceneHandlers(apiRef, refs.engineRef, options.onSelectedLatexChange);
374
394
  useCollaborationCanDraw(refs.engineRef, options.canDraw);
@@ -386,46 +406,42 @@ function useCollaborationRefs(collab, canDraw) {
386
406
  collabOptionsRef.current = collab;
387
407
  return useMemo(() => ({ canDrawRef, collabOptionsRef, enginePromiseRef, engineRef, isMountedRef }), [canDrawRef, collabOptionsRef, enginePromiseRef, engineRef, isMountedRef]);
388
408
  }
389
- function useCollaborationEngineLoader(refs, onLoadError, setLoadError) {
390
- return useCallback(
391
- (api) => {
392
- if (!refs.collabOptionsRef.current || refs.engineRef.current || refs.enginePromiseRef.current) return;
393
- refs.enginePromiseRef.current = import("../engine-5XZHDUXG.js").then(({ ExcalidrawCollabEngine }) => {
394
- const collab = refs.collabOptionsRef.current;
395
- if (!refs.isMountedRef.current || !collab || refs.engineRef.current) return;
396
- refs.engineRef.current = new ExcalidrawCollabEngine({
397
- excalidrawAPI: api,
398
- canDraw: refs.canDrawRef.current,
399
- submitUpdate: collab.submitUpdate,
400
- sendCursor: collab.sendCursor,
401
- requestSnapshot: collab.requestSnapshot,
402
- clear: collab.clear,
403
- fileTransfer: collab.fileTransfer,
404
- initiateUpload: collab.initiateUpload,
405
- finalizeUpload: collab.finalizeUpload,
406
- presignDownload: collab.presignDownload,
407
- subscribe: collab.subscribe,
408
- onFileSyncStateChange: collab.onFileSyncStateChange,
409
- onSubmissionError: collab.onSubmissionError
410
- });
411
- }).catch((reason) => {
412
- if (!refs.isMountedRef.current) return;
413
- const error = reason instanceof Error ? reason : new Error("Failed to load whiteboard collaboration");
414
- setLoadError(error.message);
415
- onLoadError?.(error);
416
- }).finally(() => {
417
- refs.enginePromiseRef.current = null;
409
+ function useCollaborationEngineLoader(refs, apiRef, onLoadError, setLoadError) {
410
+ return useCallback(() => {
411
+ if (!refs.collabOptionsRef.current || refs.engineRef.current || refs.enginePromiseRef.current) return;
412
+ refs.enginePromiseRef.current = import("../engine-BIJ57YN3.js").then(({ ExcalidrawCollabEngine }) => {
413
+ const api = apiRef.current;
414
+ const collab = refs.collabOptionsRef.current;
415
+ if (!refs.isMountedRef.current || !api || !collab) return;
416
+ refs.engineRef.current = new ExcalidrawCollabEngine({
417
+ excalidrawAPI: api,
418
+ canDraw: refs.canDrawRef.current,
419
+ submitUpdate: collab.submitUpdate,
420
+ sendCursor: collab.sendCursor,
421
+ requestSnapshot: collab.requestSnapshot,
422
+ clear: collab.clear,
423
+ fileTransfer: collab.fileTransfer,
424
+ presignDownload: collab.presignDownload,
425
+ subscribe: collab.subscribe,
426
+ onFileSyncStateChange: collab.onFileSyncStateChange,
427
+ onSubmissionError: collab.onSubmissionError
418
428
  });
419
- },
420
- [onLoadError, refs, setLoadError]
421
- );
429
+ }).catch((reason) => {
430
+ if (!refs.isMountedRef.current) return;
431
+ const error = reason instanceof Error ? reason : new Error("Failed to load whiteboard collaboration");
432
+ setLoadError(error.message);
433
+ onLoadError?.(error);
434
+ }).finally(() => {
435
+ refs.enginePromiseRef.current = null;
436
+ });
437
+ }, [apiRef, onLoadError, refs, setLoadError]);
422
438
  }
423
439
  function useExcalidrawApiReady(apiRef, initializeEngine, onExcalidrawApiReady) {
424
440
  const didReportApiRef = useRef(false);
425
441
  return useCallback(
426
442
  (api) => {
427
443
  apiRef.current = api;
428
- initializeEngine(api);
444
+ initializeEngine();
429
445
  if (!didReportApiRef.current) {
430
446
  didReportApiRef.current = true;
431
447
  onExcalidrawApiReady?.(api);
@@ -484,7 +500,7 @@ function useCollaborationInitialization(collab, apiRef, engineRef, initializeEng
484
500
  engineRef.current = null;
485
501
  return;
486
502
  }
487
- if (apiRef.current) initializeEngine(apiRef.current);
503
+ if (apiRef.current) initializeEngine();
488
504
  }, [apiRef, collab, engineRef, initializeEngine]);
489
505
  }
490
506
  function useWhiteboardMath({ apiRef, canDraw, excalidraw, isCollaborating, selectedLatex, setSelectedLatex, syncScene }) {
@@ -511,14 +527,14 @@ function useWhiteboardMath({ apiRef, canDraw, excalidraw, isCollaborating, selec
511
527
  },
512
528
  [apiRef, closeMath, excalidraw, isCollaborating, setSelectedLatex, syncScene]
513
529
  );
514
- return { closeMath, handleSubmitMath, isMathOpen, openMath, selectedLatex };
530
+ return { closeMath, handleSubmitMath, initialLatex: selectedLatex ?? DEFAULT_LATEX, isMathOpen, openMath, selectedLatex };
515
531
  }
516
532
  function useWhiteboardCanvasState(props) {
517
533
  const configuration = useWhiteboardCanvasConfiguration(props);
518
534
  const [loadError, setLoadError] = useState2(null);
519
535
  const [selectedLatex, setSelectedLatex] = useState2(null);
520
536
  const excalidraw = useExcalidrawModule(props.onLoadError, setLoadError);
521
- const stylesheet = useExternalStylesheet("chalk-excalidraw-styles", configuration.excalidrawCssPath);
537
+ const stylesheet = useExternalStylesheet(configuration.excalidrawCssPath);
522
538
  const collaboration = useWhiteboardCollaboration({
523
539
  canDraw: configuration.canDraw,
524
540
  collab: props.collab,
@@ -537,7 +553,7 @@ function useWhiteboardCanvasState(props) {
537
553
  syncScene: collaboration.syncScene
538
554
  });
539
555
  const initialData = useWhiteboardInitialData(configuration.theme, props.localParticipantColor);
540
- const uiOptions = useWhiteboardUiOptions(configuration.canDraw);
556
+ const uiOptions = useWhiteboardUiOptions();
541
557
  const resolvedLoadError = loadError ?? stylesheet.error;
542
558
  return {
543
559
  collaboration,
@@ -553,7 +569,7 @@ function useWhiteboardCanvasState(props) {
553
569
  function WhiteboardCanvasView({ state }) {
554
570
  const { collaboration, configuration, excalidraw, initialData, isReady, math, resolvedLoadError, uiOptions } = state;
555
571
  return /* @__PURE__ */ jsxs2("div", { className: configuration.rootClassName, hidden: !configuration.isVisible, children: [
556
- /* @__PURE__ */ jsx2(WhiteboardMathToolbar, { canDraw: configuration.canDraw, classNames: configuration.classNames, isReady, onOpenMath: math.openMath, selectedLatex: math.selectedLatex }),
572
+ /* @__PURE__ */ jsx2(WhiteboardMathToolbar, { canDraw: configuration.canDraw && !configuration.isCollaborating, classNames: configuration.classNames, isReady, onOpenMath: math.openMath, selectedLatex: math.selectedLatex }),
557
573
  /* @__PURE__ */ jsx2(WhiteboardCanvasStatus, { classNames: configuration.classNames, error: resolvedLoadError, icons: configuration.icons, isReady }),
558
574
  excalidraw && /* @__PURE__ */ jsx2(
559
575
  WhiteboardScene,
@@ -569,12 +585,13 @@ function WhiteboardCanvasView({ state }) {
569
585
  uiOptions
570
586
  }
571
587
  ),
572
- math.isMathOpen && /* @__PURE__ */ jsx2(MathEditor, { initialLatex: math.selectedLatex ?? DEFAULT_LATEX, isEditing: Boolean(math.selectedLatex), classNames: configuration.classNames, icons: configuration.icons, onClose: math.closeMath, onSubmit: math.handleSubmitMath })
588
+ math.isMathOpen && /* @__PURE__ */ jsx2(MathEditor, { initialLatex: math.initialLatex, isEditing: Boolean(math.selectedLatex), classNames: configuration.classNames, icons: configuration.icons, onClose: math.closeMath, onSubmit: math.handleSubmitMath })
573
589
  ] });
574
590
  }
575
591
  function WhiteboardMathToolbar({ canDraw, classNames, isReady, onOpenMath, selectedLatex }) {
576
- if (!isReady) return null;
577
- return /* @__PURE__ */ jsx2("div", { className: classNames.toolbar, style: { position: "absolute", top: 12, left: 12, zIndex: 20, display: "flex" }, children: /* @__PURE__ */ jsx2("button", { type: "button", onClick: onOpenMath, disabled: !canDraw, className: classNames.toolbarButton, "aria-label": selectedLatex ? "Edit math equation" : "Insert math equation", title: selectedLatex ? "Edit equation" : "Math", children: "\u2211" }) });
592
+ if (!isReady || !canDraw) return null;
593
+ const label = selectedLatex ? "Edit math equation" : "Insert math equation";
594
+ return /* @__PURE__ */ jsx2("div", { className: classNames.toolbar, style: { position: "absolute", top: 12, left: 12, zIndex: 20, display: "flex" }, children: /* @__PURE__ */ jsx2("button", { type: "button", onClick: onOpenMath, disabled: !canDraw, className: classNames.toolbarButton, "aria-label": label, title: label, children: "\u2211" }) });
578
595
  }
579
596
  function WhiteboardCanvasStatus({ classNames, error, icons, isReady }) {
580
597
  if (error) return /* @__PURE__ */ jsx2(WhiteboardLoadError, { className: classNames.error, error });
@@ -620,6 +637,7 @@ export {
620
637
  getRenderedSvgSize,
621
638
  getSelectedMathElement,
622
639
  isChalkMathElement,
640
+ preloadWhiteboardStylesheet,
623
641
  renderLatexToSvg,
624
642
  svgToDataUrl
625
643
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q9labsai/chalk-whiteboard",
3
- "version": "4.1.16",
3
+ "version": "5.0.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -63,7 +63,6 @@
63
63
  },
64
64
  "dependencies": {
65
65
  "@excalidraw/excalidraw": "0.18.1",
66
- "@noble/hashes": "2.3.0",
67
66
  "mathjax": "4.1.3"
68
67
  },
69
68
  "devDependencies": {
@@ -89,7 +88,7 @@
89
88
  "dev": "tsup ./src/index.ts ./src/react/index.ts ./src/collab/index.ts ./src/embedded/index.ts --format esm --out-dir ./dist --platform browser --splitting --external react --external react-dom --external @excalidraw/excalidraw --watch",
90
89
  "test": "pnpm exec vitest run && pnpm run test:declarations",
91
90
  "test:declarations": "node --test scripts/rewrite-declaration-specifiers-proof.mjs",
92
- "check-types": "tsc --noEmit",
91
+ "check-types": "tsc-rs --noEmit",
93
92
  "lint": "pnpm exec oxfmt --check . && tsc --noEmit",
94
93
  "clean": "rm -rf dist"
95
94
  }