@rndmjoker/proton-mcp 0.4.13 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +138 -21
  2. package/dist/browser/channel.d.ts +76 -0
  3. package/dist/browser/channel.js +162 -0
  4. package/dist/browser/channel.js.map +1 -0
  5. package/dist/browser/client.d.ts +50 -0
  6. package/dist/browser/client.js +284 -0
  7. package/dist/browser/client.js.map +1 -0
  8. package/dist/browser/connector.d.ts +15 -0
  9. package/dist/browser/connector.js +26 -0
  10. package/dist/browser/connector.js.map +1 -0
  11. package/dist/browser/host.d.ts +50 -0
  12. package/dist/browser/host.js +258 -0
  13. package/dist/browser/host.js.map +1 -0
  14. package/dist/browser/messages.d.ts +163 -0
  15. package/dist/browser/messages.js +338 -0
  16. package/dist/browser/messages.js.map +1 -0
  17. package/dist/browser/paths.d.ts +51 -0
  18. package/dist/browser/paths.js +92 -0
  19. package/dist/browser/paths.js.map +1 -0
  20. package/dist/browser/setup.d.ts +42 -0
  21. package/dist/browser/setup.js +170 -0
  22. package/dist/browser/setup.js.map +1 -0
  23. package/dist/filters/order.d.ts +66 -0
  24. package/dist/filters/order.js +108 -0
  25. package/dist/filters/order.js.map +1 -0
  26. package/dist/filters/sieve.d.ts +184 -0
  27. package/dist/filters/sieve.js +1312 -0
  28. package/dist/filters/sieve.js.map +1 -0
  29. package/dist/instances.d.ts +58 -0
  30. package/dist/instances.js +145 -0
  31. package/dist/instances.js.map +1 -0
  32. package/dist/mail/compose.d.ts +10 -0
  33. package/dist/mail/compose.js.map +1 -1
  34. package/dist/mail/record.d.ts +36 -0
  35. package/dist/mail/record.js +74 -0
  36. package/dist/mail/record.js.map +1 -0
  37. package/dist/permissions.d.ts +139 -0
  38. package/dist/permissions.js +355 -0
  39. package/dist/permissions.js.map +1 -0
  40. package/dist/server.js +330 -16
  41. package/dist/server.js.map +1 -1
  42. package/dist/session.d.ts +12 -0
  43. package/dist/session.js +23 -0
  44. package/dist/session.js.map +1 -1
  45. package/dist/settings.d.ts +81 -11
  46. package/dist/settings.js +160 -25
  47. package/dist/settings.js.map +1 -1
  48. package/dist/tools/confirm.d.ts +4 -2
  49. package/dist/tools/confirm.js +12 -3
  50. package/dist/tools/confirm.js.map +1 -1
  51. package/dist/tools/failures.d.ts +6 -8
  52. package/dist/tools/failures.js +36 -17
  53. package/dist/tools/failures.js.map +1 -1
  54. package/dist/tools/filter-tools.d.ts +82 -0
  55. package/dist/tools/filter-tools.js +729 -0
  56. package/dist/tools/filter-tools.js.map +1 -0
  57. package/dist/tools/filters.d.ts +8 -1
  58. package/dist/tools/filters.js +24 -12
  59. package/dist/tools/filters.js.map +1 -1
  60. package/dist/tools/format.d.ts +15 -0
  61. package/dist/tools/format.js +4 -3
  62. package/dist/tools/format.js.map +1 -1
  63. package/dist/tools/guidance.js +12 -7
  64. package/dist/tools/guidance.js.map +1 -1
  65. package/dist/tools/interface.d.ts +20 -6
  66. package/dist/tools/interface.js +40 -16
  67. package/dist/tools/interface.js.map +1 -1
  68. package/dist/tools/send.d.ts +9 -0
  69. package/dist/tools/send.js +51 -9
  70. package/dist/tools/send.js.map +1 -1
  71. package/dist/tools/sign-in-required.d.ts +15 -2
  72. package/dist/tools/sign-in-required.js +30 -2
  73. package/dist/tools/sign-in-required.js.map +1 -1
  74. package/dist/web/layout.d.ts +12 -5
  75. package/dist/web/layout.js +32 -9
  76. package/dist/web/layout.js.map +1 -1
  77. package/dist/web/pages.d.ts +4 -2
  78. package/dist/web/pages.js +10 -9
  79. package/dist/web/pages.js.map +1 -1
  80. package/dist/web/pending.d.ts +9 -6
  81. package/dist/web/pending.js +9 -7
  82. package/dist/web/pending.js.map +1 -1
  83. package/dist/web/preview-server.d.ts +33 -0
  84. package/dist/web/preview-server.js +102 -0
  85. package/dist/web/preview-server.js.map +1 -0
  86. package/dist/web/sections.d.ts +86 -1
  87. package/dist/web/sections.js +290 -7
  88. package/dist/web/sections.js.map +1 -1
  89. package/dist/web/security.d.ts +48 -13
  90. package/dist/web/security.js +68 -16
  91. package/dist/web/security.js.map +1 -1
  92. package/dist/web/server.d.ts +81 -24
  93. package/dist/web/server.js +478 -117
  94. package/dist/web/server.js.map +1 -1
  95. package/package.json +1 -1
