electron-native-speech-backend-macos 0.1.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.
Binary file
@@ -0,0 +1,3 @@
1
+ import type { SpeechAvailability } from "electron-native-speech";
2
+ export declare function checkAvailability(): Promise<SpeechAvailability>;
3
+ //# sourceMappingURL=availability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability.d.ts","sourceRoot":"","sources":["../src/availability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAYhE,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAqCrE"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkAvailability = checkAvailability;
4
+ const helper_process_1 = require("./helper-process");
5
+ async function checkAvailability() {
6
+ if (process.platform !== "darwin") {
7
+ return {
8
+ available: false,
9
+ platform: process.platform,
10
+ reason: "electron-native-speech macOS backend requires macOS",
11
+ };
12
+ }
13
+ const helper = (0, helper_process_1.getHelperProcess)();
14
+ try {
15
+ await helper.start();
16
+ }
17
+ catch (err) {
18
+ return {
19
+ available: false,
20
+ platform: "darwin",
21
+ reason: err instanceof Error ? err.message : String(err),
22
+ };
23
+ }
24
+ try {
25
+ const raw = (await helper.send({ command: "checkAvailability" }, 5000));
26
+ return {
27
+ available: raw.available,
28
+ platform: raw.platform ?? "darwin",
29
+ mode: raw.mode,
30
+ reason: raw.reason,
31
+ details: raw.details,
32
+ };
33
+ }
34
+ catch {
35
+ return {
36
+ available: false,
37
+ platform: "darwin",
38
+ reason: "Failed to query SpeechHelper availability",
39
+ };
40
+ }
41
+ }
42
+ //# sourceMappingURL=availability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability.js","sourceRoot":"","sources":["../src/availability.ts"],"names":[],"mappings":";;AAYA,8CAqCC;AAhDD,qDAAmD;AAW5C,KAAK,UAAU,iBAAiB;IACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,MAAM,EAAE,qDAAqD;SAC9D,CAAA;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,iCAAgB,GAAE,CAAA;IAEjC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACzD,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,IAAI,CAAC,CAAyB,CAAA;QAC/F,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,QAAQ;YAClC,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,QAAQ;YAClB,MAAM,EAAE,2CAA2C;SACpD,CAAA;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { FileTranscriptionOptions, FileTranscriptionResult } from "electron-native-speech";
2
+ export declare function transcribeFile(options: FileTranscriptionOptions): Promise<FileTranscriptionResult>;
3
+ //# sourceMappingURL=file-transcriber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-transcriber.d.ts","sourceRoot":"","sources":["../src/file-transcriber.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AA0B/F,wBAAsB,cAAc,CAClC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,uBAAuB,CAAC,CAyClC"}
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.transcribeFile = transcribeFile;
37
+ const fs = __importStar(require("fs"));
38
+ const electron_native_speech_1 = require("electron-native-speech");
39
+ const helper_process_1 = require("./helper-process");
40
+ async function transcribeFile(options) {
41
+ const { filePath, locale } = options;
42
+ if (!filePath) {
43
+ throw new electron_native_speech_1.SpeechRecognitionError({ code: "unsupported-input", message: "filePath is required" });
44
+ }
45
+ if (!fs.existsSync(filePath)) {
46
+ throw new electron_native_speech_1.SpeechRecognitionError({
47
+ code: "unsupported-input",
48
+ message: `File not found: ${filePath}`,
49
+ });
50
+ }
51
+ const helper = (0, helper_process_1.getHelperProcess)();
52
+ await helper.start();
53
+ let raw;
54
+ try {
55
+ raw = await helper.send({ command: "transcribeFile", filePath, locale: locale ?? null },
56
+ // Large files can take a while — allow up to 5 minutes
57
+ 5 * 60 * 1000);
58
+ }
59
+ catch (err) {
60
+ if (isErrorResponse(err)) {
61
+ throw new electron_native_speech_1.SpeechRecognitionError({
62
+ code: err.code,
63
+ message: err.message,
64
+ details: err.details,
65
+ });
66
+ }
67
+ throw err;
68
+ }
69
+ const resp = raw;
70
+ return {
71
+ segments: resp.segments ?? [],
72
+ durationMs: resp.durationMs,
73
+ locale: resp.locale,
74
+ };
75
+ }
76
+ function isErrorResponse(v) {
77
+ return (typeof v === "object" && v !== null && "type" in v && v.type === "error");
78
+ }
79
+ //# sourceMappingURL=file-transcriber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-transcriber.js","sourceRoot":"","sources":["../src/file-transcriber.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,wCA2CC;AAtED,uCAAwB;AAExB,mEAA+D;AAC/D,qDAAmD;AAwB5C,KAAK,UAAU,cAAc,CAClC,OAAiC;IAEjC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IAEpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,+CAAsB,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAA;IAClG,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,+CAAsB,CAAC;YAC/B,IAAI,EAAE,mBAAmB;YACzB,OAAO,EAAE,mBAAmB,QAAQ,EAAE;SACvC,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,iCAAgB,GAAE,CAAA;IACjC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;IAEpB,IAAI,GAAY,CAAA;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CACrB,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,IAAI,IAAI,EAAE;QAC/D,uDAAuD;QACvD,CAAC,GAAG,EAAE,GAAG,IAAI,CACd,CAAA;IACH,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAI,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,+CAAsB,CAAC;gBAC/B,IAAI,EAAE,GAAG,CAAC,IAAa;gBACvB,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAA;QACJ,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;IAED,MAAM,IAAI,GAAG,GAA6B,CAAA;IAC1C,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;QAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAC,CAAU;IACjC,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,MAAM,IAAI,CAAC,IAAK,CAAmB,CAAC,IAAI,KAAK,OAAO,CAC5F,CAAA;AACH,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { EventEmitter } from "events";
2
+ export type HelperMessage = {
3
+ id: string;
4
+ type: "result";
5
+ [key: string]: unknown;
6
+ } | {
7
+ id: string;
8
+ type: "event";
9
+ event: string;
10
+ [key: string]: unknown;
11
+ } | {
12
+ id: string;
13
+ type: "error";
14
+ code: string;
15
+ message: string;
16
+ details?: unknown;
17
+ } | {
18
+ type: "ready";
19
+ } | {
20
+ type: "log";
21
+ level: "debug" | "info" | "warn" | "error";
22
+ message: string;
23
+ };
24
+ /**
25
+ * Manages a single persistent SpeechHelper process.
26
+ *
27
+ * The process starts once and handles all requests for the lifetime of the
28
+ * backend. This avoids per-call startup overhead (~200–400 ms cold start).
29
+ *
30
+ * Communication: newline-delimited JSON over stdin/stdout.
31
+ */
32
+ export declare class HelperProcess extends EventEmitter {
33
+ private proc;
34
+ private pending;
35
+ private buffer;
36
+ private _ready;
37
+ private _starting;
38
+ private _idCounter;
39
+ private get binaryPath();
40
+ /** Start the helper process. Idempotent — safe to call multiple times. */
41
+ start(): Promise<void>;
42
+ private handleMessage;
43
+ /**
44
+ * Send a command and wait for its response.
45
+ * @param timeoutMs Maximum wait time. Defaults to 60 s for file transcription.
46
+ */
47
+ send(command: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
48
+ /**
49
+ * Send a command that will produce streaming events rather than a single response.
50
+ * Returns the request ID so the caller can subscribe to `event:<id>` emissions.
51
+ */
52
+ sendStreaming(command: Record<string, unknown>): string;
53
+ /** Send a fire-and-forget control message (no response expected) */
54
+ sendControl(command: Record<string, unknown>): void;
55
+ dispose(): Promise<void>;
56
+ }
57
+ export declare function getHelperProcess(): HelperProcess;
58
+ export declare function disposeHelperProcess(): Promise<void>;
59
+ //# sourceMappingURL=helper-process.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper-process.d.ts","sourceRoot":"","sources":["../src/helper-process.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAErC,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GACtD;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GACpE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC/E;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAQhF;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,IAAI,CAA8C;IAC1D,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,UAAU,CAAI;IAEtB,OAAO,KAAK,UAAU,GAqBrB;IAED,0EAA0E;IAC1E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2EtB,OAAO,CAAC,aAAa;IAuCrB;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB5E;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAWvD,oEAAoE;IACpE,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB/B;AAKD,wBAAgB,gBAAgB,IAAI,aAAa,CAGhD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAK1D"}
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.HelperProcess = void 0;
37
+ exports.getHelperProcess = getHelperProcess;
38
+ exports.disposeHelperProcess = disposeHelperProcess;
39
+ const child_process_1 = require("child_process");
40
+ const path = __importStar(require("path"));
41
+ const fs = __importStar(require("fs"));
42
+ const events_1 = require("events");
43
+ /**
44
+ * Manages a single persistent SpeechHelper process.
45
+ *
46
+ * The process starts once and handles all requests for the lifetime of the
47
+ * backend. This avoids per-call startup overhead (~200–400 ms cold start).
48
+ *
49
+ * Communication: newline-delimited JSON over stdin/stdout.
50
+ */
51
+ class HelperProcess extends events_1.EventEmitter {
52
+ constructor() {
53
+ super(...arguments);
54
+ this.proc = null;
55
+ this.pending = new Map();
56
+ this.buffer = "";
57
+ this._ready = false;
58
+ this._starting = null;
59
+ this._idCounter = 0;
60
+ }
61
+ get binaryPath() {
62
+ // In development: packages/backend-macos/bin/SpeechHelper
63
+ // In packaged app: resources/SpeechHelper (set by electron-builder extraResources)
64
+ const candidates = [
65
+ // packaged Electron app (process.resourcesPath is injected by Electron)
66
+ process.resourcesPath
67
+ ? path.join(process.resourcesPath, "SpeechHelper")
68
+ : null,
69
+ // workspace development
70
+ path.join(__dirname, "..", "bin", "SpeechHelper"),
71
+ // running from dist/
72
+ path.join(__dirname, "..", "..", "bin", "SpeechHelper"),
73
+ ].filter(Boolean);
74
+ for (const p of candidates) {
75
+ if (fs.existsSync(p))
76
+ return p;
77
+ }
78
+ throw new Error(`SpeechHelper binary not found. Run: npm run build:swift (in packages/backend-macos)`);
79
+ }
80
+ /** Start the helper process. Idempotent — safe to call multiple times. */
81
+ start() {
82
+ if (this._ready)
83
+ return Promise.resolve();
84
+ if (this._starting)
85
+ return this._starting;
86
+ this._starting = new Promise((resolve, reject) => {
87
+ let binary;
88
+ try {
89
+ binary = this.binaryPath;
90
+ }
91
+ catch (err) {
92
+ reject(err);
93
+ return;
94
+ }
95
+ this.proc = (0, child_process_1.spawn)(binary, [], {
96
+ stdio: ["pipe", "pipe", "pipe"],
97
+ });
98
+ const readyTimeout = setTimeout(() => {
99
+ reject(new Error("SpeechHelper did not become ready within 5 seconds"));
100
+ }, 5000);
101
+ this.proc.stdout.setEncoding("utf8");
102
+ this.proc.stdout.on("data", (chunk) => {
103
+ this.buffer += chunk;
104
+ const lines = this.buffer.split("\n");
105
+ this.buffer = lines.pop() ?? "";
106
+ for (const line of lines) {
107
+ if (line.trim())
108
+ this.handleMessage(line);
109
+ }
110
+ });
111
+ this.proc.stderr.setEncoding("utf8");
112
+ this.proc.stderr.on("data", (chunk) => {
113
+ // Surface helper stderr as debug info only
114
+ for (const line of chunk.split("\n")) {
115
+ if (line.trim()) {
116
+ this.emit("log", { level: "debug", message: line.trim() });
117
+ }
118
+ }
119
+ });
120
+ this.proc.once("spawn", () => {
121
+ // Process spawned — wait for the ready message
122
+ });
123
+ this.proc.once("error", (err) => {
124
+ clearTimeout(readyTimeout);
125
+ this._starting = null;
126
+ reject(err);
127
+ });
128
+ this.proc.once("exit", (code, signal) => {
129
+ this._ready = false;
130
+ this._starting = null;
131
+ this.proc = null;
132
+ // Reject any pending requests
133
+ for (const [, req] of this.pending) {
134
+ clearTimeout(req.timeout);
135
+ req.reject(new Error(`SpeechHelper exited (code=${code}, signal=${signal})`));
136
+ }
137
+ this.pending.clear();
138
+ this.emit("exit", code, signal);
139
+ });
140
+ this.once("ready", () => {
141
+ clearTimeout(readyTimeout);
142
+ this._ready = true;
143
+ this._starting = null;
144
+ resolve();
145
+ });
146
+ });
147
+ return this._starting;
148
+ }
149
+ handleMessage(line) {
150
+ let msg;
151
+ try {
152
+ msg = JSON.parse(line);
153
+ }
154
+ catch {
155
+ return;
156
+ }
157
+ if (msg.type === "ready") {
158
+ this.emit("ready");
159
+ return;
160
+ }
161
+ if (msg.type === "log") {
162
+ this.emit("log", msg);
163
+ return;
164
+ }
165
+ // Event messages are emitted to subscribers (live session events)
166
+ if (msg.type === "event" && "id" in msg) {
167
+ this.emit(`event:${msg.id}`, msg);
168
+ return;
169
+ }
170
+ // Result or error for a pending request
171
+ if ("id" in msg && msg.id) {
172
+ const pending = this.pending.get(msg.id);
173
+ if (!pending)
174
+ return;
175
+ clearTimeout(pending.timeout);
176
+ this.pending.delete(msg.id);
177
+ if (msg.type === "error") {
178
+ pending.reject(msg);
179
+ }
180
+ else {
181
+ pending.resolve(msg);
182
+ }
183
+ }
184
+ }
185
+ /**
186
+ * Send a command and wait for its response.
187
+ * @param timeoutMs Maximum wait time. Defaults to 60 s for file transcription.
188
+ */
189
+ send(command, timeoutMs = 60000) {
190
+ return new Promise((resolve, reject) => {
191
+ if (!this._ready || !this.proc) {
192
+ reject(new Error("SpeechHelper is not running"));
193
+ return;
194
+ }
195
+ const id = String(++this._idCounter);
196
+ const payload = JSON.stringify({ ...command, id }) + "\n";
197
+ const timeout = setTimeout(() => {
198
+ this.pending.delete(id);
199
+ reject(new Error(`SpeechHelper command timed out after ${timeoutMs}ms`));
200
+ }, timeoutMs);
201
+ this.pending.set(id, { resolve, reject, timeout });
202
+ this.proc.stdin.write(payload);
203
+ });
204
+ }
205
+ /**
206
+ * Send a command that will produce streaming events rather than a single response.
207
+ * Returns the request ID so the caller can subscribe to `event:<id>` emissions.
208
+ */
209
+ sendStreaming(command) {
210
+ if (!this._ready || !this.proc) {
211
+ throw new Error("SpeechHelper is not running");
212
+ }
213
+ const id = String(++this._idCounter);
214
+ const payload = JSON.stringify({ ...command, id }) + "\n";
215
+ this.proc.stdin.write(payload);
216
+ return id;
217
+ }
218
+ /** Send a fire-and-forget control message (no response expected) */
219
+ sendControl(command) {
220
+ if (!this._ready || !this.proc)
221
+ return;
222
+ const payload = JSON.stringify(command) + "\n";
223
+ this.proc.stdin.write(payload);
224
+ }
225
+ async dispose() {
226
+ if (!this.proc)
227
+ return;
228
+ this.sendControl({ command: "shutdown" });
229
+ await new Promise((resolve) => {
230
+ const t = setTimeout(() => {
231
+ this.proc?.kill("SIGTERM");
232
+ resolve();
233
+ }, 2000);
234
+ this.proc?.once("exit", () => {
235
+ clearTimeout(t);
236
+ resolve();
237
+ });
238
+ });
239
+ this.proc = null;
240
+ this._ready = false;
241
+ }
242
+ }
243
+ exports.HelperProcess = HelperProcess;
244
+ // Singleton — one helper process for the lifetime of the main process
245
+ let _instance = null;
246
+ function getHelperProcess() {
247
+ if (!_instance)
248
+ _instance = new HelperProcess();
249
+ return _instance;
250
+ }
251
+ async function disposeHelperProcess() {
252
+ if (_instance) {
253
+ await _instance.dispose();
254
+ _instance = null;
255
+ }
256
+ }
257
+ //# sourceMappingURL=helper-process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper-process.js","sourceRoot":"","sources":["../src/helper-process.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { ISpeechBackend, SpeechAvailability, FileTranscriptionOptions, FileTranscriptionResult, SpeechSession } from "electron-native-speech";
2
+ import { checkAvailability } from "./availability";
3
+ import { transcribeFile } from "./file-transcriber";
4
+ import { MacOSLiveSpeechSession } from "./live-session";
5
+ import { disposeHelperProcess } from "./helper-process";
6
+ export declare class MacOSSpeechBackend implements ISpeechBackend {
7
+ checkAvailability(): Promise<SpeechAvailability>;
8
+ transcribeFile(options: FileTranscriptionOptions): Promise<FileTranscriptionResult>;
9
+ createSession(): Promise<SpeechSession>;
10
+ dispose(): Promise<void>;
11
+ }
12
+ export { checkAvailability, transcribeFile, MacOSLiveSpeechSession, disposeHelperProcess };
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACvB,aAAa,EACd,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAEvD,qBAAa,kBAAmB,YAAW,cAAc;IACjD,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAIhD,cAAc,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAInF,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;IAIvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B;AAGD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.disposeHelperProcess = exports.MacOSLiveSpeechSession = exports.transcribeFile = exports.checkAvailability = exports.MacOSSpeechBackend = void 0;
4
+ const availability_1 = require("./availability");
5
+ Object.defineProperty(exports, "checkAvailability", { enumerable: true, get: function () { return availability_1.checkAvailability; } });
6
+ const file_transcriber_1 = require("./file-transcriber");
7
+ Object.defineProperty(exports, "transcribeFile", { enumerable: true, get: function () { return file_transcriber_1.transcribeFile; } });
8
+ const live_session_1 = require("./live-session");
9
+ Object.defineProperty(exports, "MacOSLiveSpeechSession", { enumerable: true, get: function () { return live_session_1.MacOSLiveSpeechSession; } });
10
+ const helper_process_1 = require("./helper-process");
11
+ Object.defineProperty(exports, "disposeHelperProcess", { enumerable: true, get: function () { return helper_process_1.disposeHelperProcess; } });
12
+ class MacOSSpeechBackend {
13
+ async checkAvailability() {
14
+ return (0, availability_1.checkAvailability)();
15
+ }
16
+ async transcribeFile(options) {
17
+ return (0, file_transcriber_1.transcribeFile)(options);
18
+ }
19
+ async createSession() {
20
+ return new live_session_1.MacOSLiveSpeechSession();
21
+ }
22
+ async dispose() {
23
+ await (0, helper_process_1.disposeHelperProcess)();
24
+ }
25
+ }
26
+ exports.MacOSSpeechBackend = MacOSSpeechBackend;
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAOA,iDAAkD;AAwBzC,kGAxBA,gCAAiB,OAwBA;AAvB1B,yDAAmD;AAuBvB,+FAvBnB,iCAAc,OAuBmB;AAtB1C,iDAAuD;AAsBX,uGAtBnC,qCAAsB,OAsBmC;AArBlE,qDAAuD;AAqBa,qGArB3D,qCAAoB,OAqB2D;AAnBxF,MAAa,kBAAkB;IAC7B,KAAK,CAAC,iBAAiB;QACrB,OAAO,IAAA,gCAAiB,GAAE,CAAA;IAC5B,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAAiC;QACpD,OAAO,IAAA,iCAAc,EAAC,OAAO,CAAC,CAAA;IAChC,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,OAAO,IAAI,qCAAsB,EAAE,CAAA;IACrC,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAA,qCAAoB,GAAE,CAAA;IAC9B,CAAC;CACF;AAhBD,gDAgBC"}
@@ -0,0 +1,18 @@
1
+ import type { SpeechSession, SpeechSessionStartOptions, SpeechSessionState, LiveSpeechResult, SpeechError } from "electron-native-speech";
2
+ export declare class MacOSLiveSpeechSession implements SpeechSession {
3
+ private emitter;
4
+ private sessionId;
5
+ private unsubscribe;
6
+ private _state;
7
+ start(options?: SpeechSessionStartOptions): Promise<void>;
8
+ stop(): Promise<void>;
9
+ abort(): Promise<void>;
10
+ dispose(): Promise<void>;
11
+ on(event: "result", listener: (result: LiveSpeechResult) => void): () => void;
12
+ on(event: "error", listener: (error: SpeechError) => void): () => void;
13
+ on(event: "state", listener: (state: SpeechSessionState) => void): () => void;
14
+ private setState;
15
+ private cleanup;
16
+ private waitForStopped;
17
+ }
18
+ //# sourceMappingURL=live-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-session.d.ts","sourceRoot":"","sources":["../src/live-session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,yBAAyB,EACzB,kBAAkB,EAClB,gBAAgB,EAChB,WAAW,EACZ,MAAM,wBAAwB,CAAA;AAY/B,qBAAa,sBAAuB,YAAW,aAAa;IAC1D,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,MAAM,CAA6B;IAErC,KAAK,CAAC,OAAO,GAAE,yBAA8B,GAAG,OAAO,CAAC,IAAI,CAAC;IA2E7D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI;IAC7E,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IACtE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,GAAG,MAAM,IAAI;IAO7E,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,cAAc;CASvB"}
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MacOSLiveSpeechSession = void 0;
4
+ const events_1 = require("events");
5
+ const electron_native_speech_1 = require("electron-native-speech");
6
+ const helper_process_1 = require("./helper-process");
7
+ class MacOSLiveSpeechSession {
8
+ constructor() {
9
+ this.emitter = new events_1.EventEmitter();
10
+ this.sessionId = null;
11
+ this.unsubscribe = null;
12
+ this._state = "idle";
13
+ }
14
+ async start(options = {}) {
15
+ if (this._state !== "idle" && this._state !== "stopped") {
16
+ throw new electron_native_speech_1.SpeechRecognitionError({
17
+ code: "invalid-state",
18
+ message: `Cannot start session in state "${this._state}"`,
19
+ });
20
+ }
21
+ this.setState("starting");
22
+ const helper = (0, helper_process_1.getHelperProcess)();
23
+ await helper.start();
24
+ // Send the start command and get back a streaming session ID
25
+ const sessionId = helper.sendStreaming({
26
+ command: "startSession",
27
+ locale: options.locale ?? null,
28
+ interimResults: options.interimResults ?? true,
29
+ continuous: options.continuous ?? false,
30
+ });
31
+ this.sessionId = sessionId;
32
+ // Subscribe to events from the helper for this session
33
+ const onEvent = (msg) => {
34
+ switch (msg.event) {
35
+ case "result":
36
+ if (msg.result)
37
+ this.emitter.emit("result", msg.result);
38
+ break;
39
+ case "state":
40
+ if (msg.state)
41
+ this.setState(msg.state);
42
+ break;
43
+ case "error":
44
+ if (msg.error)
45
+ this.emitter.emit("error", msg.error);
46
+ break;
47
+ case "stopped":
48
+ this.setState("stopped");
49
+ this.cleanup();
50
+ break;
51
+ }
52
+ };
53
+ helper.on(`event:${sessionId}`, onEvent);
54
+ this.unsubscribe = () => helper.off(`event:${sessionId}`, onEvent);
55
+ // Wait for the "listening" state (or error)
56
+ await new Promise((resolve, reject) => {
57
+ const onState = (state) => {
58
+ if (state === "listening") {
59
+ this.emitter.off("state", onState);
60
+ this.emitter.off("error", onError);
61
+ resolve();
62
+ }
63
+ };
64
+ const onError = (err) => {
65
+ this.emitter.off("state", onState);
66
+ this.emitter.off("error", onError);
67
+ reject(new electron_native_speech_1.SpeechRecognitionError(err));
68
+ };
69
+ // Timeout safety
70
+ const t = setTimeout(() => {
71
+ this.emitter.off("state", onState);
72
+ this.emitter.off("error", onError);
73
+ reject(new electron_native_speech_1.SpeechRecognitionError({ code: "backend-failure", message: "Session start timed out" }));
74
+ }, 8000);
75
+ this.emitter.on("state", onState);
76
+ this.emitter.on("error", onError);
77
+ // Clear timeout on resolution
78
+ const origResolve = resolve;
79
+ resolve = () => { clearTimeout(t); origResolve(); };
80
+ });
81
+ }
82
+ async stop() {
83
+ if (!this.sessionId)
84
+ return;
85
+ if (this._state !== "listening" && this._state !== "starting")
86
+ return;
87
+ this.setState("stopping");
88
+ (0, helper_process_1.getHelperProcess)().sendControl({ command: "stopSession", sessionId: this.sessionId });
89
+ await this.waitForStopped();
90
+ }
91
+ async abort() {
92
+ if (!this.sessionId)
93
+ return;
94
+ (0, helper_process_1.getHelperProcess)().sendControl({ command: "abortSession", sessionId: this.sessionId });
95
+ this.setState("stopped");
96
+ this.cleanup();
97
+ }
98
+ async dispose() {
99
+ if (this._state === "listening" || this._state === "starting") {
100
+ await this.abort();
101
+ }
102
+ this.emitter.removeAllListeners();
103
+ this.cleanup();
104
+ }
105
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
106
+ on(event, listener) {
107
+ this.emitter.on(event, listener);
108
+ return () => this.emitter.off(event, listener);
109
+ }
110
+ setState(state) {
111
+ if (this._state === state)
112
+ return;
113
+ this._state = state;
114
+ this.emitter.emit("state", state);
115
+ }
116
+ cleanup() {
117
+ this.unsubscribe?.();
118
+ this.unsubscribe = null;
119
+ this.sessionId = null;
120
+ }
121
+ waitForStopped() {
122
+ if (this._state === "stopped")
123
+ return Promise.resolve();
124
+ return new Promise((resolve) => {
125
+ const off = this.on("state", (state) => {
126
+ if (state === "stopped" || state === "error") {
127
+ off();
128
+ resolve();
129
+ }
130
+ });
131
+ setTimeout(() => { off(); resolve(); }, 5000);
132
+ });
133
+ }
134
+ }
135
+ exports.MacOSLiveSpeechSession = MacOSLiveSpeechSession;
136
+ //# sourceMappingURL=live-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-session.js","sourceRoot":"","sources":["../src/live-session.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "electron-native-speech-backend-macos",
3
+ "version": "0.1.0",
4
+ "description": "macOS backend for electron-native-speech using Apple Speech framework",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist/",
9
+ "bin/"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc -p tsconfig.json",
13
+ "build:swift": "cd swift && swift build -c release --arch arm64 && swift build -c release --arch x86_64 && mkdir -p ../bin && lipo -create .build/arm64-apple-macosx/release/SpeechHelper .build/x86_64-apple-macosx/release/SpeechHelper -output ../bin/SpeechHelper",
14
+ "build:all": "npm run build:swift && npm run build",
15
+ "typecheck": "tsc -p tsconfig.json --noEmit",
16
+ "clean": "rm -rf dist bin"
17
+ },
18
+ "license": "MIT",
19
+ "devDependencies": {
20
+ "typescript": "^5.4.0"
21
+ },
22
+ "dependencies": {
23
+ "electron-native-speech": "*"
24
+ }
25
+ }