@elizaos/plugin-browser 2.0.0-beta.1 → 2.0.11-beta.7

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 (169) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -64
  3. package/dist/actions/browser-autofill-login.d.ts.map +1 -1
  4. package/dist/actions/browser-autofill-login.js.map +1 -1
  5. package/dist/actions/browser.d.ts +5 -6
  6. package/dist/actions/browser.d.ts.map +1 -1
  7. package/dist/actions/browser.js +54 -59
  8. package/dist/actions/browser.js.map +1 -1
  9. package/dist/actions/manage-browser-bridge.d.ts.map +1 -1
  10. package/dist/actions/manage-browser-bridge.js +10 -14
  11. package/dist/actions/manage-browser-bridge.js.map +1 -1
  12. package/dist/bridge-policy.d.ts +10 -0
  13. package/dist/bridge-policy.d.ts.map +1 -0
  14. package/dist/bridge-policy.js +37 -0
  15. package/dist/bridge-policy.js.map +1 -0
  16. package/dist/bridge-readiness.d.ts +16 -0
  17. package/dist/bridge-readiness.d.ts.map +1 -0
  18. package/dist/bridge-readiness.js +82 -0
  19. package/dist/bridge-readiness.js.map +1 -0
  20. package/dist/bridge-records.d.ts +9 -0
  21. package/dist/bridge-records.d.ts.map +1 -0
  22. package/dist/bridge-records.js +37 -0
  23. package/dist/bridge-records.js.map +1 -0
  24. package/dist/browser-capture-hooks.d.ts +9 -0
  25. package/dist/browser-capture-hooks.d.ts.map +1 -0
  26. package/dist/browser-capture-hooks.js +15 -0
  27. package/dist/browser-capture-hooks.js.map +1 -0
  28. package/dist/browser-service.d.ts +22 -4
  29. package/dist/browser-service.d.ts.map +1 -1
  30. package/dist/browser-service.js +63 -15
  31. package/dist/browser-service.js.map +1 -1
  32. package/dist/browser-workspace-hooks.d.ts +14 -0
  33. package/dist/browser-workspace-hooks.d.ts.map +1 -0
  34. package/dist/browser-workspace-hooks.js +15 -0
  35. package/dist/browser-workspace-hooks.js.map +1 -0
  36. package/dist/companion-auth.d.ts +34 -0
  37. package/dist/companion-auth.d.ts.map +1 -0
  38. package/dist/companion-auth.js +98 -0
  39. package/dist/companion-auth.js.map +1 -0
  40. package/dist/index.d.ts +9 -3
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +46 -11
  43. package/dist/index.js.map +1 -1
  44. package/dist/message-adapter.d.ts +9 -0
  45. package/dist/message-adapter.d.ts.map +1 -0
  46. package/dist/message-adapter.js +104 -0
  47. package/dist/message-adapter.js.map +1 -0
  48. package/dist/packaging.d.ts.map +1 -1
  49. package/dist/packaging.js +2 -0
  50. package/dist/packaging.js.map +1 -1
  51. package/dist/password-manager-bridge.d.ts +50 -0
  52. package/dist/password-manager-bridge.d.ts.map +1 -0
  53. package/dist/password-manager-bridge.js +437 -0
  54. package/dist/password-manager-bridge.js.map +1 -0
  55. package/dist/plugin.d.ts.map +1 -1
  56. package/dist/plugin.js +8 -4
  57. package/dist/plugin.js.map +1 -1
  58. package/dist/providers/workspace.d.ts +1 -1
  59. package/dist/providers/workspace.js.map +1 -1
  60. package/dist/routes/bridge.d.ts.map +1 -1
  61. package/dist/routes/bridge.js +63 -14
  62. package/dist/routes/bridge.js.map +1 -1
  63. package/dist/routes/workspace-setup.d.ts.map +1 -1
  64. package/dist/routes/workspace-setup.js +1 -1
  65. package/dist/routes/workspace-setup.js.map +1 -1
  66. package/dist/routes/workspace.d.ts +1 -2
  67. package/dist/routes/workspace.d.ts.map +1 -1
  68. package/dist/routes/workspace.js +63 -3
  69. package/dist/routes/workspace.js.map +1 -1
  70. package/dist/schema.d.ts +2 -2
  71. package/dist/schema.js.map +1 -1
  72. package/dist/service.d.ts +1 -1
  73. package/dist/service.d.ts.map +1 -1
  74. package/dist/service.js.map +1 -1
  75. package/dist/targets/bridge-target.d.ts +1 -1
  76. package/dist/targets/bridge-target.d.ts.map +1 -1
  77. package/dist/targets/bridge-target.js.map +1 -1
  78. package/dist/targets/stagehand-target.d.ts +3 -0
  79. package/dist/targets/stagehand-target.d.ts.map +1 -0
  80. package/dist/targets/stagehand-target.js +187 -0
  81. package/dist/targets/stagehand-target.js.map +1 -0
  82. package/dist/workspace/browser-capture.d.ts +1 -1
  83. package/dist/workspace/browser-capture.js.map +1 -1
  84. package/dist/workspace/browser-workspace-desktop.d.ts +1 -1
  85. package/dist/workspace/browser-workspace-desktop.d.ts.map +1 -1
  86. package/dist/workspace/browser-workspace-desktop.js +47 -25
  87. package/dist/workspace/browser-workspace-desktop.js.map +1 -1
  88. package/dist/workspace/browser-workspace-forms.d.ts.map +1 -1
  89. package/dist/workspace/browser-workspace-forms.js +1 -1
  90. package/dist/workspace/browser-workspace-forms.js.map +1 -1
  91. package/dist/workspace/browser-workspace-helpers.d.ts +7 -0
  92. package/dist/workspace/browser-workspace-helpers.d.ts.map +1 -1
  93. package/dist/workspace/browser-workspace-helpers.js +37 -0
  94. package/dist/workspace/browser-workspace-helpers.js.map +1 -1
  95. package/dist/workspace/browser-workspace-network.d.ts +1 -1
  96. package/dist/workspace/browser-workspace-network.d.ts.map +1 -1
  97. package/dist/workspace/browser-workspace-types.d.ts +15 -0
  98. package/dist/workspace/browser-workspace-types.d.ts.map +1 -1
  99. package/dist/workspace/browser-workspace-types.js.map +1 -1
  100. package/dist/workspace/browser-workspace-web.d.ts.map +1 -1
  101. package/dist/workspace/browser-workspace-web.js +15 -88
  102. package/dist/workspace/browser-workspace-web.js.map +1 -1
  103. package/dist/workspace/browser-workspace.d.ts +1 -1
  104. package/dist/workspace/browser-workspace.d.ts.map +1 -1
  105. package/dist/workspace/browser-workspace.js +9 -4
  106. package/dist/workspace/browser-workspace.js.map +1 -1
  107. package/package.json +28 -7
  108. package/dist/actions/browser-autofill-login.d.js +0 -1
  109. package/dist/actions/browser-autofill-login.d.js.map +0 -1
  110. package/dist/actions/browser.d.js +0 -1
  111. package/dist/actions/browser.d.js.map +0 -1
  112. package/dist/actions/manage-browser-bridge.d.js +0 -1
  113. package/dist/actions/manage-browser-bridge.d.js.map +0 -1
  114. package/dist/ambient-jsdom.d.js +0 -1
  115. package/dist/ambient-jsdom.d.js.map +0 -1
  116. package/dist/browser-service.d.js +0 -1
  117. package/dist/browser-service.d.js.map +0 -1
  118. package/dist/contracts.d.js +0 -1
  119. package/dist/contracts.d.js.map +0 -1
  120. package/dist/index.d.js +0 -21
  121. package/dist/index.d.js.map +0 -1
  122. package/dist/lifeops-session-contracts.d.js +0 -1
  123. package/dist/lifeops-session-contracts.d.js.map +0 -1
  124. package/dist/packaging.d.js +0 -1
  125. package/dist/packaging.d.js.map +0 -1
  126. package/dist/plugin.d.js +0 -1
  127. package/dist/plugin.d.js.map +0 -1
  128. package/dist/providers/workspace.d.js +0 -1
  129. package/dist/providers/workspace.d.js.map +0 -1
  130. package/dist/routes/bridge.d.js +0 -1
  131. package/dist/routes/bridge.d.js.map +0 -1
  132. package/dist/routes/workspace-account-gate.d.js +0 -1
  133. package/dist/routes/workspace-account-gate.d.js.map +0 -1
  134. package/dist/routes/workspace-setup.d.js +0 -1
  135. package/dist/routes/workspace-setup.d.js.map +0 -1
  136. package/dist/routes/workspace.d.js +0 -1
  137. package/dist/routes/workspace.d.js.map +0 -1
  138. package/dist/schema.d.js +0 -1
  139. package/dist/schema.d.js.map +0 -1
  140. package/dist/service.d.js +0 -1
  141. package/dist/service.d.js.map +0 -1
  142. package/dist/targets/bridge-target.d.js +0 -1
  143. package/dist/targets/bridge-target.d.js.map +0 -1
  144. package/dist/workspace/browser-capture.d.js +0 -1
  145. package/dist/workspace/browser-capture.d.js.map +0 -1
  146. package/dist/workspace/browser-workspace-desktop.d.js +0 -1
  147. package/dist/workspace/browser-workspace-desktop.d.js.map +0 -1
  148. package/dist/workspace/browser-workspace-elements.d.js +0 -1
  149. package/dist/workspace/browser-workspace-elements.d.js.map +0 -1
  150. package/dist/workspace/browser-workspace-forms.d.js +0 -1
  151. package/dist/workspace/browser-workspace-forms.d.js.map +0 -1
  152. package/dist/workspace/browser-workspace-helpers.d.js +0 -1
  153. package/dist/workspace/browser-workspace-helpers.d.js.map +0 -1
  154. package/dist/workspace/browser-workspace-jsdom.d.js +0 -1
  155. package/dist/workspace/browser-workspace-jsdom.d.js.map +0 -1
  156. package/dist/workspace/browser-workspace-network.d.js +0 -1
  157. package/dist/workspace/browser-workspace-network.d.js.map +0 -1
  158. package/dist/workspace/browser-workspace-snapshots.d.js +0 -1
  159. package/dist/workspace/browser-workspace-snapshots.d.js.map +0 -1
  160. package/dist/workspace/browser-workspace-state.d.js +0 -1
  161. package/dist/workspace/browser-workspace-state.d.js.map +0 -1
  162. package/dist/workspace/browser-workspace-types.d.js +0 -1
  163. package/dist/workspace/browser-workspace-types.d.js.map +0 -1
  164. package/dist/workspace/browser-workspace-web.d.js +0 -1
  165. package/dist/workspace/browser-workspace-web.d.js.map +0 -1
  166. package/dist/workspace/browser-workspace.d.js +0 -11
  167. package/dist/workspace/browser-workspace.d.js.map +0 -1
  168. package/dist/workspace/index.d.js +0 -3
  169. package/dist/workspace/index.d.js.map +0 -1
