@yam8d/m8-sdk 0.1.0 → 0.2.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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["// @ts-expect-error - post-me types are incomplete for the generic handshake signatures used here.\nimport { ChildHandshake, DebugMessenger, WindowMessenger } from 'post-me'\n// @ts-expect-error - post-me types are incomplete for the generic handshake signatures used here.\nimport type { Connection, LocalHandle, RemoteHandle } from 'post-me'\nimport type { M8ClientEvents, M8ClientMethods, M8HostEvents, M8HostMethods, M8KeyName, M8SdkConfig, M8State } from './types'\n\nexport type { CursorPos, CursorRect, M8KeyName, M8State, RGB, SystemInfos } from './types'\n\nexport interface M8Client {\n readonly state: M8State\n readonly isConnected: boolean\n navigateToView(viewName: string): Promise<boolean>\n navigateTo(x: number, y: number): Promise<void>\n setValueToHex(targetHex: number): Promise<boolean>\n setValueToInt(targetInt: number): Promise<boolean>\n setNote(noteString: string): Promise<boolean>\n setValueToString(targetString: string, exact?: boolean, searchInCurrentLine?: boolean): Promise<boolean>\n browseFile(targetText: string, exact?: boolean): Promise<boolean>\n sendKeyPress(keys: M8KeyName[]): Promise<void>\n sendKeyDown(keys: M8KeyName[]): Promise<void>\n sendKeyUp(): Promise<void>\n getState(): M8State\n fetchState(): Promise<M8State>\n onStateChange(callback: (state: M8State) => void): () => void\n onViewChange(callback: (viewName: string | null, viewTitle: string | null) => void): () => void\n onCursorMove(callback: (pos: M8State['cursorPos'], rect: M8State['cursorRect'], selectionMode: boolean) => void): () => void\n onTextUpdate(callback: (textUnderCursor: string | null, currentLine: string | null) => void): () => void\n onKeyPress(callback: (keys: number) => void): () => void\n disconnect(): void\n}\n\nconst getDefaultState = (): M8State => ({\n viewName: null,\n viewTitle: null,\n minimapKey: null,\n cursorPos: null,\n cursorRect: null,\n selectionMode: false,\n highlightColor: null,\n titleColor: null,\n backgroundColor: null,\n textUnderCursor: null,\n currentLine: null,\n deviceModel: null,\n fontMode: null,\n systemInfo: null,\n macroRunning: false,\n})\n\nclass M8ClientImpl implements M8Client {\n private connection: Connection<M8ClientMethods, M8HostEvents, M8HostMethods, M8ClientEvents> | null = null\n private remoteHandle: RemoteHandle<M8HostMethods, M8HostEvents> | null = null\n private localHandle: LocalHandle<M8ClientMethods, M8ClientEvents> | null = null\n private readonly stateCallbacks = new Set<(state: M8State) => void>()\n private readonly viewCallbacks = new Set<(viewName: string | null, viewTitle: string | null) => void>()\n private readonly cursorCallbacks = new Set<(pos: M8State['cursorPos'], rect: M8State['cursorRect'], selectionMode: boolean) => void>()\n private readonly textCallbacks = new Set<(textUnderCursor: string | null, currentLine: string | null) => void>()\n private readonly keyCallbacks = new Set<(keys: number) => void>()\n private _state: M8State = getDefaultState()\n private _isConnected = false\n private readonly config: M8SdkConfig\n\n constructor(config: M8SdkConfig = {}) {\n this.config = config\n }\n\n get state(): M8State {\n return this._state\n }\n\n get isConnected(): boolean {\n return this._isConnected\n }\n\n async connect(): Promise<void> {\n if (this.connection) {\n return\n }\n\n let messenger = new WindowMessenger({\n localWindow: window,\n remoteWindow: window.parent,\n remoteOrigin: '*',\n })\n\n if (this.config.debug) {\n messenger = DebugMessenger(messenger, (msg: string, ...args: unknown[]) => {\n console.log('[M8 SDK]', msg, ...args)\n })\n }\n\n const connection = await ChildHandshake<M8ClientMethods, M8HostEvents, M8HostMethods, M8ClientEvents>(messenger, {\n ping: async () => 'pong',\n })\n\n this.connection = connection\n this.remoteHandle = connection.remoteHandle()\n this.localHandle = connection.localHandle()\n this._isConnected = true\n\n this.remoteHandle.addEventListener('stateChanged', (state: M8State) => {\n this._state = state\n this.stateCallbacks.forEach((cb) => {\n cb(state)\n })\n })\n\n this.remoteHandle.addEventListener('viewChanged', ({ viewName, viewTitle }: { viewName: string | null; viewTitle: string | null }) => {\n this._state = { ...this._state, viewName, viewTitle }\n this.viewCallbacks.forEach((cb) => {\n cb(viewName, viewTitle)\n })\n })\n\n this.remoteHandle.addEventListener('cursorMoved', ({ pos, rect, selectionMode }: { pos: M8State['cursorPos']; rect: M8State['cursorRect']; selectionMode: boolean }) => {\n this._state = { ...this._state, cursorPos: pos, cursorRect: rect, selectionMode }\n this.cursorCallbacks.forEach((cb) => {\n cb(pos, rect, selectionMode)\n })\n })\n\n this.remoteHandle.addEventListener('textUpdated', ({ textUnderCursor, currentLine }: { textUnderCursor: string | null; currentLine: string | null }) => {\n this._state = { ...this._state, textUnderCursor, currentLine }\n this.textCallbacks.forEach((cb) => {\n cb(textUnderCursor, currentLine)\n })\n })\n\n this.remoteHandle.addEventListener('keyPressed', ({ keys }: { keys: number }) => {\n this.keyCallbacks.forEach((cb) => {\n cb(keys)\n })\n })\n\n await this.fetchState()\n this.localHandle.emit('ready', undefined)\n }\n\n async navigateToView(viewName: string): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('navigateToView', viewName)\n }\n\n async navigateTo(x: number, y: number): Promise<void> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('navigateTo', x, y)\n }\n\n async setValueToHex(targetHex: number): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('setValueToHex', targetHex)\n }\n\n async setValueToInt(targetInt: number): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('setValueToInt', targetInt)\n }\n\n async setNote(noteString: string): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('setNote', noteString)\n }\n\n async setValueToString(targetString: string, exact = true, searchInCurrentLine = false): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('setValueToString', targetString, exact, searchInCurrentLine)\n }\n\n async browseFile(targetText: string, exact = true): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('browseFile', targetText, exact)\n }\n\n async sendKeyPress(keys: M8KeyName[]): Promise<void> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('sendKeyPress', keys)\n }\n\n async sendKeyDown(keys: M8KeyName[]): Promise<void> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('sendKeyDown', keys)\n }\n\n async sendKeyUp(): Promise<void> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('sendKeyUp')\n }\n\n getState(): M8State {\n return this._state\n }\n\n async fetchState(): Promise<M8State> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n const state = await this.remoteHandle.call('getState')\n this._state = state\n return state\n }\n\n onStateChange(callback: (state: M8State) => void): () => void {\n this.stateCallbacks.add(callback)\n return () => this.stateCallbacks.delete(callback)\n }\n\n onViewChange(callback: (viewName: string | null, viewTitle: string | null) => void): () => void {\n this.viewCallbacks.add(callback)\n return () => this.viewCallbacks.delete(callback)\n }\n\n onCursorMove(callback: (pos: M8State['cursorPos'], rect: M8State['cursorRect'], selectionMode: boolean) => void): () => void {\n this.cursorCallbacks.add(callback)\n return () => this.cursorCallbacks.delete(callback)\n }\n\n onTextUpdate(callback: (textUnderCursor: string | null, currentLine: string | null) => void): () => void {\n this.textCallbacks.add(callback)\n return () => this.textCallbacks.delete(callback)\n }\n\n onKeyPress(callback: (keys: number) => void): () => void {\n this.keyCallbacks.add(callback)\n return () => this.keyCallbacks.delete(callback)\n }\n\n disconnect(): void {\n this.connection?.close()\n this.connection = null\n this.remoteHandle = null\n this.localHandle = null\n this._isConnected = false\n this.stateCallbacks.clear()\n this.viewCallbacks.clear()\n this.cursorCallbacks.clear()\n this.textCallbacks.clear()\n this.keyCallbacks.clear()\n }\n}\n\nexport async function createM8Client(config: M8SdkConfig = {}): Promise<M8Client> {\n const client = new M8ClientImpl(config)\n await client.connect()\n return client\n}\n\nexport function createM8ClientSync(config: M8SdkConfig = {}): { client: M8Client; connect: () => Promise<void> } {\n const client = new M8ClientImpl(config)\n return {\n client,\n connect: async () => {\n await client.connect()\n },\n }\n}\n\nexport default {\n createM8Client,\n createM8ClientSync,\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/m8-view-context.json","../src/viewContext.ts","../src/client.ts"],"sourcesContent":["{\r\n \"version\": \"1.0\",\r\n \"description\": \"Semantic mapping of M8 tracker views: defines the structure of each grid view so cursor position + line text can be interpreted as typed field values.\",\r\n \"notes\": {\r\n \"fontMode\": \"All x/width values assume font mode 0 (standard, 12×14 px cells, 40 cols × ~22 rows). Font modes 1 (bold uppercase) and 2 (large) may shift column positions.\",\r\n \"playbackIndicator\": \"The M8 renders a '>' character one column to the left of the first data column when that step/row/track is currently playing. This character is part of the text stream; the editing cursor is a separate rect overlay.\",\r\n \"emptyCell\": \"An empty or unused cell displays '--' (2 chars) or '---' (3 chars) or '---00' (command+value). Parsed hexValue will be null for these.\",\r\n \"relativeHex\": \"Transpose and some FX values use relative hex: 00 = no change, 01-7F = +1-127, FF-80 = -1-128. See 'Relative and Absolute FX Commands' in the manual.\",\r\n \"rowIndex\": \"Row/step indices are parsed from the leftmost characters of currentLine. They are hex for all grid views.\"\r\n },\r\n \"fieldTypes\": {\r\n \"chainRef\": \"Reference to a chain number (hex 00-FF). '--' means empty/unused.\",\r\n \"phraseRef\": \"Reference to a phrase number (hex 00-FF). '--' means empty/unused.\",\r\n \"note\": \"Musical note in M8 format: [A-G][#|-][0-9] e.g. 'C-4', 'A#3'. '---' = empty. 'OFF' = note-off.\",\r\n \"velocity\": \"Note velocity 00-7F (hex). Default is 64 (hex). '--' = inherit.\",\r\n \"instrumentRef\": \"Instrument number 00-7F (hex). '--' = no retrigger (keep current instrument).\",\r\n \"fxCommand\": \"3-character sequencer or instrument FX command name, e.g. 'KIL', 'ARP', 'DEL'. '---' = none.\",\r\n \"fxValue\": \"2-char hex value 00-FF accompanying an FX command. Interpretation depends on the command.\",\r\n \"transpose\": \"Semitone or tick transpose. Relative: 00=none, 01-7F=+1-+127, FF-80=-1--128.\",\r\n \"ticks\": \"Number of ticks this step consumes in a groove (hex 01-FF). '00' skips the step. '--' = empty (groove loops at this point).\",\r\n \"volume\": \"Volume multiplier 00-FF (hex). Multiplied with the phrase-row velocity. '--' = no override.\", \"ppq\": \"Pulses Per Quarter note: resolution of the groove clock (decimal). Only editable on groove row 0.\",\r\n \"instrumentName\": \"Instrument name string (up to 12 characters). Text field, no hex value.\",\r\n \"eqSlot\": \"EQ slot assignment (hex). '--' = no EQ applied to this instrument.\",\r\n \"rowIndex\": \"The positional index of this row in the current view (song row, chain position, phrase step, etc.).\"\r\n },\r\n \"views\": {\r\n \"song\": {\r\n \"title\": \"Song View\",\r\n \"type\": \"grid\",\r\n \"description\": \"Arranges chains across 8 independent tracks to form the song structure. Each row is a song position; each column is a track.\",\r\n \"rowField\": {\r\n \"x\": 0, \"width\": 2, \"parse\": \"hex\", \"type\": \"rowIndex\",\r\n \"key\": \"songRow\", \"description\": \"Song row 00-FF. Each track loops back to row 00 when it reaches '--'.\"\r\n },\r\n \"columns\": [\r\n { \"x\": 3, \"width\": 2, \"key\": \"track1\", \"type\": \"chainRef\", \"label\": \"Track 1\", \"meta\": { \"trackIndex\": 1 } },\r\n { \"x\": 6, \"width\": 2, \"key\": \"track2\", \"type\": \"chainRef\", \"label\": \"Track 2\", \"meta\": { \"trackIndex\": 2 } },\r\n { \"x\": 9, \"width\": 2, \"key\": \"track3\", \"type\": \"chainRef\", \"label\": \"Track 3\", \"meta\": { \"trackIndex\": 3 } },\r\n { \"x\": 12, \"width\": 2, \"key\": \"track4\", \"type\": \"chainRef\", \"label\": \"Track 4\", \"meta\": { \"trackIndex\": 4 } },\r\n { \"x\": 15, \"width\": 2, \"key\": \"track5\", \"type\": \"chainRef\", \"label\": \"Track 5\", \"meta\": { \"trackIndex\": 5 } },\r\n { \"x\": 18, \"width\": 2, \"key\": \"track6\", \"type\": \"chainRef\", \"label\": \"Track 6\", \"meta\": { \"trackIndex\": 6 } },\r\n { \"x\": 21, \"width\": 2, \"key\": \"track7\", \"type\": \"chainRef\", \"label\": \"Track 7\", \"meta\": { \"trackIndex\": 7 } },\r\n { \"x\": 24, \"width\": 2, \"key\": \"track8\", \"type\": \"chainRef\", \"label\": \"Track 8\", \"meta\": { \"trackIndex\": 8 } }\r\n ]\r\n },\r\n \"chain\": {\r\n \"title\": \"Chain View\",\r\n \"type\": \"grid\",\r\n \"description\": \"An ordered list of up to 16 phrases. The first '--' phrase ends the chain and loops back to the song.\",\r\n \"rowField\": {\r\n \"x\": 0, \"width\": 1, \"parse\": \"hex\", \"type\": \"rowIndex\",\r\n \"key\": \"chainPos\", \"description\": \"Position within the chain (0-F, max 16 entries).\"\r\n },\r\n \"columns\": [\r\n { \"x\": 2, \"width\": 2, \"key\": \"phrase\", \"type\": \"phraseRef\", \"label\": \"Phrase (PH)\", \"description\": \"Phrase number to play at this chain position.\" },\r\n { \"x\": 5, \"width\": 2, \"key\": \"transpose\", \"type\": \"transpose\", \"label\": \"Transpose (TSP)\", \"description\": \"Optional note transpose in semitones applied to every note in the phrase (relative hex).\" }\r\n ]\r\n },\r\n \"phrase\": {\r\n \"title\": \"Phrase View\",\r\n \"type\": \"grid\",\r\n \"description\": \"A 16-step sequence. Each step holds a note, velocity, instrument assignment, and up to 3 FX command+value pairs.\",\r\n \"rowField\": {\r\n \"x\": 0, \"width\": 1, \"parse\": \"hex\", \"type\": \"rowIndex\",\r\n \"key\": \"step\", \"description\": \"Step index 0-F (16th note by default; altered by groove).\"\r\n },\r\n \"columns\": [\r\n { \"x\": 2, \"width\": 3, \"key\": \"note\", \"type\": \"note\", \"label\": \"Note (N)\" },\r\n { \"x\": 6, \"width\": 2, \"key\": \"vel\", \"type\": \"velocity\", \"label\": \"Velocity (V)\" },\r\n { \"x\": 9, \"width\": 2, \"key\": \"inst\", \"type\": \"instrumentRef\", \"label\": \"Instrument (I)\" },\r\n { \"x\": 12, \"width\": 3, \"key\": \"fx1cmd\", \"type\": \"fxCommand\", \"label\": \"FX1 Command\" },\r\n { \"x\": 15, \"width\": 2, \"key\": \"fx1val\", \"type\": \"fxValue\", \"label\": \"FX1 Value\" },\r\n { \"x\": 18, \"width\": 3, \"key\": \"fx2cmd\", \"type\": \"fxCommand\", \"label\": \"FX2 Command\" },\r\n { \"x\": 21, \"width\": 2, \"key\": \"fx2val\", \"type\": \"fxValue\", \"label\": \"FX2 Value\" },\r\n { \"x\": 24, \"width\": 3, \"key\": \"fx3cmd\", \"type\": \"fxCommand\", \"label\": \"FX3 Command\" },\r\n { \"x\": 27, \"width\": 2, \"key\": \"fx3val\", \"type\": \"fxValue\", \"label\": \"FX3 Value\" }\r\n ]\r\n },\r\n \"table\": {\r\n \"title\": \"Table View\",\r\n \"type\": \"grid\",\r\n \"description\": \"A 16-step mini-sequencer that runs alongside an instrument. Used for arpeggios, multi-stage envelopes, and automated FX.\",\r\n \"rowField\": {\r\n \"x\": 0, \"width\": 1, \"parse\": \"hex\", \"type\": \"rowIndex\",\r\n \"key\": \"step\", \"description\": \"Table step 0-F. Loops from bottom unless a HOP command redirects.\"\r\n },\r\n \"columns\": [\r\n { \"x\": 2, \"width\": 2, \"key\": \"transpose\", \"type\": \"transpose\", \"label\": \"Transpose (N)\", \"description\": \"Transposes the instrument for this step (relative hex). '--' = no transpose.\" },\r\n { \"x\": 5, \"width\": 2, \"key\": \"volume\", \"type\": \"volume\", \"label\": \"Volume (V)\", \"description\": \"Volume multiplier applied on top of the phrase velocity (hex). '--' = no override.\" },\r\n { \"x\": 8, \"width\": 3, \"key\": \"fx1cmd\", \"type\": \"fxCommand\", \"label\": \"FX1 Command\", \"description\": \"3-char command name for table FX slot 1.\" },\r\n { \"x\": 11, \"width\": 2, \"key\": \"fx1val\", \"type\": \"fxValue\", \"label\": \"FX1 Value\", \"description\": \"Value for table FX1.\" },\r\n { \"x\": 14, \"width\": 3, \"key\": \"fx2cmd\", \"type\": \"fxCommand\", \"label\": \"FX2 Command\", \"description\": \"3-char command name for table FX slot 2.\" },\r\n { \"x\": 17, \"width\": 2, \"key\": \"fx2val\", \"type\": \"fxValue\", \"label\": \"FX2 Value\", \"description\": \"Value for table FX2.\" },\r\n { \"x\": 20, \"width\": 3, \"key\": \"fx3cmd\", \"type\": \"fxCommand\", \"label\": \"FX3 Command\", \"description\": \"3-char command name for table FX slot 3.\" },\r\n { \"x\": 23, \"width\": 2, \"key\": \"fx3val\", \"type\": \"fxValue\", \"label\": \"FX3 Value\", \"description\": \"Value for table FX3.\" }\r\n ]\r\n },\r\n \"groove\": {\r\n \"title\": \"Groove View\",\r\n \"type\": \"grid\",\r\n \"description\": \"Defines the timing of each phrase step in ticks. Used to create swing, shuffle, triplets, and other rhythmic feels.\",\r\n \"rowField\": {\r\n \"x\": 0, \"width\": 1, \"parse\": \"hex\", \"type\": \"rowIndex\",\r\n \"key\": \"step\", \"description\": \"Groove step 0-F. The groove loops when a '--' entry is reached.\"\r\n },\r\n \"columns\": [\r\n { \"x\": 2, \"width\": 2, \"key\": \"ticks\", \"type\": \"ticks\", \"label\": \"Ticks (TIC)\", \"description\": \"Number of ticks this step takes. Default is 06 (at 24 PPQN = 1 sixteenth note). '00' skips the step.\" },\r\n { \"x\": 6, \"width\": 2, \"key\": \"ppq\", \"type\": \"ppq\", \"label\": \"PPQ\", \"description\": \"Pulses Per Quarter note. Only present on groove row 0; absent on all other rows.\" }\r\n ]\r\n },\r\n \"instrumentpool\": {\r\n \"title\": \"Instrument Pool\",\r\n \"type\": \"grid\",\r\n \"description\": \"Lists all instrument slots with their mix routing. Each row shows the instrument name and its dry/FX send levels.\",\r\n \"rowField\": {\r\n \"x\": 0, \"width\": 2, \"parse\": \"hex\", \"type\": \"rowIndex\",\r\n \"key\": \"instIndex\", \"description\": \"Instrument slot index 00-7F.\"\r\n },\r\n \"columns\": [\r\n { \"x\": 3, \"width\": 12, \"key\": \"name\", \"type\": \"instrumentName\", \"label\": \"Instrument Name\", \"description\": \"Name of the instrument in this slot (up to 12 chars). '------------' = empty slot.\" },\r\n { \"x\": 16, \"width\": 2, \"key\": \"dry\", \"type\": \"volume\", \"label\": \"Dry (DRY)\", \"description\": \"Direct output volume for this instrument (hex 00-FF).\" },\r\n { \"x\": 19, \"width\": 2, \"key\": \"mx\", \"type\": \"volume\", \"label\": \"ModFX (MX)\", \"description\": \"ModFX send level (hex 00-FF).\" },\r\n { \"x\": 22, \"width\": 2, \"key\": \"de\", \"type\": \"volume\", \"label\": \"Delay (DE)\", \"description\": \"Delay send level (hex 00-FF).\" },\r\n { \"x\": 25, \"width\": 2, \"key\": \"rv\", \"type\": \"volume\", \"label\": \"Reverb (RV)\", \"description\": \"Reverb send level (hex 00-FF).\" },\r\n { \"x\": 28, \"width\": 2, \"key\": \"eq\", \"type\": \"eqSlot\", \"label\": \"EQ Slot (EQ)\", \"description\": \"EQ slot assignment. '--' = no EQ.\" }\r\n ]\r\n }\r\n },\r\n \"fxCommands\": {\r\n \"sequencer\": {\r\n \"ARP\": { \"description\": \"Arpeggio: plays 3 notes rapidly. X=first interval semitones, Y=second interval semitones.\" },\r\n \"ARC\": { \"description\": \"Arpeggio Config: X=mode, Y=speed in ticks.\" },\r\n \"CHA\": { \"description\": \"Chance: X=probability left of command (0=never, F=always), Y=probability right.\" },\r\n \"DEL\": { \"description\": \"Delay: in phrase delays entire row by XX ticks; in table delays table playhead.\" },\r\n \"GRV\": { \"description\": \"Groove: sets groove number XX for the current track.\" },\r\n \"GGR\": { \"description\": \"Global Groove: sets groove XX for all tracks.\" },\r\n \"HOP\": { \"description\": \"Hop: in phrase jumps to row Y of next phrase; HOPFF stops track. In table loops to row Y X times.\" },\r\n \"INS\": { \"description\": \"Instrument: changes active instrument to XX as an FX command.\" },\r\n \"KIL\": { \"description\": \"Kill: stops the playing instrument after XX ticks.\" },\r\n \"RND\": { \"description\": \"Random: randomises the preceding FX command. X=left range, Y=right range (0=none, F=full).\" },\r\n \"RNL\": { \"description\": \"Randomise Left: randomises the FX command to the left.\" },\r\n \"RET\": { \"description\": \"Retrig: retriggers current row. Y≠0: retrig every Y ticks with X volume ramp. Y=0: single retrig after X ticks.\" },\r\n \"REP\": { \"description\": \"Repeat: repeats and increments the last FX command by XX each step.\" },\r\n \"RTO\": { \"description\": \"Repeat To: sets the min/max value that REP stops at.\" },\r\n \"RMX\": { \"description\": \"Remix: repositions the phrase playhead (Y) on tracks to the left (selected by X).\" },\r\n \"NTH\": { \"description\": \"Nth Trigger: conditional trigger based on loop count.\" },\r\n \"PSL\": { \"description\": \"Pitch Slide (portamento): enables portamento for XX ticks.\" },\r\n \"PBN\": { \"description\": \"Pitch Bend: continuous pitch slide up (00-7F) or down (80-FF).\" },\r\n \"PVB\": { \"description\": \"Vibrato: X=speed, Y=depth.\" },\r\n \"PVX\": { \"description\": \"Extreme Vibrato: like PVB but with higher range.\" },\r\n \"SCA\": { \"description\": \"Track Scale: X=key signature, Y=scale number for this track.\" },\r\n \"SCG\": { \"description\": \"Global Scale: X=key, Y=scale number for the whole song.\" },\r\n \"SNG\": { \"description\": \"Song Hop: moves this track's song position by XX rows relative to current.\" },\r\n \"SED\": { \"description\": \"Random Seed: sets the random seed XX for this track.\" },\r\n \"TBL\": { \"description\": \"Table: assigns table number XX to the current instrument.\" },\r\n \"THO\": { \"description\": \"Table Hop: jumps all table columns to position 0X.\" },\r\n \"TIC\": { \"description\": \"Table Tick: sets the table tick rate. In a table, each FX column can run independently.\" },\r\n \"TBX\": { \"description\": \"Aux Table: runs table XX in parallel with the instrument table. 00=stop aux table.\" },\r\n \"TPO\": { \"description\": \"Tempo: sets song BPM to XX (hex → decimal conversion shown in help text).\" },\r\n \"TSP\": { \"description\": \"Global Transpose: transposes the entire song by XX semitones.\" },\r\n \"NXT\": { \"description\": \"Next Track Trigger: plays instrument XX on the next track using current note/velocity.\" },\r\n \"OFF\": { \"description\": \"Note Off: stops the playing instrument after XX ticks. Triggers ADSR release stage.\" },\r\n \"MTT\": { \"description\": \"Micro Time: adjusts row playback timing in sub-tick (1/8 tick) amounts.\" }\r\n },\r\n \"instrument\": {\r\n \"VOL\": { \"description\": \"Volume offset (relative).\" },\r\n \"PIT\": { \"description\": \"Pitch offset in semitones (relative).\" },\r\n \"FIN\": { \"description\": \"Fine tune: pitch offset -1 to +1 semitones (relative).\" },\r\n \"EA1\": { \"description\": \"Envelope 1 Amount offset.\" },\r\n \"EA2\": { \"description\": \"Envelope 2 Amount offset.\" },\r\n \"AT1\": { \"description\": \"Envelope 1 Attack time offset.\" },\r\n \"AT2\": { \"description\": \"Envelope 2 Attack time offset.\" },\r\n \"HO1\": { \"description\": \"Envelope 1 Hold time offset.\" },\r\n \"HO2\": { \"description\": \"Envelope 2 Hold time offset.\" },\r\n \"DE1\": { \"description\": \"Envelope 1 Decay time offset.\" },\r\n \"DE2\": { \"description\": \"Envelope 2 Decay time offset.\" },\r\n \"ET1\": { \"description\": \"Retrigger Envelope 1 (any value > 00 retriggers).\" },\r\n \"ET2\": { \"description\": \"Retrigger Envelope 2.\" },\r\n \"LA1\": { \"description\": \"LFO 1 Amount offset.\" },\r\n \"LA2\": { \"description\": \"LFO 2 Amount offset.\" },\r\n \"LF1\": { \"description\": \"LFO 1 Frequency offset.\" },\r\n \"LF2\": { \"description\": \"LFO 2 Frequency offset.\" },\r\n \"LT1\": { \"description\": \"Retrigger LFO 1 (value sets phase offset).\" },\r\n \"LT2\": { \"description\": \"Retrigger LFO 2.\" }\r\n },\r\n \"mixer\": {\r\n \"VMV\": { \"description\": \"Main Volume: sets the main song output volume.\" },\r\n \"VMX\": { \"description\": \"ModFX Volume.\" },\r\n \"VDE\": { \"description\": \"Delay Volume.\" },\r\n \"VRE\": { \"description\": \"Reverb Volume.\" },\r\n \"VT1\": { \"description\": \"Track 1 Volume.\" },\r\n \"VT2\": { \"description\": \"Track 2 Volume.\" },\r\n \"VT3\": { \"description\": \"Track 3 Volume.\" },\r\n \"VT4\": { \"description\": \"Track 4 Volume.\" },\r\n \"VT5\": { \"description\": \"Track 5 Volume.\" },\r\n \"VT6\": { \"description\": \"Track 6 Volume.\" },\r\n \"VT7\": { \"description\": \"Track 7 Volume.\" },\r\n \"VT8\": { \"description\": \"Track 8 Volume.\" },\r\n \"DJC\": { \"description\": \"DJ Filter Cutoff.\" },\r\n \"DJR\": { \"description\": \"DJ Filter Resonance.\" },\r\n \"DJT\": { \"description\": \"DJ Filter Type.\" },\r\n \"EQM\": { \"description\": \"Assign main mix EQ slot.\" },\r\n \"EQI\": { \"description\": \"Assign current instrument EQ slot.\" }\r\n }\r\n }\r\n}\r\n","/**\r\n * viewContext.ts\r\n *\r\n * Derives semantic meaning from raw M8State by mapping cursor position and\r\n * currentLine content to typed, labelled fields using the m8-view-context.json schema.\r\n *\r\n * The five grid views (song, chain, phrase, table, groove) are fully supported.\r\n * Parameter views (inst, mixer, project, …) return a minimal context with viewName only.\r\n */\r\n\r\nimport type { M8State } from './types'\r\nimport schema from './m8-view-context.json'\r\n\r\n// Public field type union \r\n\r\nexport type M8FieldType =\r\n | 'chainRef'\r\n | 'phraseRef'\r\n | 'note'\r\n | 'velocity'\r\n | 'instrumentRef'\r\n | 'fxCommand'\r\n | 'fxValue'\r\n | 'transpose'\r\n | 'ticks'\r\n | 'volume'\r\n | 'ppq'\r\n | 'instrumentName'\r\n | 'eqSlot'\r\n | 'rowIndex'\r\n\r\n// Schema shapes (mirror m8-view-context.json) \r\n\r\ninterface ColumnDef {\r\n x: number\r\n width: number\r\n key: string\r\n type: M8FieldType\r\n label: string\r\n description?: string\r\n meta?: Record<string, unknown>\r\n}\r\n\r\ninterface RowFieldDef {\r\n x: number\r\n width: number\r\n parse: 'hex' | 'decimal'\r\n type: M8FieldType\r\n key: string\r\n description?: string\r\n}\r\n\r\ninterface ViewDef {\r\n title: string\r\n type: 'grid' | 'parameter'\r\n description: string\r\n rowField?: RowFieldDef\r\n columns: ColumnDef[]\r\n}\r\n\r\n// Public result types \r\n\r\n/**\r\n * A single parsed field value extracted from the currentLine.\r\n */\r\nexport interface M8ParsedField {\r\n /** Column key as defined in the schema (e.g. 'fx1cmd', 'note', 'track3'). */\r\n key: string\r\n /** Human-readable label (e.g. 'FX1 Command', 'Note (N)'). */\r\n label: string\r\n /** Semantic type of this field. */\r\n type: M8FieldType\r\n /** Raw text extracted from currentLine (trimmed). */\r\n rawValue: string\r\n /**\r\n * Parsed integer (from hex) when the field holds a numeric value.\r\n * `null` for empty cells ('--', '---') and text-only types (note name, fxCommand).\r\n */\r\n hexValue: number | null\r\n /** True when the cell is empty/unused ('--', '---', '---00'). */\r\n isEmpty: boolean\r\n /** Extra view-specific metadata (e.g. { trackIndex: 2 } for song view track columns). */\r\n meta?: Record<string, unknown>\r\n}\r\n\r\n/**\r\n * All fields parsed from the current row (line at cursorPos.y).\r\n */\r\nexport interface M8ParsedRow {\r\n /** Row index (hex-parsed) derived from the leftmost chars of currentLine. null if not parseable. */\r\n rowIndex: number | null\r\n /** Schema key for the row index field (e.g. 'songRow', 'step', 'chainPos'). */\r\n rowKey: string\r\n /** Map of column key → parsed field for every column in this view. */\r\n fields: Record<string, M8ParsedField>\r\n}\r\n\r\n/**\r\n * The field currently under the cursor, plus row context.\r\n */\r\nexport interface M8ActiveField extends M8ParsedField {\r\n /** Repetition of the view name for convenience. */\r\n viewName: string\r\n /** Row index of the line containing this field (null if not parseable). */\r\n rowIndex: number | null\r\n}\r\n\r\n/**\r\n * Full semantic context for the current M8State.\r\n */\r\nexport interface M8SemanticContext {\r\n /** M8 view name (lowercased), e.g. 'song', 'phrase'. */\r\n viewName: string\r\n /** Human-readable view title from schema ('Song View', 'Phrase View', …). */\r\n viewTitle: string | null\r\n /** View description from the schema. */\r\n viewDescription: string | null\r\n /**\r\n * The numeric ID of the current view item, parsed from the screen title.\r\n * e.g. 'F2' from ' CHAIN F2*', '03' from ' PHRASE 03'.\r\n * null for views that have no item number (song, instrument pool).\r\n */\r\n viewId: string | null\r\n /** True when the title carries a '*' suffix, indicating unsaved changes. */\r\n isUnsaved: boolean\r\n /** Whether this view is a structured grid (song/chain/phrase/table/groove). */\r\n isGridView: boolean\r\n /** All fields on the line at cursorPos.y (null for non-grid views or missing line). */\r\n row: M8ParsedRow | null\r\n /** The specific field under the cursor (null when cursor is out of any column range). */\r\n activeField: M8ActiveField | null\r\n}\r\n\r\n// FX command lookup \r\n\r\ntype FxCategory = 'sequencer' | 'instrument' | 'mixer'\r\ntype FxCommandMap = Record<string, { description: string }>\r\n\r\nconst fxCommands = schema.fxCommands as Record<FxCategory, FxCommandMap>\r\n\r\n/**\r\n * Look up the description of a 3-character FX command name.\r\n * Returns undefined if the command is unknown.\r\n */\r\nexport function lookupFxCommand(cmd: string): { description: string } | undefined {\r\n const upper = cmd.toUpperCase()\r\n for (const cat of Object.values(fxCommands)) {\r\n if (upper in cat) return cat[upper]\r\n }\r\n return undefined\r\n}\r\n\r\n// Internal helpers \r\n\r\nconst EMPTY_PATTERNS = new Set(['--', '---', '---00', '----', '-'])\r\n\r\nfunction isEmptyRaw(raw: string): boolean {\r\n if (!raw) return true\r\n // Also count strings that are all dashes\r\n return EMPTY_PATTERNS.has(raw) || /^-+$/.test(raw)\r\n}\r\n\r\nfunction parseHex(raw: string): number | null {\r\n const trimmed = raw.trim()\r\n if (!trimmed || isEmptyRaw(trimmed)) return null\r\n const n = parseInt(trimmed, 16)\r\n return Number.isNaN(n) ? null : n\r\n}\r\n\r\nfunction extractFromLine(line: string, x: number, width: number): string {\r\n // Guard: x may exceed line length (line might be shorter than full 40-char row)\r\n if (x >= line.length) return ''\r\n return line.slice(x, Math.min(x + width, line.length))\r\n}\r\n\r\n/**\r\n * When a row is currently playing, the M8 prepends a single non-alphanumeric\r\n * indicator character (e.g. '<' or '>') to currentLine, shifting all data\r\n * positions right by 1. Strip it so column offsets remain consistent.\r\n * Returns the clean line and the number of stripped characters (0 or 1).\r\n */\r\n/**\r\n * Extracts the item ID and unsaved flag from a raw M8 screen title.\r\n * Titles follow the pattern ' VIEWNAME ID* ' where ID is 1–2 hex chars\r\n * and '*' is an optional unsaved-changes marker.\r\n * Returns { viewId: null, isUnsaved: false } for views without an item number.\r\n */\r\nfunction extractViewId(rawTitle: string | null): { viewId: string | null; isUnsaved: boolean } {\r\n if (!rawTitle) return { viewId: null, isUnsaved: false }\r\n const trimmed = rawTitle.trim()\r\n const isUnsaved = trimmed.endsWith('*')\r\n const withoutStar = isUnsaved ? trimmed.slice(0, -1).trimEnd() : trimmed\r\n const parts = withoutStar.split(/\\s+/)\r\n const last = parts[parts.length - 1] ?? ''\r\n // Accept 1–2 uppercase hex digits as a view ID\r\n const viewId = /^[0-9A-Fa-f]{1,2}$/.test(last) ? last.toUpperCase() : null\r\n return { viewId, isUnsaved }\r\n}\r\n\r\nfunction stripPlaybackIndicator(line: string): { line: string; offset: number } {\r\n if (line.length > 0 && /^[^a-zA-Z0-9 ]/.test(line[0])) {\r\n return { line: line.slice(1), offset: 1 }\r\n }\r\n return { line, offset: 0 }\r\n}\r\n\r\nfunction parseColumn(col: ColumnDef, line: string): M8ParsedField {\r\n const raw = extractFromLine(line, col.x, col.width).trim()\r\n const empty = isEmptyRaw(raw)\r\n\r\n // Numeric types we try to parse as hex\r\n const numericTypes: M8FieldType[] = [\r\n 'chainRef', 'phraseRef', 'velocity', 'instrumentRef',\r\n 'fxValue', 'transpose', 'ticks', 'volume', 'ppq', 'eqSlot', 'rowIndex',\r\n ]\r\n // Types that are decimal (not hex)\r\n const decimalTypes: M8FieldType[] = ['ppq']\r\n let hexValue: number | null = null\r\n if (!empty && numericTypes.includes(col.type)) {\r\n if (decimalTypes.includes(col.type)) {\r\n const n = parseInt(raw, 10)\r\n hexValue = Number.isNaN(n) ? null : n\r\n } else {\r\n hexValue = parseHex(raw)\r\n }\r\n }\r\n\r\n return {\r\n key: col.key,\r\n label: col.label,\r\n type: col.type,\r\n rawValue: raw,\r\n hexValue,\r\n isEmpty: empty,\r\n meta: col.meta,\r\n }\r\n}\r\n\r\nfunction parseRowIndex(line: string, rf: RowFieldDef): number | null {\r\n const raw = extractFromLine(line, rf.x, rf.width).trim()\r\n if (!raw) return null\r\n if (rf.parse === 'hex') return parseHex(raw)\r\n const n = parseInt(raw, 10)\r\n return Number.isNaN(n) ? null : n\r\n}\r\n\r\n/**\r\n * Find the column whose x range contains cursorX.\r\n * Falls back to the closest column within 1-character tolerance.\r\n */\r\nfunction findColumn(cols: ColumnDef[], cursorX: number): ColumnDef | null {\r\n // Exact range hit\r\n for (const col of cols) {\r\n if (cursorX >= col.x && cursorX < col.x + col.width) return col\r\n }\r\n // 1-char tolerance (cursor border may be 1 px off)\r\n let best: ColumnDef | null = null\r\n let bestDist = 2 // reject anything > 1 char away\r\n for (const col of cols) {\r\n const dist = Math.min(\r\n Math.abs(cursorX - col.x),\r\n Math.abs(cursorX - (col.x + col.width - 1)),\r\n )\r\n if (dist < bestDist) {\r\n bestDist = dist\r\n best = col\r\n }\r\n }\r\n return best\r\n}\r\n\r\n// Public API \r\n\r\n/**\r\n * Derives a full semantic context from the current M8State.\r\n *\r\n * @example\r\n * ```ts\r\n * const ctx = getSemanticContext(state)\r\n * if (ctx?.activeField?.type === 'chainRef') {\r\n * const track = ctx.activeField.meta?.trackIndex // 1–8\r\n * const chainNum = ctx.activeField.hexValue // 0–255 or null if empty\r\n * const songRow = ctx.row?.rowIndex\r\n * }\r\n * ```\r\n */\r\nexport function getSemanticContext(state: M8State): M8SemanticContext | null {\r\n const viewName = state.viewName\r\n if (!viewName) return null\r\n\r\n const viewDefs = schema.views as Record<string, ViewDef>\r\n const viewDef = viewDefs[viewName] ?? null\r\n\r\n const isGridView = viewDef?.type === 'grid'\r\n const viewTitle = viewDef?.title ?? null\r\n const viewDescription = viewDef?.description ?? null\r\n const { viewId, isUnsaved } = extractViewId(state.viewTitle)\r\n\r\n if (!isGridView || !viewDef) {\r\n return { viewName, viewTitle, viewDescription, viewId, isUnsaved, isGridView: false, row: null, activeField: null }\r\n }\r\n\r\n const rawLine = state.currentLine\r\n if (!rawLine) {\r\n return { viewName, viewTitle, viewDescription, viewId, isUnsaved, isGridView: true, row: null, activeField: null }\r\n }\r\n\r\n // Strip playback indicator prefix ('>' or '<') emitted when the row is playing.\r\n const { line, offset } = stripPlaybackIndicator(rawLine)\r\n const cursorX = state.cursorPos ? state.cursorPos.x - offset : 0\r\n\r\n // Parse row index\r\n const rowIndex = viewDef.rowField ? parseRowIndex(line, viewDef.rowField) : null\r\n\r\n // Parse every column defined for this view\r\n const fields: Record<string, M8ParsedField> = {}\r\n for (const col of viewDef.columns) {\r\n fields[col.key] = parseColumn(col, line)\r\n }\r\n\r\n const row: M8ParsedRow = {\r\n rowIndex,\r\n rowKey: viewDef.rowField?.key ?? 'row',\r\n fields,\r\n }\r\n\r\n // Determine active field from cursor X position\r\n let activeField: M8ActiveField | null = null\r\n if (state.cursorPos) {\r\n const col = findColumn(viewDef.columns, cursorX)\r\n if (col) {\r\n const field = fields[col.key]\r\n if (field) {\r\n activeField = { ...field, viewName, rowIndex }\r\n }\r\n }\r\n }\r\n\r\n return { viewName, viewTitle, viewDescription, viewId, isUnsaved, isGridView: true, row, activeField }\r\n}\r\n\r\n/**\r\n * Returns a short human-readable description of what the cursor is currently on.\r\n *\r\n * @example\r\n * \"Track 3 — Chain 0A — Song Row 02\"\r\n * \"Note A#4 — Step 7 (Phrase)\"\r\n * \"FX1 Command: KIL (Kill Note) — Step 0\"\r\n */\r\nexport function describeContext(ctx: M8SemanticContext): string {\r\n if (!ctx.activeField) return ctx.viewTitle ?? ctx.viewName\r\n\r\n const { activeField: f, row } = ctx\r\n const parts: string[] = []\r\n\r\n // Label + value\r\n const val = formatFieldValue(f)\r\n parts.push(`${f.label}: ${val}`)\r\n\r\n // FX command extra info\r\n if (f.type === 'fxCommand' && !f.isEmpty) {\r\n const info = lookupFxCommand(f.rawValue)\r\n if (info) parts.push(`(${info.description})`)\r\n }\r\n\r\n // FX value context: include sibling command if we're on a value column\r\n if (f.type === 'fxValue' && row) {\r\n const cmdKey = f.key.replace('val', 'cmd') // fx1val → fx1cmd, fx2val → fx2cmd …\r\n const cmdField = row.fields[cmdKey]\r\n if (cmdField && !cmdField.isEmpty) {\r\n const info = lookupFxCommand(cmdField.rawValue)\r\n const label = info ? `${cmdField.rawValue} (${info.description})` : cmdField.rawValue\r\n parts.push(`for ${label}`)\r\n }\r\n }\r\n\r\n // Track index for song view\r\n if (f.meta?.trackIndex != null) parts.push(`Track ${f.meta.trackIndex}`)\r\n\r\n // Row index\r\n if (row?.rowIndex != null) {\r\n const rowHex = row.rowIndex.toString(16).toUpperCase().padStart(2, '0')\r\n parts.push(`${ctx.viewTitle ?? ctx.viewName} row ${rowHex}`)\r\n }\r\n\r\n return parts.join(' — ')\r\n}\r\n\r\n/**\r\n * Formats a parsed field value as a human-readable string.\r\n */\r\nexport function formatFieldValue(field: M8ParsedField): string {\r\n if (field.isEmpty) return '(empty)'\r\n\r\n switch (field.type) {\r\n case 'note':\r\n if (field.rawValue === 'OFF') return 'Note Off'\r\n return `Note ${field.rawValue}`\r\n\r\n case 'transpose': {\r\n if (field.hexValue == null) return field.rawValue\r\n // Relative hex: 00=none, 01–7F=positive, 80–FF=negative (two's complement)\r\n if (field.hexValue === 0) return '±0 st'\r\n const signed = field.hexValue > 0x7f ? field.hexValue - 0x100 : field.hexValue\r\n return `${signed > 0 ? '+' : ''}${signed} st`\r\n }\r\n\r\n case 'velocity':\r\n if (field.hexValue == null) return field.rawValue\r\n return `${field.rawValue}h (${field.hexValue} / 127 max)`\r\n\r\n case 'chainRef':\r\n case 'phraseRef':\r\n case 'instrumentRef':\r\n return field.rawValue\r\n\r\n case 'fxCommand':\r\n return field.rawValue\r\n\r\n case 'fxValue':\r\n if (field.hexValue == null) return field.rawValue\r\n return `${field.rawValue}h (dec ${field.hexValue})`\r\n\r\n case 'ticks':\r\n if (field.rawValue === '00') return '00 (skip step)'\r\n if (field.hexValue == null) return field.rawValue\r\n return `${field.rawValue}h (${field.hexValue} ticks)`\r\n\r\n case 'volume':\r\n return field.rawValue\r\n\r\n default:\r\n return field.rawValue\r\n }\r\n}\r\n","// @ts-expect-error - post-me types are incomplete for the generic handshake signatures used here.\nimport { ChildHandshake, DebugMessenger, WindowMessenger } from 'post-me'\n// @ts-expect-error - post-me types are incomplete for the generic handshake signatures used here.\nimport type { Connection, LocalHandle, RemoteHandle } from 'post-me'\nimport type { M8ClientEvents, M8ClientMethods, M8HostEvents, M8HostMethods, M8KeyName, M8SdkConfig, M8State } from './types'\nimport { getSemanticContext, describeContext } from './viewContext'\nimport type { M8SemanticContext } from './viewContext'\n\nexport type { CursorPos, CursorRect, M8KeyName, M8State, RGB, SystemInfos } from './types'\nexport type { M8SemanticContext } from './viewContext'\n\nexport interface M8Client {\n readonly state: M8State\n readonly isConnected: boolean\n navigateToView(viewName: string): Promise<boolean>\n navigateTo(x: number, y: number): Promise<void>\n setValueToHex(targetHex: number): Promise<boolean>\n setValueToInt(targetInt: number): Promise<boolean>\n setNote(noteString: string): Promise<boolean>\n setValueToString(targetString: string, exact?: boolean, searchInCurrentLine?: boolean): Promise<boolean>\n browseFile(targetText: string, exact?: boolean): Promise<boolean>\n sendKeyPress(keys: M8KeyName[]): Promise<void>\n sendKeyDown(keys: M8KeyName[]): Promise<void>\n sendKeyUp(): Promise<void>\n getState(): M8State\n fetchState(): Promise<M8State>\n onStateChange(callback: (state: M8State) => void): () => void\n onViewChange(callback: (viewName: string | null, viewTitle: string | null) => void): () => void\n onCursorMove(callback: (pos: M8State['cursorPos'], rect: M8State['cursorRect'], selectionMode: boolean) => void): () => void\n onTextUpdate(callback: (textUnderCursor: string | null, currentLine: string | null) => void): () => void\n onKeyPress(callback: (keys: number) => void): () => void\n disconnect(): void\n /**\n * Derives semantic context from the current state: view, row, and the typed\n * field under the cursor. Works for the five grid views (song, chain, phrase,\n * table, groove). Returns null when no view is active.\n */\n getSemanticContext(): M8SemanticContext | null\n /**\n * Returns a short human-readable description of what the cursor is on,\n * e.g. \"Track 3 — Chain 0A — Song View row 02\".\n */\n describeContext(): string | null\n}\n\nconst getDefaultState = (): M8State => ({\n viewName: null,\n viewTitle: null,\n minimapKey: null,\n cursorPos: null,\n cursorRect: null,\n selectionMode: false,\n highlightColor: null,\n titleColor: null,\n backgroundColor: null,\n textUnderCursor: null,\n currentLine: null,\n deviceModel: null,\n fontMode: null,\n systemInfo: null,\n macroRunning: false,\n})\n\nclass M8ClientImpl implements M8Client {\n private connection: Connection<M8ClientMethods, M8HostEvents, M8HostMethods, M8ClientEvents> | null = null\n private remoteHandle: RemoteHandle<M8HostMethods, M8HostEvents> | null = null\n private localHandle: LocalHandle<M8ClientMethods, M8ClientEvents> | null = null\n private readonly stateCallbacks = new Set<(state: M8State) => void>()\n private readonly viewCallbacks = new Set<(viewName: string | null, viewTitle: string | null) => void>()\n private readonly cursorCallbacks = new Set<(pos: M8State['cursorPos'], rect: M8State['cursorRect'], selectionMode: boolean) => void>()\n private readonly textCallbacks = new Set<(textUnderCursor: string | null, currentLine: string | null) => void>()\n private readonly keyCallbacks = new Set<(keys: number) => void>()\n private _state: M8State = getDefaultState()\n private _isConnected = false\n private readonly config: M8SdkConfig\n\n constructor(config: M8SdkConfig = {}) {\n this.config = config\n }\n\n get state(): M8State {\n return this._state\n }\n\n get isConnected(): boolean {\n return this._isConnected\n }\n\n async connect(): Promise<void> {\n if (this.connection) {\n return\n }\n\n let messenger = new WindowMessenger({\n localWindow: window,\n remoteWindow: window.parent,\n remoteOrigin: '*',\n })\n\n if (this.config.debug) {\n messenger = DebugMessenger(messenger, (msg: string, ...args: unknown[]) => {\n console.log('[M8 SDK]', msg, ...args)\n })\n }\n\n const connection = await ChildHandshake<M8ClientMethods, M8HostEvents, M8HostMethods, M8ClientEvents>(messenger, {\n ping: async () => 'pong',\n })\n\n this.connection = connection\n this.remoteHandle = connection.remoteHandle()\n this.localHandle = connection.localHandle()\n this._isConnected = true\n\n this.remoteHandle.addEventListener('stateChanged', (state: M8State) => {\n this._state = state\n this.stateCallbacks.forEach((cb) => {\n cb(state)\n })\n })\n\n this.remoteHandle.addEventListener('viewChanged', ({ viewName, viewTitle }: { viewName: string | null; viewTitle: string | null }) => {\n this._state = { ...this._state, viewName, viewTitle }\n this.viewCallbacks.forEach((cb) => {\n cb(viewName, viewTitle)\n })\n })\n\n this.remoteHandle.addEventListener('cursorMoved', ({ pos, rect, selectionMode }: { pos: M8State['cursorPos']; rect: M8State['cursorRect']; selectionMode: boolean }) => {\n this._state = { ...this._state, cursorPos: pos, cursorRect: rect, selectionMode }\n this.cursorCallbacks.forEach((cb) => {\n cb(pos, rect, selectionMode)\n })\n })\n\n this.remoteHandle.addEventListener('textUpdated', ({ textUnderCursor, currentLine }: { textUnderCursor: string | null; currentLine: string | null }) => {\n this._state = { ...this._state, textUnderCursor, currentLine }\n this.textCallbacks.forEach((cb) => {\n cb(textUnderCursor, currentLine)\n })\n })\n\n this.remoteHandle.addEventListener('keyPressed', ({ keys }: { keys: number }) => {\n this.keyCallbacks.forEach((cb) => {\n cb(keys)\n })\n })\n\n await this.fetchState()\n this.localHandle.emit('ready', undefined)\n }\n\n async navigateToView(viewName: string): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('navigateToView', viewName)\n }\n\n async navigateTo(x: number, y: number): Promise<void> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('navigateTo', x, y)\n }\n\n async setValueToHex(targetHex: number): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('setValueToHex', targetHex)\n }\n\n async setValueToInt(targetInt: number): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('setValueToInt', targetInt)\n }\n\n async setNote(noteString: string): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('setNote', noteString)\n }\n\n async setValueToString(targetString: string, exact = true, searchInCurrentLine = false): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('setValueToString', targetString, exact, searchInCurrentLine)\n }\n\n async browseFile(targetText: string, exact = true): Promise<boolean> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('browseFile', targetText, exact)\n }\n\n async sendKeyPress(keys: M8KeyName[]): Promise<void> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('sendKeyPress', keys)\n }\n\n async sendKeyDown(keys: M8KeyName[]): Promise<void> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('sendKeyDown', keys)\n }\n\n async sendKeyUp(): Promise<void> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n return this.remoteHandle.call('sendKeyUp')\n }\n\n getState(): M8State {\n return this._state\n }\n\n async fetchState(): Promise<M8State> {\n if (!this.remoteHandle) throw new Error('M8 SDK client is not connected')\n const state = await this.remoteHandle.call('getState')\n this._state = state\n return state\n }\n\n onStateChange(callback: (state: M8State) => void): () => void {\n this.stateCallbacks.add(callback)\n return () => this.stateCallbacks.delete(callback)\n }\n\n onViewChange(callback: (viewName: string | null, viewTitle: string | null) => void): () => void {\n this.viewCallbacks.add(callback)\n return () => this.viewCallbacks.delete(callback)\n }\n\n onCursorMove(callback: (pos: M8State['cursorPos'], rect: M8State['cursorRect'], selectionMode: boolean) => void): () => void {\n this.cursorCallbacks.add(callback)\n return () => this.cursorCallbacks.delete(callback)\n }\n\n onTextUpdate(callback: (textUnderCursor: string | null, currentLine: string | null) => void): () => void {\n this.textCallbacks.add(callback)\n return () => this.textCallbacks.delete(callback)\n }\n\n onKeyPress(callback: (keys: number) => void): () => void {\n this.keyCallbacks.add(callback)\n return () => this.keyCallbacks.delete(callback)\n }\n\n disconnect(): void {\n this.connection?.close()\n this.connection = null\n this.remoteHandle = null\n this.localHandle = null\n this._isConnected = false\n this.stateCallbacks.clear()\n this.viewCallbacks.clear()\n this.cursorCallbacks.clear()\n this.textCallbacks.clear()\n this.keyCallbacks.clear()\n }\n\n getSemanticContext(): M8SemanticContext | null {\n return getSemanticContext(this._state)\n }\n\n describeContext(): string | null {\n const ctx = getSemanticContext(this._state)\n return ctx ? describeContext(ctx) : null\n }\n}\n\nexport async function createM8Client(config: M8SdkConfig = {}): Promise<M8Client> {\n const client = new M8ClientImpl(config)\n await client.connect()\n return client\n}\n\nexport function createM8ClientSync(config: M8SdkConfig = {}): { client: M8Client; connect: () => Promise<void> } {\n const client = new M8ClientImpl(config)\n return {\n client,\n connect: async () => {\n await client.connect()\n },\n }\n}\n\nexport default {\n createM8Client,\n createM8ClientSync,\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yam8d/m8-sdk",
3
- "version": "0.1.0",
4
- "description": "Client SDK for iframe applications that communicate with an M8 host.",
3
+ "version": "0.2.0",
4
+ "description": "Client SDK for iframe applications that communicate with yam8d M8 host.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",