@@ -0,0 +1,50 @@
1
+ /**
2
+ * This server's end of the browser channel (#59).
3
+ *
4
+ * One connection per request: filters are asked about now and then, and a
5
+ * connection held open would have to notice Chrome going away and coming back,
6
+ * which a fresh one does for free.
7
+ *
8
+ * When the extension cannot be reached, the answer says so plainly and names
9
+ * the cause wherever it can be found out: no setup, Chrome not running, the
10
+ * extension missing or switched off, a connector left over from before. Tobi
11
+ * asked for exactly that on 05.11.2026: "the extension is not active", and
12
+ * help with it, rather than an error code nobody can act on.
13
+ */
14
+ import { type BrowserRequest, type BrowserResponse } from './messages.js';
15
+ import { type BrowserPaths } from './paths.js';
16
+ /** The command that sets the connector up, as a user types it. */
17
+ export declare const SETUP_COMMAND = "npx -y @rndmjoker/proton-mcp@latest setup-browser";
18
+ export type Unavailable = 'platform' | 'not-set-up' | 'setup-broken' | 'browser-closed' | 'extension-not-connected' | 'connector-stale' | 'connector-outdated' | 'secret-mismatch' | 'unsafe-socket-dir' | 'no-answer';
19
+ /** The extension cannot be reached. The message says why, the help what to do. */
20
+ export declare class BrowserUnavailable extends Error {
21
+ readonly reason: Unavailable;
22
+ readonly help: string[];
23
+ constructor(reason: Unavailable, message: string, help: string[]);
24
+ }
25
+ /** Whether Chrome is running, or nothing when that cannot be told. */
26
+ export declare function chromeRunning(platform: BrowserPaths['platform']): boolean | undefined;
27
+ /**
28
+ * Why nothing answers on the socket, as far as it can be told from outside.
29
+ *
30
+ * Checked from the cause that needs the most work to the one that needs the
31
+ * least, so the answer starts where the user has to start.
32
+ */
33
+ export declare function diagnose(paths: BrowserPaths, running?: boolean | undefined): BrowserUnavailable;
34
+ /** Why a directory is not private enough for the socket, or nothing when it is or does not exist yet. */
35
+ export declare function unsafeDirectory(dir: string): string | undefined;
36
+ export interface AskOptions {
37
+ paths?: BrowserPaths;
38
+ /** How long to wait for the answer after the request went out. */
39
+ timeoutMs?: number;
40
+ /** Replaces the check for a running Chrome, for tests. */
41
+ chromeRunning?: () => boolean | undefined;
42
+ }
43
+ /**
44
+ * Sends one request to the extension and returns its answer.
45
+ *
46
+ * Throws BrowserUnavailable whenever the extension cannot be reached, with the
47
+ * cause and what helps. An answer from the extension that reports a problem,
48
+ * such as no Proton tab, is returned as an answer: the extension is there.
49
+ */
50
+ export declare function askBrowser(request: BrowserRequest, options?: AskOptions): Promise<BrowserResponse>;
@@ -0,0 +1,284 @@
1
+ /**
2
+ * This server's end of the browser channel (#59).
3
+ *
4
+ * One connection per request: filters are asked about now and then, and a
5
+ * connection held open would have to notice Chrome going away and coming back,
6
+ * which a fresh one does for free.
7
+ *
8
+ * When the extension cannot be reached, the answer says so plainly and names
9
+ * the cause wherever it can be found out: no setup, Chrome not running, the
10
+ * extension missing or switched off, a connector left over from before. Tobi
11
+ * asked for exactly that on 05.11.2026: "the extension is not active", and
12
+ * help with it, rather than an error code nobody can act on.
13
+ */
14
+ import { connect } from 'node:net';
15
+ import { existsSync, readFileSync, readdirSync, lstatSync } from 'node:fs';
16
+ import { dirname, win32 } from 'node:path';
17
+ import { execFileSync } from 'node:child_process';
18
+ import { randomUUID } from 'node:crypto';
19
+ import { PROTOCOL_VERSION, parseResponse } from './messages.js';
20
+ import { browserPaths, UnsupportedPlatform } from './paths.js';
21
+ import { LineReader, parseLine, newNonce, proof, proofMatches, isNonce, readSecret } from './channel.js';
22
+ /** The command that sets the connector up, as a user types it. */
23
+ export const SETUP_COMMAND = 'npx -y @rndmjoker/proton-mcp@latest setup-browser';
24
+ /** The extension cannot be reached. The message says why, the help what to do. */
25
+ export class BrowserUnavailable extends Error {
26
+ reason;
27
+ help;
28
+ constructor(reason, message, help) {
29
+ super(message);
30
+ this.reason = reason;
31
+ this.help = help;
32
+ }
33
+ }
34
+ const LOAD_EXTENSION = 'Load the extension in Chrome: open chrome://extensions, switch on Developer mode, choose ' +
35
+ '"Load unpacked" and pick the unpacked folder of the extension from the release.';
36
+ const RELOAD_EXTENSION = 'Open chrome://extensions, find "Proton MCP Helper" and click its reload arrow. Its popup ' +
37
+ 'shows what it reports about the connector.';
38
+ /** Whether Chrome is running, or nothing when that cannot be told. */
39
+ export function chromeRunning(platform) {
40
+ try {
41
+ if (platform === 'linux') {
42
+ for (const entry of readdirSync('/proc')) {
43
+ if (!/^\d+$/.test(entry))
44
+ continue;
45
+ try {
46
+ if (readFileSync(`/proc/${entry}/comm`, 'utf8').trim() === 'chrome')
47
+ return true;
48
+ }
49
+ catch {
50
+ // A process that ended while the list was read.
51
+ }
52
+ }
53
+ return false;
54
+ }
55
+ // Programs by their full path: a bare name is looked up in the current
56
+ // directory first on Windows, and a project the assistant works in could
57
+ // carry a tasklist.exe of its own. Found in the review of 06.11.2026.
58
+ if (platform === 'darwin') {
59
+ const list = execFileSync('/bin/ps', ['-axo', 'comm'], { encoding: 'utf8', timeout: 3000 });
60
+ return list.split('\n').some((line) => line.endsWith('/Google Chrome'));
61
+ }
62
+ const tasklist = win32.join(process.env.SystemRoot ?? 'C:\\Windows', 'System32', 'tasklist.exe');
63
+ const list = execFileSync(tasklist, ['/FI', 'IMAGENAME eq chrome.exe', '/NH'], {
64
+ encoding: 'utf8',
65
+ timeout: 3000,
66
+ windowsHide: true,
67
+ });
68
+ return /chrome\.exe/i.test(list);
69
+ }
70
+ catch {
71
+ return undefined;
72
+ }
73
+ }
74
+ /** The Node the launcher starts the connector with, read back from the launcher. */
75
+ function launcherNode(paths) {
76
+ try {
77
+ const text = readFileSync(paths.launcher, 'utf8');
78
+ const match = paths.platform === 'win32' ? /^"([^"]+)"/m.exec(text) : /^exec '((?:[^']|'\\'')+)'/m.exec(text);
79
+ return match?.[1]?.replace(/'\\''/g, "'");
80
+ }
81
+ catch {
82
+ return undefined;
83
+ }
84
+ }
85
+ /**
86
+ * Why nothing answers on the socket, as far as it can be told from outside.
87
+ *
88
+ * Checked from the cause that needs the most work to the one that needs the
89
+ * least, so the answer starts where the user has to start.
90
+ */
91
+ export function diagnose(paths, running = chromeRunning(paths.platform)) {
92
+ if (!existsSync(paths.secretFile) || !existsSync(paths.manifestFile) || !existsSync(paths.launcher)) {
93
+ return new BrowserUnavailable('not-set-up', 'The browser extension Proton MCP Helper is not active: its connector is not set up on this computer.', [
94
+ `Run this in a terminal: ${SETUP_COMMAND}`,
95
+ LOAD_EXTENSION,
96
+ 'Reload any open Proton tab once afterwards.',
97
+ ]);
98
+ }
99
+ const node = launcherNode(paths);
100
+ if (node && !existsSync(node)) {
101
+ return new BrowserUnavailable('setup-broken', `The browser extension Proton MCP Helper is not active: its connector was set up with a Node that no longer exists (${node}).`, [`Run the setup again in a terminal: ${SETUP_COMMAND}`, RELOAD_EXTENSION]);
102
+ }
103
+ if (running === false) {
104
+ return new BrowserUnavailable('browser-closed', 'The browser extension Proton MCP Helper is not active: Chrome is not running.', ['Start Chrome and open https://mail.proton.me, signed in to the account.']);
105
+ }
106
+ return new BrowserUnavailable('extension-not-connected', 'The browser extension Proton MCP Helper is not active: ' +
107
+ (running ? 'Chrome is running and the connector is set up, but ' : 'the connector is set up, but ') +
108
+ 'the extension has not started it. It is missing, switched off, or needs a reload.', [
109
+ RELOAD_EXTENSION,
110
+ 'If it is not listed there: ' + LOAD_EXTENSION,
111
+ ]);
112
+ }
113
+ /** Why a directory is not private enough for the socket, or nothing when it is or does not exist yet. */
114
+ export function unsafeDirectory(dir) {
115
+ let stat;
116
+ try {
117
+ stat = lstatSync(dir);
118
+ }
119
+ catch {
120
+ return undefined;
121
+ }
122
+ if (stat.isSymbolicLink() || !stat.isDirectory())
123
+ return `${dir} is not a plain directory.`;
124
+ const uid = process.getuid?.();
125
+ if (uid !== undefined && stat.uid !== uid)
126
+ return `${dir} belongs to another user.`;
127
+ if ((stat.mode & 0o077) !== 0)
128
+ return `${dir} can be opened by other users.`;
129
+ return undefined;
130
+ }
131
+ /** Waits for the next message on the socket, or fails when it closes or takes too long. */
132
+ class Conversation {
133
+ socket;
134
+ #queue = [];
135
+ #waiting = [];
136
+ #closed = false;
137
+ constructor(socket) {
138
+ this.socket = socket;
139
+ const reader = new LineReader();
140
+ socket.on('data', (chunk) => {
141
+ let lines;
142
+ try {
143
+ lines = reader.push(chunk);
144
+ }
145
+ catch {
146
+ socket.destroy();
147
+ return;
148
+ }
149
+ for (const line of lines)
150
+ this.#deliver(parseLine(line));
151
+ });
152
+ socket.on('close', () => {
153
+ this.#closed = true;
154
+ for (const waiter of this.#waiting.splice(0))
155
+ waiter(undefined);
156
+ });
157
+ socket.on('error', () => undefined);
158
+ }
159
+ #deliver(message) {
160
+ const waiter = this.#waiting.shift();
161
+ if (waiter)
162
+ waiter(message);
163
+ else
164
+ this.#queue.push(message);
165
+ }
166
+ next(timeoutMs) {
167
+ if (this.#queue.length > 0)
168
+ return Promise.resolve(this.#queue.shift());
169
+ if (this.#closed)
170
+ return Promise.resolve(undefined);
171
+ return new Promise((resolve) => {
172
+ const timer = setTimeout(() => {
173
+ const index = this.#waiting.indexOf(done);
174
+ if (index >= 0)
175
+ this.#waiting.splice(index, 1);
176
+ resolve('timeout');
177
+ }, timeoutMs);
178
+ const done = (message) => {
179
+ clearTimeout(timer);
180
+ resolve(message);
181
+ };
182
+ this.#waiting.push(done);
183
+ });
184
+ }
185
+ send(message) {
186
+ if (!this.socket.destroyed)
187
+ this.socket.write(`${JSON.stringify(message)}\n`);
188
+ }
189
+ }
190
+ function open(path) {
191
+ return new Promise((resolve, reject) => {
192
+ const socket = connect(path);
193
+ socket.once('connect', () => {
194
+ socket.removeAllListeners('error');
195
+ resolve(socket);
196
+ });
197
+ socket.once('error', reject);
198
+ });
199
+ }
200
+ /**
201
+ * Sends one request to the extension and returns its answer.
202
+ *
203
+ * Throws BrowserUnavailable whenever the extension cannot be reached, with the
204
+ * cause and what helps. An answer from the extension that reports a problem,
205
+ * such as no Proton tab, is returned as an answer: the extension is there.
206
+ */
207
+ export async function askBrowser(request, options = {}) {
208
+ let paths;
209
+ try {
210
+ paths = options.paths ?? browserPaths();
211
+ }
212
+ catch (error) {
213
+ if (error instanceof UnsupportedPlatform)
214
+ throw new BrowserUnavailable('platform', error.message, []);
215
+ throw error;
216
+ }
217
+ const running = options.chromeRunning ?? (() => chromeRunning(paths.platform));
218
+ const secret = readSecret(paths.secretFile);
219
+ if (!secret)
220
+ throw diagnose(paths, running());
221
+ // The connector refuses a socket directory somebody else owns or others can
222
+ // open; the server checks the same before it says anything there, so a name
223
+ // taken first in /tmp is named as the cause rather than as a wrong secret.
224
+ if (paths.platform !== 'win32') {
225
+ const unsafe = unsafeDirectory(dirname(paths.socket));
226
+ if (unsafe) {
227
+ throw new BrowserUnavailable('unsafe-socket-dir', `The browser extension Proton MCP Helper cannot be reached safely: ${unsafe}`, [
228
+ `Remove ${dirname(paths.socket)} if it is not yours, then reload the extension in chrome://extensions.`,
229
+ ]);
230
+ }
231
+ }
232
+ let socket;
233
+ try {
234
+ socket = await open(paths.socket);
235
+ }
236
+ catch (error) {
237
+ const code = error.code;
238
+ if (code === 'ECONNREFUSED' && paths.platform !== 'win32') {
239
+ throw new BrowserUnavailable('connector-stale', 'The browser extension Proton MCP Helper is not active: its connector stopped without ' +
240
+ 'closing its socket.', [RELOAD_EXTENSION, 'If that does not help, restart Chrome.']);
241
+ }
242
+ throw diagnose(paths, running());
243
+ }
244
+ const conversation = new Conversation(socket);
245
+ try {
246
+ const hello = await conversation.next(3000);
247
+ if (hello === 'timeout' || !hello || hello.type !== 'hello' || !isNonce(hello.nonce)) {
248
+ throw new BrowserUnavailable('connector-stale', 'The browser extension Proton MCP Helper is not active: something answers on its ' +
249
+ 'socket, but not the way its connector does.', [RELOAD_EXTENSION, `If that does not help, run the setup again: ${SETUP_COMMAND}`]);
250
+ }
251
+ if (hello.version !== PROTOCOL_VERSION) {
252
+ throw new BrowserUnavailable('connector-outdated', `The browser extension's connector speaks version ${String(hello.version)} of the channel and this server ` +
253
+ `version ${PROTOCOL_VERSION}, so they cannot work together.`, [`Run the setup again: ${SETUP_COMMAND}`, 'Update the extension to the release that matches this server.', RELOAD_EXTENSION]);
254
+ }
255
+ const mine = newNonce();
256
+ conversation.send({ type: 'auth', proof: proof(secret, 'client', hello.nonce), nonce: mine });
257
+ const ready = await conversation.next(3000);
258
+ if (ready === 'timeout' || !ready || ready.type !== 'ready' || !proofMatches(secret, 'host', mine, ready.proof)) {
259
+ throw new BrowserUnavailable('secret-mismatch', 'The browser extension is running, but its connector and this server do not share the same secret. ' +
260
+ 'That happens when the setup ran again after Chrome started the connector.', [RELOAD_EXTENSION, `If that does not help, run the setup again: ${SETUP_COMMAND}`]);
261
+ }
262
+ const id = randomUUID();
263
+ conversation.send({ type: 'request', id, body: request });
264
+ const timeoutMs = options.timeoutMs ?? 90_000;
265
+ for (;;) {
266
+ const message = await conversation.next(timeoutMs);
267
+ if (message === 'timeout' || message === undefined) {
268
+ throw new BrowserUnavailable('no-answer', 'The browser extension did not answer in time. It may still carry out the request, so look ' +
269
+ 'with list_filters before asking for it again.', ['Check that Chrome is not stuck.', RELOAD_EXTENSION]);
270
+ }
271
+ if (message.type !== 'response' || message.id !== id)
272
+ continue;
273
+ const body = parseResponse(message.body);
274
+ if (!body) {
275
+ return { ok: false, error: 'internal', message: 'The extension answered in a shape this server does not know.' };
276
+ }
277
+ return body;
278
+ }
279
+ }
280
+ finally {
281
+ socket.destroy();
282
+ }
283
+ }
284
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/browser/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The connector's entry point (#59): the file the launcher starts when Chrome
4
+ * asks for it on behalf of the Proton MCP Helper extension.
5
+ *
6
+ * It does one thing, start the connector, and decides nothing about whether it
7
+ * should. The first version had no file of its own: host.ts checked whether it
8
+ * was the program being started by comparing its own address with the path it
9
+ * was started under. On Tobi's machine /home is a link to /var/home, so the
10
+ * two were spellings of the same file that never compared equal, and the
11
+ * connector did nothing at all. Chrome showed "Native host has exited", and no
12
+ * test noticed, because the tests run the connector inside their own process.
13
+ * Measured on 06.11.2026.
14
+ */
15
+ export {};
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The connector's entry point (#59): the file the launcher starts when Chrome
4
+ * asks for it on behalf of the Proton MCP Helper extension.
5
+ *
6
+ * It does one thing, start the connector, and decides nothing about whether it
7
+ * should. The first version had no file of its own: host.ts checked whether it
8
+ * was the program being started by comparing its own address with the path it
9
+ * was started under. On Tobi's machine /home is a link to /var/home, so the
10
+ * two were spellings of the same file that never compared equal, and the
11
+ * connector did nothing at all. Chrome showed "Native host has exited", and no
12
+ * test noticed, because the tests run the connector inside their own process.
13
+ * Measured on 06.11.2026.
14
+ */
15
+ import { runHost } from './host.js';
16
+ import { browserPaths } from './paths.js';
17
+ const host = await runHost({
18
+ input: process.stdin,
19
+ output: process.stdout,
20
+ origin: process.argv[2],
21
+ paths: browserPaths(),
22
+ log: (line) => process.stderr.write(`proton-mcp connector: ${line}\n`),
23
+ });
24
+ await host.done;
25
+ process.exit(host.failure ? 1 : 0);
26
+ //# sourceMappingURL=connector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connector.js","sourceRoot":"","sources":["../../src/browser/connector.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC,KAAK;IACpB,MAAM,EAAE,OAAO,CAAC,MAAM;IACtB,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACvB,KAAK,EAAE,YAAY,EAAE;IACrB,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,IAAI,IAAI,CAAC;CACvE,CAAC,CAAA;AACF,MAAM,IAAI,CAAC,IAAI,CAAA;AACf,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The connector Chrome starts for the extension (#59), in Chrome's words a
3
+ * native messaging host.
4
+ *
5
+ * Chrome starts it when the extension asks for it, hands it the extension's
6
+ * origin as the first argument, and talks to it over standard input and
7
+ * output. Chrome starts it only for the extension named in its manifest, and
8
+ * only from that extension: a web page cannot reach it.
9
+ *
10
+ * The connector opens a socket file for this server and relays between the two.
11
+ * It holds nothing and decides nothing about filters. What it does decide is
12
+ * who gets through:
13
+ *
14
+ * - Chrome's origin has to be the extension's fixed id.
15
+ * - A connection on the socket has to prove it knows the secret from the
16
+ * setup before it may send anything, and the connector proves the same back.
17
+ * - Every request has to be one of the three kinds in messages.ts, in exactly
18
+ * that shape, and every answer from the extension as well.
19
+ *
20
+ * It stops when Chrome closes the channel, which happens when the extension
21
+ * is switched off, reloaded or removed, or when Chrome quits.
22
+ *
23
+ * The setup copies this file, with connector.ts, paths.ts, channel.ts and
24
+ * messages.ts, into the user's configuration directory, and connector.ts
25
+ * starts it with the Node the setup ran under. So it imports nothing but Node
26
+ * and those files.
27
+ */
28
+ import type { Readable, Writable } from 'node:stream';
29
+ import type { BrowserPaths } from './paths.js';
30
+ /** How long a request may wait for the extension. Filling in a confirmation is not waited for. */
31
+ export declare const REQUEST_TIMEOUT_MS = 60000;
32
+ export interface HostOptions {
33
+ /** What Chrome writes: the extension's messages. */
34
+ input: Readable;
35
+ /** What Chrome reads. */
36
+ output: Writable;
37
+ /** The first argument Chrome passes: the extension's origin. */
38
+ origin: string | undefined;
39
+ paths: BrowserPaths;
40
+ log?: (line: string) => void;
41
+ requestTimeoutMs?: number;
42
+ }
43
+ export interface RunningHost {
44
+ /** Settles once Chrome closed the channel and the socket is gone, or the connector gave up. */
45
+ done: Promise<void>;
46
+ /** The reason the connector gave up at start, if it did. */
47
+ failure?: string;
48
+ close(): Promise<void>;
49
+ }
50
+ export declare function runHost(options: HostOptions): Promise<RunningHost>;