@@ -0,0 +1,437 @@
1
+ import { execFile, spawn } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { logger } from "@elizaos/core";
4
+ const execFileAsync = promisify(execFile);
5
+ class PasswordManagerError extends Error {
6
+ backend;
7
+ cause;
8
+ constructor(message, backend, cause) {
9
+ super(message);
10
+ this.name = "PasswordManagerError";
11
+ this.backend = backend;
12
+ this.cause = cause;
13
+ }
14
+ }
15
+ const CLIPBOARD_TTL_SECONDS = 30;
16
+ const PASSWORD_MANAGER_FIXTURE_ITEMS = [
17
+ {
18
+ id: "pm-github",
19
+ title: "GitHub",
20
+ url: "https://github.com/login",
21
+ username: "benchmark-user",
22
+ hasPassword: true,
23
+ tags: ["dev", "github", "code"],
24
+ metadata: { vault: "Mocked Benchmark" }
25
+ },
26
+ {
27
+ id: "pm-google-workspace",
28
+ title: "Google Workspace",
29
+ url: "https://mail.google.com",
30
+ username: "owner@example.com",
31
+ hasPassword: true,
32
+ tags: ["google", "email"],
33
+ metadata: { vault: "Mocked Benchmark" }
34
+ },
35
+ {
36
+ id: "pm-aws-prod",
37
+ title: "AWS Console",
38
+ url: "https://signin.aws.amazon.com",
39
+ username: "infra@example.com",
40
+ hasPassword: true,
41
+ tags: ["aws", "cloud"],
42
+ metadata: { vault: "Mocked Benchmark" }
43
+ }
44
+ ];
45
+ function isTruthyEnv(value) {
46
+ if (!value) return false;
47
+ const normalized = value.trim().toLowerCase();
48
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on" || normalized === "fixture";
49
+ }
50
+ function isFalsyEnv(value) {
51
+ if (!value) return false;
52
+ const normalized = value.trim().toLowerCase();
53
+ return normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off";
54
+ }
55
+ function isFixturePasswordManagerEnabled() {
56
+ const explicit = process.env.ELIZA_TEST_PASSWORD_MANAGER_BACKEND;
57
+ if (isFalsyEnv(explicit)) return false;
58
+ if (isTruthyEnv(explicit)) return true;
59
+ return false;
60
+ }
61
+ function listItemsViaFixture() {
62
+ return PASSWORD_MANAGER_FIXTURE_ITEMS.map((item) => ({
63
+ ...item,
64
+ tags: item.tags ? [...item.tags] : void 0,
65
+ metadata: item.metadata ? { ...item.metadata } : void 0
66
+ }));
67
+ }
68
+ const detectionCache = /* @__PURE__ */ new Map();
69
+ function cacheKey(config) {
70
+ const c = config ?? {};
71
+ return [
72
+ c.preferredBackend ?? "",
73
+ c.onePasswordAccount ?? "",
74
+ c.opPath ?? "",
75
+ c.protonPassPath ?? ""
76
+ ].join("|");
77
+ }
78
+ function resolveOpBinary(config) {
79
+ return config?.opPath?.trim() || "op";
80
+ }
81
+ function resolveProtonPassBinary(config) {
82
+ return config?.protonPassPath?.trim() || "protonpass";
83
+ }
84
+ async function probeBinary(binary, args) {
85
+ try {
86
+ await execFileAsync(binary, args, { timeout: 3e3 });
87
+ return true;
88
+ } catch {
89
+ return false;
90
+ }
91
+ }
92
+ async function probeOp(config) {
93
+ return probeBinary(resolveOpBinary(config), ["--version"]);
94
+ }
95
+ async function probeProtonPass(config) {
96
+ if (await probeBinary(resolveProtonPassBinary(config), ["--version"])) {
97
+ return true;
98
+ }
99
+ if (!config?.protonPassPath) {
100
+ return probeBinary("pass", ["--version"]);
101
+ }
102
+ return false;
103
+ }
104
+ async function detectPasswordManagerBackend(config) {
105
+ const key = cacheKey(config);
106
+ const cached = detectionCache.get(key);
107
+ if (cached !== void 0) return cached;
108
+ const preferred = config?.preferredBackend;
109
+ if (preferred === "none") {
110
+ detectionCache.set(key, "none");
111
+ return "none";
112
+ }
113
+ if (preferred === "fixture") {
114
+ detectionCache.set(key, "fixture");
115
+ return "fixture";
116
+ }
117
+ if (isFixturePasswordManagerEnabled()) {
118
+ detectionCache.set(key, "fixture");
119
+ return "fixture";
120
+ }
121
+ if (preferred === "1password") {
122
+ const ok = await probeOp(config);
123
+ const result = ok ? "1password" : "none";
124
+ detectionCache.set(key, result);
125
+ return result;
126
+ }
127
+ if (preferred === "protonpass") {
128
+ const ok = await probeProtonPass(config);
129
+ const result = ok ? "protonpass" : "none";
130
+ detectionCache.set(key, result);
131
+ return result;
132
+ }
133
+ if (await probeOp(config)) {
134
+ detectionCache.set(key, "1password");
135
+ return "1password";
136
+ }
137
+ if (await probeProtonPass(config)) {
138
+ detectionCache.set(key, "protonpass");
139
+ return "protonpass";
140
+ }
141
+ detectionCache.set(key, "none");
142
+ return "none";
143
+ }
144
+ function clearPasswordManagerBackendCache() {
145
+ detectionCache.clear();
146
+ }
147
+ function opBaseArgs(config) {
148
+ const args = [];
149
+ const account = config?.onePasswordAccount?.trim();
150
+ if (account) args.push("--account", account);
151
+ return args;
152
+ }
153
+ async function runOp(args, config) {
154
+ const binary = resolveOpBinary(config);
155
+ const fullArgs = [...opBaseArgs(config), ...args];
156
+ try {
157
+ const { stdout } = await execFileAsync(binary, fullArgs, {
158
+ timeout: 15e3,
159
+ maxBuffer: 16 * 1024 * 1024
160
+ });
161
+ return stdout;
162
+ } catch (error) {
163
+ throw new PasswordManagerError(
164
+ `1Password CLI failed for "${args[0] ?? ""}": ${error instanceof Error ? error.message : String(error)}`,
165
+ "1password",
166
+ error
167
+ );
168
+ }
169
+ }
170
+ function normalizeOpListEntry(raw) {
171
+ const id = raw.id ?? "";
172
+ if (!id) {
173
+ throw new PasswordManagerError("1Password item missing id", "1password");
174
+ }
175
+ const primaryUrl = raw.urls?.find((u) => u.primary)?.href ?? raw.urls?.[0]?.href;
176
+ return {
177
+ id,
178
+ title: raw.title ?? id,
179
+ url: primaryUrl,
180
+ username: raw.additional_information,
181
+ hasPassword: (raw.category ?? "").toUpperCase() === "LOGIN",
182
+ tags: raw.tags,
183
+ metadata: {
184
+ category: raw.category,
185
+ vault: raw.vault?.name
186
+ }
187
+ };
188
+ }
189
+ async function listItemsVia1Password(config) {
190
+ const stdout = await runOp(["item", "list", "--format", "json"], config);
191
+ const trimmed = stdout.trim();
192
+ if (!trimmed) return [];
193
+ let parsed;
194
+ try {
195
+ parsed = JSON.parse(trimmed);
196
+ } catch (error) {
197
+ throw new PasswordManagerError(
198
+ "1Password returned invalid JSON from item list",
199
+ "1password",
200
+ error
201
+ );
202
+ }
203
+ if (!Array.isArray(parsed)) {
204
+ throw new PasswordManagerError(
205
+ "1Password item list was not an array",
206
+ "1password"
207
+ );
208
+ }
209
+ return parsed.map(normalizeOpListEntry);
210
+ }
211
+ function matchesQuery(item, q) {
212
+ if (!q) return true;
213
+ const needle = q.toLowerCase();
214
+ if (item.title.toLowerCase().includes(needle)) return true;
215
+ if (item.url?.toLowerCase().includes(needle)) return true;
216
+ if (item.username?.toLowerCase().includes(needle)) return true;
217
+ if (item.tags?.some((t) => t.toLowerCase().includes(needle))) return true;
218
+ return false;
219
+ }
220
+ async function listItemsViaProtonPass(config) {
221
+ const binary = resolveProtonPassBinary(config);
222
+ let stdout;
223
+ try {
224
+ const result = await execFileAsync(binary, ["list"], {
225
+ timeout: 1e4,
226
+ maxBuffer: 8 * 1024 * 1024
227
+ });
228
+ stdout = result.stdout;
229
+ } catch (error) {
230
+ if (!config?.protonPassPath) {
231
+ try {
232
+ const result = await execFileAsync("pass", ["ls"], {
233
+ timeout: 1e4,
234
+ maxBuffer: 8 * 1024 * 1024
235
+ });
236
+ stdout = result.stdout;
237
+ } catch (inner) {
238
+ throw new PasswordManagerError(
239
+ `ProtonPass/pass list failed: ${inner instanceof Error ? inner.message : String(inner)}`,
240
+ "protonpass",
241
+ inner
242
+ );
243
+ }
244
+ } else {
245
+ throw new PasswordManagerError(
246
+ `ProtonPass list failed: ${error instanceof Error ? error.message : String(error)}`,
247
+ "protonpass",
248
+ error
249
+ );
250
+ }
251
+ }
252
+ const items = [];
253
+ for (const rawLine of stdout.split("\n")) {
254
+ const line = rawLine.replace(/[│├└─]+/g, "").replace(/\u00a0/g, " ").trim();
255
+ if (!line) continue;
256
+ if (line.toLowerCase().startsWith("password store")) continue;
257
+ items.push({
258
+ id: line,
259
+ title: line,
260
+ hasPassword: true
261
+ });
262
+ }
263
+ return items;
264
+ }
265
+ function clipboardCommand() {
266
+ switch (process.platform) {
267
+ case "darwin":
268
+ return { cmd: "pbcopy", args: [] };
269
+ case "win32":
270
+ return { cmd: "clip", args: [] };
271
+ default:
272
+ return { cmd: "xclip", args: ["-selection", "clipboard"] };
273
+ }
274
+ }
275
+ async function pipeToClipboard(producer, backend) {
276
+ const clip = clipboardCommand();
277
+ await new Promise((resolve, reject) => {
278
+ const source = spawn(producer.cmd, producer.args, {
279
+ stdio: ["ignore", "pipe", "pipe"]
280
+ });
281
+ const sink = spawn(clip.cmd, clip.args, {
282
+ stdio: ["pipe", "ignore", "pipe"]
283
+ });
284
+ let settled = false;
285
+ const settle = (err) => {
286
+ if (settled) return;
287
+ settled = true;
288
+ if (err) {
289
+ source.kill();
290
+ sink.kill();
291
+ reject(err);
292
+ } else {
293
+ resolve();
294
+ }
295
+ };
296
+ source.on(
297
+ "error",
298
+ (err) => settle(
299
+ new PasswordManagerError(
300
+ `Failed to run ${producer.cmd}: ${err.message}`,
301
+ backend,
302
+ err
303
+ )
304
+ )
305
+ );
306
+ sink.on(
307
+ "error",
308
+ (err) => settle(
309
+ new PasswordManagerError(
310
+ `Failed to run clipboard command ${clip.cmd}: ${err.message}`,
311
+ backend,
312
+ err
313
+ )
314
+ )
315
+ );
316
+ source.stdout.pipe(sink.stdin);
317
+ let sourceExit = null;
318
+ let sinkExit = null;
319
+ const maybeDone = () => {
320
+ if (sourceExit === null || sinkExit === null) return;
321
+ if (sourceExit !== 0) {
322
+ settle(
323
+ new PasswordManagerError(
324
+ `${producer.cmd} exited with code ${sourceExit}`,
325
+ backend
326
+ )
327
+ );
328
+ return;
329
+ }
330
+ if (sinkExit !== 0) {
331
+ settle(
332
+ new PasswordManagerError(
333
+ `${clip.cmd} exited with code ${sinkExit}`,
334
+ backend
335
+ )
336
+ );
337
+ return;
338
+ }
339
+ settle();
340
+ };
341
+ source.on("close", (code) => {
342
+ sourceExit = code ?? 0;
343
+ maybeDone();
344
+ });
345
+ sink.on("close", (code) => {
346
+ sinkExit = code ?? 0;
347
+ maybeDone();
348
+ });
349
+ });
350
+ }
351
+ async function resolveActiveBackend(config) {
352
+ const backend = await detectPasswordManagerBackend(config);
353
+ if (backend === "none") {
354
+ throw new PasswordManagerError(
355
+ "No password manager backend available (install 1Password CLI `op` or ProtonPass/`pass`)",
356
+ "none"
357
+ );
358
+ }
359
+ return backend;
360
+ }
361
+ async function searchPasswordItems(query, config) {
362
+ const backend = await resolveActiveBackend(config);
363
+ const items = backend === "fixture" ? listItemsViaFixture() : backend === "1password" ? await listItemsVia1Password(config) : await listItemsViaProtonPass(config);
364
+ return items.filter((item) => matchesQuery(item, query));
365
+ }
366
+ async function listPasswordItems(opts, config) {
367
+ const backend = await resolveActiveBackend(config);
368
+ const items = backend === "fixture" ? listItemsViaFixture() : backend === "1password" ? await listItemsVia1Password(config) : await listItemsViaProtonPass(config);
369
+ const limit = opts.limit;
370
+ if (typeof limit === "number" && limit >= 0) {
371
+ return items.slice(0, limit);
372
+ }
373
+ return items;
374
+ }
375
+ async function injectCredentialToClipboard(itemId, field, config) {
376
+ if (!itemId || typeof itemId !== "string") {
377
+ throw new PasswordManagerError(
378
+ "itemId is required",
379
+ config?.preferredBackend ?? "none"
380
+ );
381
+ }
382
+ const backend = await resolveActiveBackend(config);
383
+ if (backend === "fixture") {
384
+ logger.warn(
385
+ {
386
+ itemId,
387
+ field,
388
+ boundary: "browser",
389
+ component: "password-manager-bridge"
390
+ },
391
+ "[password-manager-bridge] fixture backend active: no clipboard write performed. Set ELIZA_TEST_PASSWORD_MANAGER_BACKEND=0 for real injection."
392
+ );
393
+ return {
394
+ ok: true,
395
+ expiresInSeconds: CLIPBOARD_TTL_SECONDS,
396
+ fixtureMode: true
397
+ };
398
+ }
399
+ if (backend === "1password") {
400
+ const binary2 = resolveOpBinary(config);
401
+ const args = [
402
+ ...opBaseArgs(config),
403
+ "item",
404
+ "get",
405
+ itemId,
406
+ "--fields",
407
+ field === "password" ? "password" : "username",
408
+ "--reveal"
409
+ ];
410
+ await pipeToClipboard({ cmd: binary2, args }, "1password");
411
+ return { ok: true, expiresInSeconds: CLIPBOARD_TTL_SECONDS };
412
+ }
413
+ const binary = resolveProtonPassBinary(config);
414
+ if (field === "username") {
415
+ throw new PasswordManagerError(
416
+ "Username injection is not supported by the ProtonPass/pass backend",
417
+ "protonpass"
418
+ );
419
+ }
420
+ let producerCmd = binary;
421
+ const producerArgs = ["show", itemId];
422
+ if (!config?.protonPassPath) {
423
+ const hasProton = await probeBinary(binary, ["--version"]);
424
+ if (!hasProton) producerCmd = "pass";
425
+ }
426
+ await pipeToClipboard({ cmd: producerCmd, args: producerArgs }, "protonpass");
427
+ return { ok: true, expiresInSeconds: CLIPBOARD_TTL_SECONDS };
428
+ }
429
+ export {
430
+ PasswordManagerError,
431
+ clearPasswordManagerBackendCache,
432
+ detectPasswordManagerBackend,
433
+ injectCredentialToClipboard,
434
+ listPasswordItems,
435
+ searchPasswordItems
436
+ };
437
+ //# sourceMappingURL=password-manager-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/password-manager-bridge.ts"],"sourcesContent":["/**\n * Password manager bridge — dual-backend (1Password CLI `op` or ProtonPass CLI).\n *\n * Security posture:\n * - Plaintext credentials NEVER enter return values.\n * - `injectCredentialToClipboard` pipes the secret from the backend CLI\n * directly into the OS clipboard via `execFile` without ever surfacing\n * the value to the Node process beyond a narrow buffer that is\n * discarded immediately.\n * - Nothing is logged that could contain secret material.\n * - All subprocess invocations use `execFile` with an args array.\n */\n\nimport { execFile, spawn } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { logger } from \"@elizaos/core\";\n\nconst execFileAsync = promisify(execFile);\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type PasswordManagerBackend =\n | \"1password\"\n | \"protonpass\"\n | \"fixture\"\n | \"none\";\n\nexport interface PasswordManagerItem {\n id: string;\n title: string;\n url?: string;\n username?: string;\n /** Metadata flag only — the actual password is never returned. */\n hasPassword: boolean;\n tags?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface PasswordManagerBridgeConfig {\n preferredBackend?: PasswordManagerBackend;\n /** Passed via `op --account`. Sourced from env `ELIZA_1PASSWORD_ACCOUNT`. */\n onePasswordAccount?: string;\n /** Binary override for 1Password CLI (default: \"op\"). */\n opPath?: string;\n /** Binary override for ProtonPass CLI (default: \"protonpass\" then \"pass\"). */\n protonPassPath?: string;\n}\n\nexport class PasswordManagerError extends Error {\n readonly backend: PasswordManagerBackend;\n readonly cause?: unknown;\n\n constructor(\n message: string,\n backend: PasswordManagerBackend,\n cause?: unknown,\n ) {\n super(message);\n this.name = \"PasswordManagerError\";\n this.backend = backend;\n this.cause = cause;\n }\n}\n\nconst CLIPBOARD_TTL_SECONDS = 30;\n\nconst PASSWORD_MANAGER_FIXTURE_ITEMS: ReadonlyArray<PasswordManagerItem> = [\n {\n id: \"pm-github\",\n title: \"GitHub\",\n url: \"https://github.com/login\",\n username: \"benchmark-user\",\n hasPassword: true,\n tags: [\"dev\", \"github\", \"code\"],\n metadata: { vault: \"Mocked Benchmark\" },\n },\n {\n id: \"pm-google-workspace\",\n title: \"Google Workspace\",\n url: \"https://mail.google.com\",\n username: \"owner@example.com\",\n hasPassword: true,\n tags: [\"google\", \"email\"],\n metadata: { vault: \"Mocked Benchmark\" },\n },\n {\n id: \"pm-aws-prod\",\n title: \"AWS Console\",\n url: \"https://signin.aws.amazon.com\",\n username: \"infra@example.com\",\n hasPassword: true,\n tags: [\"aws\", \"cloud\"],\n metadata: { vault: \"Mocked Benchmark\" },\n },\n];\n\nfunction isTruthyEnv(value: string | undefined): boolean {\n if (!value) return false;\n const normalized = value.trim().toLowerCase();\n return (\n normalized === \"1\" ||\n normalized === \"true\" ||\n normalized === \"yes\" ||\n normalized === \"on\" ||\n normalized === \"fixture\"\n );\n}\n\nfunction isFalsyEnv(value: string | undefined): boolean {\n if (!value) return false;\n const normalized = value.trim().toLowerCase();\n return (\n normalized === \"0\" ||\n normalized === \"false\" ||\n normalized === \"no\" ||\n normalized === \"off\"\n );\n}\n\nfunction isFixturePasswordManagerEnabled(): boolean {\n const explicit = process.env.ELIZA_TEST_PASSWORD_MANAGER_BACKEND;\n if (isFalsyEnv(explicit)) return false;\n if (isTruthyEnv(explicit)) return true;\n return false;\n}\n\nfunction listItemsViaFixture(): PasswordManagerItem[] {\n return PASSWORD_MANAGER_FIXTURE_ITEMS.map((item) => ({\n ...item,\n tags: item.tags ? [...item.tags] : undefined,\n metadata: item.metadata ? { ...item.metadata } : undefined,\n }));\n}\n\n// ---------------------------------------------------------------------------\n// Detection\n// ---------------------------------------------------------------------------\n\nconst detectionCache = new Map<string, PasswordManagerBackend>();\n\nfunction cacheKey(config?: PasswordManagerBridgeConfig): string {\n const c = config ?? {};\n return [\n c.preferredBackend ?? \"\",\n c.onePasswordAccount ?? \"\",\n c.opPath ?? \"\",\n c.protonPassPath ?? \"\",\n ].join(\"|\");\n}\n\nfunction resolveOpBinary(config?: PasswordManagerBridgeConfig): string {\n return config?.opPath?.trim() || \"op\";\n}\n\nfunction resolveProtonPassBinary(config?: PasswordManagerBridgeConfig): string {\n return config?.protonPassPath?.trim() || \"protonpass\";\n}\n\nasync function probeBinary(binary: string, args: string[]): Promise<boolean> {\n try {\n await execFileAsync(binary, args, { timeout: 3_000 });\n return true;\n } catch {\n return false;\n }\n}\n\nasync function probeOp(config?: PasswordManagerBridgeConfig): Promise<boolean> {\n return probeBinary(resolveOpBinary(config), [\"--version\"]);\n}\n\nasync function probeProtonPass(\n config?: PasswordManagerBridgeConfig,\n): Promise<boolean> {\n if (await probeBinary(resolveProtonPassBinary(config), [\"--version\"])) {\n return true;\n }\n // `pass` — classic Unix password-store — also supported as a fallback.\n if (!config?.protonPassPath) {\n return probeBinary(\"pass\", [\"--version\"]);\n }\n return false;\n}\n\nexport async function detectPasswordManagerBackend(\n config?: PasswordManagerBridgeConfig,\n): Promise<PasswordManagerBackend> {\n const key = cacheKey(config);\n const cached = detectionCache.get(key);\n if (cached !== undefined) return cached;\n\n const preferred = config?.preferredBackend;\n if (preferred === \"none\") {\n detectionCache.set(key, \"none\");\n return \"none\";\n }\n if (preferred === \"fixture\") {\n detectionCache.set(key, \"fixture\");\n return \"fixture\";\n }\n if (isFixturePasswordManagerEnabled()) {\n detectionCache.set(key, \"fixture\");\n return \"fixture\";\n }\n if (preferred === \"1password\") {\n const ok = await probeOp(config);\n const result: PasswordManagerBackend = ok ? \"1password\" : \"none\";\n detectionCache.set(key, result);\n return result;\n }\n if (preferred === \"protonpass\") {\n const ok = await probeProtonPass(config);\n const result: PasswordManagerBackend = ok ? \"protonpass\" : \"none\";\n detectionCache.set(key, result);\n return result;\n }\n\n if (await probeOp(config)) {\n detectionCache.set(key, \"1password\");\n return \"1password\";\n }\n if (await probeProtonPass(config)) {\n detectionCache.set(key, \"protonpass\");\n return \"protonpass\";\n }\n detectionCache.set(key, \"none\");\n return \"none\";\n}\n\n/** Clear the backend detection cache. Exposed for tests. */\nexport function clearPasswordManagerBackendCache(): void {\n detectionCache.clear();\n}\n\n// ---------------------------------------------------------------------------\n// 1Password CLI backend\n// ---------------------------------------------------------------------------\n\ninterface OpItemListEntry {\n id?: string;\n title?: string;\n tags?: string[];\n urls?: Array<{ href?: string; primary?: boolean }>;\n additional_information?: string;\n category?: string;\n vault?: { id?: string; name?: string };\n}\n\nfunction opBaseArgs(config?: PasswordManagerBridgeConfig): string[] {\n const args: string[] = [];\n const account = config?.onePasswordAccount?.trim();\n if (account) args.push(\"--account\", account);\n return args;\n}\n\nasync function runOp(\n args: string[],\n config?: PasswordManagerBridgeConfig,\n): Promise<string> {\n const binary = resolveOpBinary(config);\n const fullArgs = [...opBaseArgs(config), ...args];\n try {\n const { stdout } = await execFileAsync(binary, fullArgs, {\n timeout: 15_000,\n maxBuffer: 16 * 1024 * 1024,\n });\n return stdout;\n } catch (error) {\n throw new PasswordManagerError(\n `1Password CLI failed for \"${args[0] ?? \"\"}\": ${\n error instanceof Error ? error.message : String(error)\n }`,\n \"1password\",\n error,\n );\n }\n}\n\nfunction normalizeOpListEntry(raw: OpItemListEntry): PasswordManagerItem {\n const id = raw.id ?? \"\";\n if (!id) {\n throw new PasswordManagerError(\"1Password item missing id\", \"1password\");\n }\n const primaryUrl =\n raw.urls?.find((u) => u.primary)?.href ?? raw.urls?.[0]?.href;\n return {\n id,\n title: raw.title ?? id,\n url: primaryUrl,\n username: raw.additional_information,\n hasPassword: (raw.category ?? \"\").toUpperCase() === \"LOGIN\",\n tags: raw.tags,\n metadata: {\n category: raw.category,\n vault: raw.vault?.name,\n },\n };\n}\n\nasync function listItemsVia1Password(\n config?: PasswordManagerBridgeConfig,\n): Promise<PasswordManagerItem[]> {\n const stdout = await runOp([\"item\", \"list\", \"--format\", \"json\"], config);\n const trimmed = stdout.trim();\n if (!trimmed) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch (error) {\n throw new PasswordManagerError(\n \"1Password returned invalid JSON from item list\",\n \"1password\",\n error,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new PasswordManagerError(\n \"1Password item list was not an array\",\n \"1password\",\n );\n }\n return (parsed as OpItemListEntry[]).map(normalizeOpListEntry);\n}\n\nfunction matchesQuery(item: PasswordManagerItem, q: string): boolean {\n if (!q) return true;\n const needle = q.toLowerCase();\n if (item.title.toLowerCase().includes(needle)) return true;\n if (item.url?.toLowerCase().includes(needle)) return true;\n if (item.username?.toLowerCase().includes(needle)) return true;\n if (item.tags?.some((t) => t.toLowerCase().includes(needle))) return true;\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// ProtonPass / pass backend\n// ---------------------------------------------------------------------------\n//\n// Both `protonpass` and classic `pass` support listing entries by name.\n// Neither exposes rich metadata; we emit title-only items with the entry\n// path used as the id. Per the contract, we never include plaintext\n// secrets in returned objects.\n\nasync function listItemsViaProtonPass(\n config?: PasswordManagerBridgeConfig,\n): Promise<PasswordManagerItem[]> {\n const binary = resolveProtonPassBinary(config);\n let stdout: string;\n try {\n const result = await execFileAsync(binary, [\"list\"], {\n timeout: 10_000,\n maxBuffer: 8 * 1024 * 1024,\n });\n stdout = result.stdout;\n } catch (error) {\n // Try classic `pass` if protonpass failed and user didn't pin a binary.\n if (!config?.protonPassPath) {\n try {\n const result = await execFileAsync(\"pass\", [\"ls\"], {\n timeout: 10_000,\n maxBuffer: 8 * 1024 * 1024,\n });\n stdout = result.stdout;\n } catch (inner) {\n throw new PasswordManagerError(\n `ProtonPass/pass list failed: ${\n inner instanceof Error ? inner.message : String(inner)\n }`,\n \"protonpass\",\n inner,\n );\n }\n } else {\n throw new PasswordManagerError(\n `ProtonPass list failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n \"protonpass\",\n error,\n );\n }\n }\n\n const items: PasswordManagerItem[] = [];\n for (const rawLine of stdout.split(\"\\n\")) {\n // Strip tree characters from `pass ls` output (├── └── │ etc.).\n const line = rawLine\n .replace(/[│├└─]+/g, \"\")\n .replace(/\\u00a0/g, \" \")\n .trim();\n if (!line) continue;\n if (line.toLowerCase().startsWith(\"password store\")) continue;\n items.push({\n id: line,\n title: line,\n hasPassword: true,\n });\n }\n return items;\n}\n\n// ---------------------------------------------------------------------------\n// Clipboard injection\n// ---------------------------------------------------------------------------\n\nfunction clipboardCommand(): { cmd: string; args: string[] } {\n switch (process.platform) {\n case \"darwin\":\n return { cmd: \"pbcopy\", args: [] };\n case \"win32\":\n return { cmd: \"clip\", args: [] };\n default:\n // Linux/BSD — prefer xclip, but the command must be present on PATH.\n return { cmd: \"xclip\", args: [\"-selection\", \"clipboard\"] };\n }\n}\n\n/**\n * Pipe stdout of a producer subprocess directly into the clipboard command.\n *\n * The plaintext secret passes through this process's memory only as kernel\n * pipe buffers between the two children — it is never buffered as a JS\n * string, never logged, and never returned.\n */\nasync function pipeToClipboard(\n producer: { cmd: string; args: string[] },\n backend: PasswordManagerBackend,\n): Promise<void> {\n const clip = clipboardCommand();\n\n await new Promise<void>((resolve, reject) => {\n const source = spawn(producer.cmd, producer.args, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n const sink = spawn(clip.cmd, clip.args, {\n stdio: [\"pipe\", \"ignore\", \"pipe\"],\n });\n\n let settled = false;\n const settle = (err?: Error) => {\n if (settled) return;\n settled = true;\n if (err) {\n source.kill();\n sink.kill();\n reject(err);\n } else {\n resolve();\n }\n };\n\n source.on(\"error\", (err) =>\n settle(\n new PasswordManagerError(\n `Failed to run ${producer.cmd}: ${err.message}`,\n backend,\n err,\n ),\n ),\n );\n sink.on(\"error\", (err) =>\n settle(\n new PasswordManagerError(\n `Failed to run clipboard command ${clip.cmd}: ${err.message}`,\n backend,\n err,\n ),\n ),\n );\n\n source.stdout.pipe(sink.stdin);\n\n let sourceExit: number | null = null;\n let sinkExit: number | null = null;\n const maybeDone = () => {\n if (sourceExit === null || sinkExit === null) return;\n if (sourceExit !== 0) {\n settle(\n new PasswordManagerError(\n `${producer.cmd} exited with code ${sourceExit}`,\n backend,\n ),\n );\n return;\n }\n if (sinkExit !== 0) {\n settle(\n new PasswordManagerError(\n `${clip.cmd} exited with code ${sinkExit}`,\n backend,\n ),\n );\n return;\n }\n settle();\n };\n source.on(\"close\", (code) => {\n sourceExit = code ?? 0;\n maybeDone();\n });\n sink.on(\"close\", (code) => {\n sinkExit = code ?? 0;\n maybeDone();\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Public dispatch\n// ---------------------------------------------------------------------------\n\nasync function resolveActiveBackend(\n config?: PasswordManagerBridgeConfig,\n): Promise<PasswordManagerBackend> {\n const backend = await detectPasswordManagerBackend(config);\n if (backend === \"none\") {\n throw new PasswordManagerError(\n \"No password manager backend available (install 1Password CLI `op` or ProtonPass/`pass`)\",\n \"none\",\n );\n }\n return backend;\n}\n\nexport async function searchPasswordItems(\n query: string,\n config?: PasswordManagerBridgeConfig,\n): Promise<PasswordManagerItem[]> {\n const backend = await resolveActiveBackend(config);\n const items =\n backend === \"fixture\"\n ? listItemsViaFixture()\n : backend === \"1password\"\n ? await listItemsVia1Password(config)\n : await listItemsViaProtonPass(config);\n return items.filter((item) => matchesQuery(item, query));\n}\n\nexport async function listPasswordItems(\n opts: { limit?: number },\n config?: PasswordManagerBridgeConfig,\n): Promise<PasswordManagerItem[]> {\n const backend = await resolveActiveBackend(config);\n const items =\n backend === \"fixture\"\n ? listItemsViaFixture()\n : backend === \"1password\"\n ? await listItemsVia1Password(config)\n : await listItemsViaProtonPass(config);\n const limit = opts.limit;\n if (typeof limit === \"number\" && limit >= 0) {\n return items.slice(0, limit);\n }\n return items;\n}\n\nexport async function injectCredentialToClipboard(\n itemId: string,\n field: \"username\" | \"password\",\n config?: PasswordManagerBridgeConfig,\n): Promise<{ ok: true; expiresInSeconds: number; fixtureMode?: boolean }> {\n if (!itemId || typeof itemId !== \"string\") {\n throw new PasswordManagerError(\n \"itemId is required\",\n config?.preferredBackend ?? \"none\",\n );\n }\n const backend = await resolveActiveBackend(config);\n\n if (backend === \"fixture\") {\n logger.warn(\n {\n itemId,\n field,\n boundary: \"browser\",\n component: \"password-manager-bridge\",\n },\n \"[password-manager-bridge] fixture backend active: no clipboard write performed. Set ELIZA_TEST_PASSWORD_MANAGER_BACKEND=0 for real injection.\",\n );\n return {\n ok: true,\n expiresInSeconds: CLIPBOARD_TTL_SECONDS,\n fixtureMode: true,\n };\n }\n\n if (backend === \"1password\") {\n const binary = resolveOpBinary(config);\n const args = [\n ...opBaseArgs(config),\n \"item\",\n \"get\",\n itemId,\n \"--fields\",\n field === \"password\" ? \"password\" : \"username\",\n \"--reveal\",\n ];\n await pipeToClipboard({ cmd: binary, args }, \"1password\");\n return { ok: true, expiresInSeconds: CLIPBOARD_TTL_SECONDS };\n }\n\n // protonpass / pass\n const binary = resolveProtonPassBinary(config);\n // Both `protonpass show <id>` and `pass show <id>` print the secret on the\n // first line. Username retrieval is not uniformly supported in classic\n // pass; callers must store username in the entry body to retrieve it.\n if (field === \"username\") {\n throw new PasswordManagerError(\n \"Username injection is not supported by the ProtonPass/pass backend\",\n \"protonpass\",\n );\n }\n let producerCmd = binary;\n const producerArgs = [\"show\", itemId];\n // Fallback to classic `pass` when protonpass isn't pinned and missing.\n if (!config?.protonPassPath) {\n const hasProton = await probeBinary(binary, [\"--version\"]);\n if (!hasProton) producerCmd = \"pass\";\n }\n await pipeToClipboard({ cmd: producerCmd, args: producerArgs }, \"protonpass\");\n return { ok: true, expiresInSeconds: CLIPBOARD_TTL_SECONDS };\n}\n"],"mappings":"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","names":["binary"]}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,KAAK,EAEV,MAAM,EAIP,MAAM,eAAe,CAAC;AA4KvB,eAAO,MAAM,aAAa,EAAE,MAyB3B,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAGV,MAAM,EAIP,MAAM,eAAe,CAAC;AAgLvB,eAAO,MAAM,aAAa,EAAE,MA6B3B,CAAC"}
package/dist/plugin.js CHANGED
@@ -1,11 +1,11 @@
1
+ import { TLSSocket } from "node:tls";
1
2
  import {
2
3
  readJsonBody as httpReadJsonBody,
3
4
  sendJson as httpSendJson,
4
5
  sendJsonError as httpSendJsonError,
5
- promoteSubactionsToActions
6
+ promoteSubactionsToActions,
7
+ resolveCanonicalOwnerId
6
8
  } from "@elizaos/core";
