1// The vendored pulseq +mr package as numbl boot files. The tree is inlined
2// into the bundle at build time (raw imports); see src/engine/pulseq/VENDORED.md
3// for provenance.
4import type { BootFile } from 'numbl/browser'
6const raw = import.meta.glob('./pulseq/+mr/**/*.m', {
7 query: '?raw',
8 import: 'default',
9 eager: true,
10}) as Record<string, string>
12// pulseq's md5 needs Java (MATLAB) or the `hash` builtin (Octave). numbl
13// provides `hash`, but md5.m only reaches it through its isOctave branch —
14// replace the whole file with a direct wrapper.
15const MD5_OVERRIDE = `function digest = md5(message, noBuiltIn)
16 digest = hash('MD5', char(message));
17end
18`
20// There is no Python/SigPy (and no OS `system` command) in the browser.
21// isSigPyAvailable probes for it via system(); stub it to "not available" so
22// pulse designers (adiabatic, SLR) take their internal non-sigpy path.
23const ISSIGPY_OVERRIDE = `function [sigPyOK, pythonExe] = isSigPyAvailable()
24 sigPyOK = false;
25 pythonExe = '';
26end
27`
29const OVERRIDES: Record<string, string> = {
30 '+mr/+aux/md5.m': MD5_OVERRIDE,
31 '+mr/+aux/isSigPyAvailable.m': ISSIGPY_OVERRIDE,
32}
34/** Boot-file list for a session: the +mr tree with app-level overrides applied. */
35export function mrBootFiles(): BootFile[] {
36 const files: BootFile[] = []
37 for (const [key, content] of Object.entries(raw)) {
38 const path = key.replace('./pulseq/', '')
39 files.push({ path, content: OVERRIDES[path] ?? content })
40 }
41 return files
42}