7
- import { TLSSocket } from "node:tls";
8
- import { resolveCanonicalOwnerId } from "@elizaos/core";
9
9
  import { browserAction } from "./actions/browser.js";
10
10
  import { manageBrowserBridgeAction } from "./actions/manage-browser-bridge.js";
11
11
  import { BrowserService } from "./browser-service.js";
@@ -141,7 +141,7 @@ const browserBridgePluginRoutes = [
141
141
  ];
142
142
  const browserPlugin = {
143
143
  name: "@elizaos/plugin-browser",
144
- description: "Browser plugin: BROWSER (including autofill-login subaction) + MANAGE_BROWSER_BRIDGE; workspace browser command router (electrobun-embedded BrowserView + JSDOM fallback) and Chrome/Safari companion bridge (settings, pairing, tab + page-context sync, packaging artifacts).",
144
+ description: "Browser plugin: BROWSER (including action=autofill_login) + MANAGE_BROWSER_BRIDGE; workspace browser command router (electrobun-embedded BrowserView + JSDOM fallback) and Chrome/Safari companion bridge (settings, pairing, tab + page-context sync, packaging artifacts).",
145
145
  schema: browserBridgeSchema,
146
146
  routes: [...browserBridgePluginRoutes, ...browserWorkspaceRoutes],
147
147
  services: [BrowserService],
@@ -156,6 +156,10 @@ const browserPlugin = {
156
156
  const f = config?.features?.browser;
157
157
  return f === true || typeof f === "object" && f !== null && f.enabled !== false;
158
158
  }
159
+ },
160
+ async dispose(runtime) {
161
+ const svc = runtime.getService(BrowserService.serviceType);
162
+ await svc?.stop();
159
163
  }
160
164
  };
161
165
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["/**\n * @elizaos/plugin-browser plugin export.\n *\n * plugin-collector discovers `routes` and `schema` at runtime. Eliza loads\n * this as a core plugin so the Browser Workspace UI and browser companion\n * extension share one route surface.\n */\n\nimport type http from \"node:http\";\nimport {\n readJsonBody as httpReadJsonBody,\n sendJson as httpSendJson,\n sendJsonError as httpSendJsonError,\n promoteSubactionsToActions,\n} from \"@elizaos/core\";\nimport { TLSSocket } from \"node:tls\";\nimport type {\n AgentRuntime,\n Plugin,\n Route,\n ServiceClass,\n UUID,\n} from \"@elizaos/core\";\nimport { resolveCanonicalOwnerId } from \"@elizaos/core\";\nimport { browserAction } from \"./actions/browser.js\";\nimport { manageBrowserBridgeAction } from \"./actions/manage-browser-bridge.js\";\nimport { BrowserService } from \"./browser-service.js\";\nimport { browserWorkspaceProvider } from \"./providers/workspace.js\";\nimport {\n type BrowserBridgeRouteContext,\n handleBrowserBridgeRoutes,\n} from \"./routes/bridge.js\";\nimport { browserWorkspaceRoutes } from \"./routes/workspace-setup.js\";\nimport { browserBridgeSchema } from \"./schema.js\";\n\nfunction json(res: http.ServerResponse, data: unknown, status = 200): void {\n httpSendJson(res, data, status);\n}\n\nfunction error(res: http.ServerResponse, message: string, status = 400): void {\n httpSendJsonError(res, message, status);\n}\n\nfunction httpDecodePathComponent(\n raw: string,\n res: http.ServerResponse,\n fieldName: string,\n): string | null {\n try {\n return decodeURIComponent(raw);\n } catch {\n httpSendJsonError(res, `Invalid ${fieldName}: malformed URL encoding`, 400);\n return null;\n }\n}\n\nfunction firstHeaderValue(value: string | string[] | undefined): string | null {\n if (Array.isArray(value)) {\n return firstHeaderValue(value[0]);\n }\n if (typeof value !== \"string\") {\n return null;\n }\n const normalized = value.split(\",\")[0]?.trim();\n return normalized ? normalized : null;\n}\n\nfunction requestBaseUrl(req: http.IncomingMessage): string {\n const headers = req.headers ?? {};\n const protocol =\n firstHeaderValue(headers[\"x-forwarded-proto\"]) ??\n (req.socket instanceof TLSSocket && req.socket.encrypted\n ? \"https\"\n : \"http\");\n const host =\n firstHeaderValue(headers[\"x-forwarded-host\"]) ??\n firstHeaderValue(headers.host) ??\n \"localhost\";\n return `${protocol}://${host}`;\n}\n\nfunction routeOwnerEntityId(runtime: AgentRuntime | null): UUID | null {\n const ownerId = runtime ? resolveCanonicalOwnerId(runtime) : null;\n return typeof ownerId === \"string\" ? (ownerId as UUID) : null;\n}\n\nfunction buildRouteContext(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n runtime: AgentRuntime | null,\n): BrowserBridgeRouteContext {\n const method = (req.method ?? \"GET\").toUpperCase();\n const url = new URL(req.url ?? \"/\", requestBaseUrl(req));\n return {\n req,\n res,\n method,\n pathname: url.pathname,\n url,\n state: {\n runtime,\n adminEntityId: routeOwnerEntityId(runtime),\n },\n json,\n error,\n readJsonBody: httpReadJsonBody,\n decodePathComponent: httpDecodePathComponent,\n };\n}\n\nconst STATIC_ROUTES: Array<{ type: string; path: string; public?: boolean }> = [\n { type: \"GET\", path: \"/api/browser-bridge/sessions\" },\n { type: \"GET\", path: \"/api/browser-bridge/settings\" },\n { type: \"POST\", path: \"/api/browser-bridge/settings\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/pair\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/auto-pair\" },\n { type: \"GET\", path: \"/api/browser-bridge/companions\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/revoke\", public: true },\n { type: \"GET\", path: \"/api/browser-bridge/packages\" },\n { type: \"POST\", path: \"/api/browser-bridge/packages/open-path\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/sync\", public: true },\n { type: \"GET\", path: \"/api/browser-bridge/tabs\" },\n { type: \"GET\", path: \"/api/browser-bridge/current-page\" },\n { type: \"POST\", path: \"/api/browser-bridge/sync\" },\n { type: \"POST\", path: \"/api/browser-bridge/sessions\" },\n];\n\nconst DYNAMIC_ROUTES: Array<{ type: string; path: string; public?: boolean }> =\n [\n { type: \"GET\", path: \"/api/browser-bridge/sessions/:id\" },\n { type: \"POST\", path: \"/api/browser-bridge/sessions/:id/confirm\" },\n { type: \"POST\", path: \"/api/browser-bridge/sessions/:id/progress\" },\n { type: \"POST\", path: \"/api/browser-bridge/sessions/:id/complete\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/:id/revoke\" },\n {\n type: \"POST\",\n path: \"/api/browser-bridge/companions/sessions/:id/progress\",\n public: true,\n },\n {\n type: \"POST\",\n path: \"/api/browser-bridge/companions/sessions/:id/complete\",\n public: true,\n },\n { type: \"POST\", path: \"/api/browser-bridge/packages/:browser/build\" },\n {\n type: \"POST\",\n path: \"/api/browser-bridge/packages/:browser/open-manager\",\n },\n { type: \"GET\", path: \"/api/browser-bridge/packages/:browser/download\" },\n ];\n\ntype PluginRouteHandler = NonNullable<Route[\"handler\"]>;\n\nfunction routeHandler(): PluginRouteHandler {\n return async (\n req: unknown,\n res: unknown,\n runtime: unknown,\n ): Promise<void> => {\n const httpReq = req as http.IncomingMessage;\n const httpRes = res as http.ServerResponse;\n const ctx = buildRouteContext(\n httpReq,\n httpRes,\n (runtime as AgentRuntime) ?? null,\n );\n await handleBrowserBridgeRoutes(ctx);\n };\n}\n\nconst browserBridgePluginRoutes: Route[] = [\n ...STATIC_ROUTES.map(\n (r) =>\n ({\n type: r.type as Route[\"type\"],\n path: r.path,\n rawPath: true as const,\n ...(r.public ? ({ public: true } as const) : {}),\n handler: routeHandler(),\n }) as Route,\n ),\n ...DYNAMIC_ROUTES.map(\n (r) =>\n ({\n type: r.type as Route[\"type\"],\n path: r.path,\n rawPath: true as const,\n ...(r.public ? ({ public: true } as const) : {}),\n handler: routeHandler(),\n }) as Route,\n ),\n];\n\nexport const browserPlugin: Plugin = {\n name: \"@elizaos/plugin-browser\",\n description:\n \"Browser plugin: BROWSER (including autofill-login subaction) + MANAGE_BROWSER_BRIDGE; workspace browser command router (electrobun-embedded BrowserView + JSDOM fallback) and Chrome/Safari companion bridge (settings, pairing, tab + page-context sync, packaging artifacts).\",\n schema: browserBridgeSchema,\n routes: [...browserBridgePluginRoutes, ...browserWorkspaceRoutes],\n services: [BrowserService as ServiceClass],\n providers: [browserWorkspaceProvider],\n actions: [\n ...promoteSubactionsToActions(browserAction),\n ...promoteSubactionsToActions(manageBrowserBridgeAction),\n ],\n // Self-declared auto-enable: activate when features.browser is enabled.\n autoEnable: {\n shouldEnable: (_env, config) => {\n const f = (config?.features as Record<string, unknown> | undefined)\n ?.browser;\n return (\n f === true ||\n (typeof f === \"object\" &&\n f !== null &&\n (f as { enabled?: unknown }).enabled !== false)\n );\n },\n },\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["/**\n * @elizaos/plugin-browser plugin export.\n *\n * plugin-collector discovers `routes` and `schema` at runtime. Eliza loads\n * this as a core plugin so the Browser Workspace UI and browser companion\n * extension share one route surface.\n */\n\nimport type http from \"node:http\";\nimport { TLSSocket } from \"node:tls\";\nimport type {\n AgentRuntime,\n LegacyRouteHandler,\n Plugin,\n Route,\n ServiceClass,\n UUID,\n} from \"@elizaos/core\";\nimport {\n readJsonBody as httpReadJsonBody,\n sendJson as httpSendJson,\n sendJsonError as httpSendJsonError,\n promoteSubactionsToActions,\n resolveCanonicalOwnerId,\n} from \"@elizaos/core\";\nimport { browserAction } from \"./actions/browser.js\";\nimport { manageBrowserBridgeAction } from \"./actions/manage-browser-bridge.js\";\nimport { BrowserService } from \"./browser-service.js\";\nimport { browserWorkspaceProvider } from \"./providers/workspace.js\";\nimport {\n type BrowserBridgeRouteContext,\n handleBrowserBridgeRoutes,\n} from \"./routes/bridge.js\";\nimport { browserWorkspaceRoutes } from \"./routes/workspace-setup.js\";\nimport { browserBridgeSchema } from \"./schema.js\";\n\nfunction json(res: http.ServerResponse, data: unknown, status = 200): void {\n httpSendJson(res, data, status);\n}\n\nfunction error(res: http.ServerResponse, message: string, status = 400): void {\n httpSendJsonError(res, message, status);\n}\n\nfunction httpDecodePathComponent(\n raw: string,\n res: http.ServerResponse,\n fieldName: string,\n): string | null {\n try {\n return decodeURIComponent(raw);\n } catch {\n httpSendJsonError(res, `Invalid ${fieldName}: malformed URL encoding`, 400);\n return null;\n }\n}\n\nfunction firstHeaderValue(value: string | string[] | undefined): string | null {\n if (Array.isArray(value)) {\n return firstHeaderValue(value[0]);\n }\n if (typeof value !== \"string\") {\n return null;\n }\n const normalized = value.split(\",\")[0]?.trim();\n return normalized ? normalized : null;\n}\n\nfunction requestBaseUrl(req: http.IncomingMessage): string {\n const headers = req.headers ?? {};\n const protocol =\n firstHeaderValue(headers[\"x-forwarded-proto\"]) ??\n (req.socket instanceof TLSSocket && req.socket.encrypted\n ? \"https\"\n : \"http\");\n const host =\n firstHeaderValue(headers[\"x-forwarded-host\"]) ??\n firstHeaderValue(headers.host) ??\n \"localhost\";\n return `${protocol}://${host}`;\n}\n\nfunction routeOwnerEntityId(runtime: AgentRuntime | null): UUID | null {\n const ownerId = runtime ? resolveCanonicalOwnerId(runtime) : null;\n return typeof ownerId === \"string\" ? (ownerId as UUID) : null;\n}\n\nfunction buildRouteContext(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n runtime: AgentRuntime | null,\n): BrowserBridgeRouteContext {\n const method = (req.method ?? \"GET\").toUpperCase();\n const url = new URL(req.url ?? \"/\", requestBaseUrl(req));\n return {\n req,\n res,\n method,\n pathname: url.pathname,\n url,\n state: {\n runtime,\n adminEntityId: routeOwnerEntityId(runtime),\n },\n json,\n error,\n readJsonBody: httpReadJsonBody,\n decodePathComponent: httpDecodePathComponent,\n };\n}\n\nconst STATIC_ROUTES: Array<{ type: string; path: string; public?: boolean }> = [\n { type: \"GET\", path: \"/api/browser-bridge/sessions\" },\n { type: \"GET\", path: \"/api/browser-bridge/settings\" },\n { type: \"POST\", path: \"/api/browser-bridge/settings\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/pair\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/auto-pair\" },\n { type: \"GET\", path: \"/api/browser-bridge/companions\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/revoke\", public: true },\n { type: \"GET\", path: \"/api/browser-bridge/packages\" },\n { type: \"POST\", path: \"/api/browser-bridge/packages/open-path\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/sync\", public: true },\n { type: \"GET\", path: \"/api/browser-bridge/tabs\" },\n { type: \"GET\", path: \"/api/browser-bridge/current-page\" },\n { type: \"POST\", path: \"/api/browser-bridge/sync\" },\n { type: \"POST\", path: \"/api/browser-bridge/sessions\" },\n];\n\nconst DYNAMIC_ROUTES: Array<{ type: string; path: string; public?: boolean }> =\n [\n { type: \"GET\", path: \"/api/browser-bridge/sessions/:id\" },\n { type: \"POST\", path: \"/api/browser-bridge/sessions/:id/confirm\" },\n { type: \"POST\", path: \"/api/browser-bridge/sessions/:id/progress\" },\n { type: \"POST\", path: \"/api/browser-bridge/sessions/:id/complete\" },\n { type: \"POST\", path: \"/api/browser-bridge/companions/:id/revoke\" },\n {\n type: \"POST\",\n path: \"/api/browser-bridge/companions/sessions/:id/progress\",\n public: true,\n },\n {\n type: \"POST\",\n path: \"/api/browser-bridge/companions/sessions/:id/complete\",\n public: true,\n },\n { type: \"POST\", path: \"/api/browser-bridge/packages/:browser/build\" },\n {\n type: \"POST\",\n path: \"/api/browser-bridge/packages/:browser/open-manager\",\n },\n { type: \"GET\", path: \"/api/browser-bridge/packages/:browser/download\" },\n ];\n\nfunction routeHandler(): LegacyRouteHandler {\n return async (\n req: unknown,\n res: unknown,\n runtime: unknown,\n ): Promise<void> => {\n const httpReq = req as http.IncomingMessage;\n const httpRes = res as http.ServerResponse;\n const ctx = buildRouteContext(\n httpReq,\n httpRes,\n (runtime as AgentRuntime) ?? null,\n );\n await handleBrowserBridgeRoutes(ctx);\n };\n}\n\nconst browserBridgePluginRoutes: Route[] = [\n ...STATIC_ROUTES.map(\n (r) =>\n ({\n type: r.type as Route[\"type\"],\n path: r.path,\n rawPath: true as const,\n ...(r.public ? ({ public: true } as const) : {}),\n handler: routeHandler(),\n }) as Route,\n ),\n ...DYNAMIC_ROUTES.map(\n (r) =>\n ({\n type: r.type as Route[\"type\"],\n path: r.path,\n rawPath: true as const,\n ...(r.public ? ({ public: true } as const) : {}),\n handler: routeHandler(),\n }) as Route,\n ),\n];\n\nexport const browserPlugin: Plugin = {\n name: \"@elizaos/plugin-browser\",\n description:\n \"Browser plugin: BROWSER (including action=autofill_login) + MANAGE_BROWSER_BRIDGE; workspace browser command router (electrobun-embedded BrowserView + JSDOM fallback) and Chrome/Safari companion bridge (settings, pairing, tab + page-context sync, packaging artifacts).\",\n schema: browserBridgeSchema,\n routes: [...browserBridgePluginRoutes, ...browserWorkspaceRoutes],\n services: [BrowserService as ServiceClass],\n providers: [browserWorkspaceProvider],\n actions: [\n ...promoteSubactionsToActions(browserAction),\n ...promoteSubactionsToActions(manageBrowserBridgeAction),\n ],\n // Self-declared auto-enable: activate when features.browser is enabled.\n autoEnable: {\n shouldEnable: (_env, config) => {\n const f = (config?.features as Record<string, unknown> | undefined)\n ?.browser;\n return (\n f === true ||\n (typeof f === \"object\" &&\n f !== null &&\n (f as { enabled?: unknown }).enabled !== false)\n );\n },\n },\n async dispose(runtime) {\n const svc = runtime.getService<BrowserService>(BrowserService.serviceType);\n await svc?.stop();\n },\n};\n"],"mappings":"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","names":[]}
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Does not include Steward wallet state — that lived in this provider while
7
7
  * `@elizaos/app-browser` owned both surfaces. After consolidation, Steward
8
- * exposes its own provider from `@elizaos/app-steward`; an agent that needs
8
+ * exposes its own provider from `@elizaos/plugin-steward-app`; an agent that needs
9
9
  * both contexts gets both providers, not a coupled one.
10
10
  */
11
11
  import type { Provider } from "@elizaos/core";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/workspace.ts"],"sourcesContent":["/**\n * Browser workspace provider — surfaces the live browser-workspace tab list\n * and current dispatch mode (`desktop` / `web`) into agent context whenever\n * a `browser` or `web` context is selected.\n *\n * Does not include Steward wallet state — that lived in this provider while\n * `@elizaos/app-browser` owned both surfaces. After consolidation, Steward\n * exposes its own provider from `@elizaos/app-steward`; an agent that needs\n * both contexts gets both providers, not a coupled one.\n */\n\nimport type { Provider } from \"@elizaos/core\";\nimport {\n getBrowserWorkspaceMode,\n listBrowserWorkspaceTabs,\n} from \"../workspace/browser-workspace.js\";\n\nconst PROVIDER_NAME = \"browser_workspace\";\nconst MAX_TABS_IN_SUMMARY = 8;\n\nexport const browserWorkspaceProvider: Provider = {\n name: PROVIDER_NAME,\n description:\n \"Live summary of the Eliza browser workspace — current dispatch mode and the open tab list, capped to the first 8 tabs.\",\n descriptionCompressed: \"Browser workspace mode + open tab list.\",\n contexts: [\"browser\", \"web\"],\n contextGate: { anyOf: [\"browser\", \"web\"] },\n cacheStable: false,\n cacheScope: \"turn\",\n get: async () => {\n try {\n const mode = getBrowserWorkspaceMode();\n const tabs = await listBrowserWorkspaceTabs();\n const text = JSON.stringify(\n {\n [PROVIDER_NAME]: {\n mode,\n tabCount: tabs.length,\n tabs: tabs.slice(0, MAX_TABS_IN_SUMMARY).map((tab) => ({\n id: tab.id,\n visible: tab.visible,\n url: tab.url,\n title: tab.title,\n })),\n },\n },\n null,\n 2,\n );\n return {\n text,\n data: {\n available: true,\n mode,\n tabs,\n },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n text: JSON.stringify(\n {\n [PROVIDER_NAME]: {\n available: false,\n error: message,\n },\n },\n null,\n 2,\n ),\n data: { available: false, error: message },\n };\n }\n },\n};\n"],"mappings":"AAYA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAEP,MAAM,gBAAgB;AACtB,MAAM,sBAAsB;AAErB,MAAM,2BAAqC;AAAA,EAChD,MAAM;AAAA,EACN,aACE;AAAA,EACF,uBAAuB;AAAA,EACvB,UAAU,CAAC,WAAW,KAAK;AAAA,EAC3B,aAAa,EAAE,OAAO,CAAC,WAAW,KAAK,EAAE;AAAA,EACzC,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,KAAK,YAAY;AACf,QAAI;AACF,YAAM,OAAO,wBAAwB;AACrC,YAAM,OAAO,MAAM,yBAAyB;AAC5C,YAAM,OAAO,KAAK;AAAA,QAChB;AAAA,UACE,CAAC,aAAa,GAAG;AAAA,YACf;AAAA,YACA,UAAU,KAAK;AAAA,YACf,MAAM,KAAK,MAAM,GAAG,mBAAmB,EAAE,IAAI,CAAC,SAAS;AAAA,cACrD,IAAI,IAAI;AAAA,cACR,SAAS,IAAI;AAAA,cACb,KAAK,IAAI;AAAA,cACT,OAAO,IAAI;AAAA,YACb,EAAE;AAAA,UACJ;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,QACA,MAAM;AAAA,UACJ,WAAW;AAAA,UACX;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO;AAAA,QACL,MAAM,KAAK;AAAA,UACT;AAAA,YACE,CAAC,aAAa,GAAG;AAAA,cACf,WAAW;AAAA,cACX,OAAO;AAAA,YACT;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,MAAM,EAAE,WAAW,OAAO,OAAO,QAAQ;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/providers/workspace.ts"],"sourcesContent":["/**\n * Browser workspace provider — surfaces the live browser-workspace tab list\n * and current dispatch mode (`desktop` / `web`) into agent context whenever\n * a `browser` or `web` context is selected.\n *\n * Does not include Steward wallet state — that lived in this provider while\n * `@elizaos/app-browser` owned both surfaces. After consolidation, Steward\n * exposes its own provider from `@elizaos/plugin-steward-app`; an agent that needs\n * both contexts gets both providers, not a coupled one.\n */\n\nimport type { Provider } from \"@elizaos/core\";\nimport {\n getBrowserWorkspaceMode,\n listBrowserWorkspaceTabs,\n} from \"../workspace/browser-workspace.js\";\n\nconst PROVIDER_NAME = \"browser_workspace\";\nconst MAX_TABS_IN_SUMMARY = 8;\n\nexport const browserWorkspaceProvider: Provider = {\n name: PROVIDER_NAME,\n description:\n \"Live summary of the Eliza browser workspace — current dispatch mode and the open tab list, capped to the first 8 tabs.\",\n descriptionCompressed: \"Browser workspace mode + open tab list.\",\n contexts: [\"browser\", \"web\"],\n contextGate: { anyOf: [\"browser\", \"web\"] },\n cacheStable: false,\n cacheScope: \"turn\",\n get: async () => {\n try {\n const mode = getBrowserWorkspaceMode();\n const tabs = await listBrowserWorkspaceTabs();\n const text = JSON.stringify(\n {\n [PROVIDER_NAME]: {\n mode,\n tabCount: tabs.length,\n tabs: tabs.slice(0, MAX_TABS_IN_SUMMARY).map((tab) => ({\n id: tab.id,\n visible: tab.visible,\n url: tab.url,\n title: tab.title,\n })),\n },\n },\n null,\n 2,\n );\n return {\n text,\n data: {\n available: true,\n mode,\n tabs,\n },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n text: JSON.stringify(\n {\n [PROVIDER_NAME]: {\n available: false,\n error: message,\n },\n },\n null,\n 2,\n ),\n data: { available: false, error: message },\n };\n }\n },\n};\n"],"mappings":"AAYA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAEP,MAAM,gBAAgB;AACtB,MAAM,sBAAsB;AAErB,MAAM,2BAAqC;AAAA,EAChD,MAAM;AAAA,EACN,aACE;AAAA,EACF,uBAAuB;AAAA,EACvB,UAAU,CAAC,WAAW,KAAK;AAAA,EAC3B,aAAa,EAAE,OAAO,CAAC,WAAW,KAAK,EAAE;AAAA,EACzC,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,KAAK,YAAY;AACf,QAAI;AACF,YAAM,OAAO,wBAAwB;AACrC,YAAM,OAAO,MAAM,yBAAyB;AAC5C,YAAM,OAAO,KAAK;AAAA,QAChB;AAAA,UACE,CAAC,aAAa,GAAG;AAAA,YACf;AAAA,YACA,UAAU,KAAK;AAAA,YACf,MAAM,KAAK,MAAM,GAAG,mBAAmB,EAAE,IAAI,CAAC,SAAS;AAAA,cACrD,IAAI,IAAI;AAAA,cACR,SAAS,IAAI;AAAA,cACb,KAAK,IAAI;AAAA,cACT,OAAO,IAAI;AAAA,YACb,EAAE;AAAA,UACJ;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,QACA,MAAM;AAAA,UACJ,WAAW;AAAA,UACX;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO;AAAA,QACL,MAAM,KAAK;AAAA,UACT;AAAA,YACE,CAAC,aAAa,GAAG;AAAA,cACf,WAAW;AAAA,cACX,OAAO;AAAA,YACT;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,MAAM,EAAE,WAAW,OAAO,OAAO,QAAQ;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/routes/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,KAAK,YAAY,EAAU,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AA2BrE,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,IAAI,CAAC,eAAe,CAAC;IAC1B,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,KAAK,EAAE;QACL,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;QAC7B,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5E,YAAY,EAAE,CAAC,CAAC,SAAS,MAAM,EAC7B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,OAAO,CAAC,EAAE,mBAAmB,KAC1B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvB,mBAAmB,EAAE,CACnB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,KAAK,EAAE,MAAM,KACV,MAAM,GAAG,IAAI,CAAC;CACpB;AAyID,iBAAS,gBAAgB,CACvB,GAAG,EAAE,yBAAyB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAqBT;AAgQD,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,yBAAyB,GAC7B,OAAO,CAAC,OAAO,CAAC,CA4gBlB;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/routes/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,KAAK,YAAY,EAAU,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AA2BrE,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,IAAI,CAAC,eAAe,CAAC;IAC1B,GAAG,EAAE,IAAI,CAAC,cAAc,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,KAAK,EAAE;QACL,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;QAC7B,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5E,YAAY,EAAE,CAAC,CAAC,SAAS,MAAM,EAC7B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,OAAO,CAAC,EAAE,mBAAmB,KAC1B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvB,mBAAmB,EAAE,CACnB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,KAAK,EAAE,MAAM,KACV,MAAM,GAAG,IAAI,CAAC;CACpB;AA2ID,iBAAS,gBAAgB,CACvB,GAAG,EAAE,yBAAyB,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAqBT;AA8QD,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,yBAAyB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAmjBlB;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}