@jobshimo/browser-link 0.40.0 → 0.42.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.
Files changed (82) hide show
  1. package/README.md +27 -12
  2. package/dist/admin/actions.d.ts +57 -0
  3. package/dist/admin/actions.js +163 -0
  4. package/dist/admin/actions.js.map +1 -0
  5. package/dist/admin/descriptor.d.ts +65 -0
  6. package/dist/admin/descriptor.js +205 -0
  7. package/dist/admin/descriptor.js.map +1 -0
  8. package/dist/admin/i18n.d.ts +90 -0
  9. package/dist/admin/i18n.js +203 -0
  10. package/dist/admin/i18n.js.map +1 -0
  11. package/dist/admin/primary.d.ts +21 -0
  12. package/dist/admin/primary.js +56 -0
  13. package/dist/admin/primary.js.map +1 -0
  14. package/dist/admin/sources.d.ts +22 -0
  15. package/dist/admin/sources.js +82 -0
  16. package/dist/admin/sources.js.map +1 -0
  17. package/dist/bridge/dispatch.js +17 -7
  18. package/dist/bridge/dispatch.js.map +1 -1
  19. package/dist/bridge/ws-bridge.d.ts +65 -3
  20. package/dist/bridge/ws-bridge.js +165 -7
  21. package/dist/bridge/ws-bridge.js.map +1 -1
  22. package/dist/cli.js +6 -2
  23. package/dist/cli.js.map +1 -1
  24. package/dist/commands/doctor.d.ts +24 -0
  25. package/dist/commands/doctor.js +62 -1
  26. package/dist/commands/doctor.js.map +1 -1
  27. package/dist/commands/free-port.d.ts +40 -1
  28. package/dist/commands/free-port.js +72 -7
  29. package/dist/commands/free-port.js.map +1 -1
  30. package/dist/extension/admin-view.d.ts +95 -0
  31. package/dist/extension/admin-view.js +164 -0
  32. package/dist/extension/admin-view.js.map +1 -0
  33. package/dist/extension/background.js +176 -8
  34. package/dist/extension/background.js.map +1 -1
  35. package/dist/extension/manifest.json +1 -1
  36. package/dist/extension/popup.html +113 -0
  37. package/dist/extension/popup.js +282 -1
  38. package/dist/extension/popup.js.map +1 -1
  39. package/dist/extension/repair-policy.d.ts +60 -0
  40. package/dist/extension/repair-policy.js +79 -0
  41. package/dist/extension/repair-policy.js.map +1 -0
  42. package/dist/extension/version-status.d.ts +44 -0
  43. package/dist/extension/version-status.js +60 -0
  44. package/dist/extension/version-status.js.map +1 -0
  45. package/dist/lifecycle/election.d.ts +98 -0
  46. package/dist/lifecycle/election.js +187 -0
  47. package/dist/lifecycle/election.js.map +1 -0
  48. package/dist/lifecycle/processes.d.ts +67 -0
  49. package/dist/lifecycle/processes.js +239 -0
  50. package/dist/lifecycle/processes.js.map +1 -0
  51. package/dist/lifecycle/repair.d.ts +48 -0
  52. package/dist/lifecycle/repair.js +67 -0
  53. package/dist/lifecycle/repair.js.map +1 -0
  54. package/dist/lifecycle/version-endpoint.d.ts +16 -0
  55. package/dist/lifecycle/version-endpoint.js +50 -0
  56. package/dist/lifecycle/version-endpoint.js.map +1 -0
  57. package/dist/manual/topics.js +1 -1
  58. package/dist/manual/topics.js.map +1 -1
  59. package/dist/messages.d.ts +115 -2
  60. package/dist/server.js +104 -1
  61. package/dist/server.js.map +1 -1
  62. package/dist/tools/browser-dispatch.d.ts +8 -0
  63. package/dist/tools/browser-dispatch.js +15 -1
  64. package/dist/tools/browser-dispatch.js.map +1 -1
  65. package/dist/ui/app.d.ts +4 -1
  66. package/dist/ui/app.js +55 -42
  67. package/dist/ui/app.js.map +1 -1
  68. package/dist/ui/screens/free-port.js +4 -2
  69. package/dist/ui/screens/free-port.js.map +1 -1
  70. package/dist/ui/screens/index.d.ts +1 -0
  71. package/dist/ui/screens/index.js +1 -0
  72. package/dist/ui/screens/index.js.map +1 -1
  73. package/dist/ui/screens/menu.d.ts +11 -1
  74. package/dist/ui/screens/menu.js +12 -4
  75. package/dist/ui/screens/menu.js.map +1 -1
  76. package/dist/ui/screens/status.d.ts +19 -0
  77. package/dist/ui/screens/status.js +67 -0
  78. package/dist/ui/screens/status.js.map +1 -0
  79. package/dist/version.d.ts +8 -0
  80. package/dist/version.js +16 -0
  81. package/dist/version.js.map +1 -1
  82. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  import type { Language } from './welcome.js';
2
+ import { type ProcessEntry } from '../lifecycle/processes.js';
2
3
  export interface FreePortResult {
3
4
  /** True when the port was free (nothing to do) OR the owning process was killed. */
4
5
  ok: boolean;
@@ -8,7 +9,36 @@ export interface FreePortResult {
8
9
  imageName: string | null;
9
10
  /** Human-readable message in the requested language. */
10
11
  message: string;
12
+ /** Since 0.41.0: every browser-link process this run tried to stop (the
13
+ * 17529 owner, the 17530 owner and every other live bridge), in kill
14
+ * order. Absent when there was none, so the "already free" result keeps
15
+ * its exact previous shape. */
16
+ processes?: StoppedProcess[];
11
17
  }
18
+ export interface StoppedProcess {
19
+ pid: number;
20
+ /** Short display form, e.g. `node browser-link start`. */
21
+ command: string;
22
+ stopped: boolean;
23
+ }
24
+ /**
25
+ * Best-effort lookup of the PID owning the WS port, cross-platform.
26
+ * Returns null when nothing is listening on the port, when the OS tools
27
+ * needed to find the owner are missing, or when parsing fails.
28
+ *
29
+ * We don't shell out via a string command — `execFileSync` with an argv
30
+ * array avoids any quoting / injection surprises.
31
+ */
32
+ export declare function findPidOnPort(port: number): number | null;
33
+ /**
34
+ * Return the image / executable name of a PID, or null when the lookup
35
+ * fails. We use this as a safety check before killing: we will only kill
36
+ * processes whose image name starts with "node" — refuse to nuke anything
37
+ * else that happens to share the port (some other dev server, malware,
38
+ * a misconfigured tool, etc.).
39
+ */
40
+ export declare function imageNameOf(pid: number): string | null;
41
+ export declare function isNodeImage(image: string | null): boolean;
12
42
  /**
13
43
  * Find the process listening on WS_PORT and try to stop it.
14
44
  *
@@ -17,5 +47,14 @@ export interface FreePortResult {
17
47
  * This stops a stray browser-link from blocking the next MCP client
18
48
  * without ever risking killing some unrelated user process that happens
19
49
  * to share the port.
50
+ *
51
+ * Since 0.41.0 it then stops every OTHER live browser-link bridge too: the
52
+ * 17530 (IPC) owner when it is a node process, and every process whose
53
+ * command line runs this package with no subcommand or `start` (see
54
+ * `lifecycle/processes.ts`; never this process, its ancestors, or short
55
+ * commands such as `doctor`). Each one gets a line under the original
56
+ * message; with nothing else running, the result is exactly what it was.
20
57
  */
21
- export declare function runFreePort(language?: Language): FreePortResult;
58
+ export declare function runFreePort(language?: Language, deps?: {
59
+ listBridgeProcesses?: () => ProcessEntry[];
60
+ }): FreePortResult;
@@ -1,5 +1,7 @@
1
1
  import { execFileSync } from 'node:child_process';
2
2
  import { platform } from 'node:os';
3
+ import { IPC_PORT } from '../bridge/protocol.js';
4
+ import { listBridgeProcesses, shortCommand } from '../lifecycle/processes.js';
3
5
  const WS_HOST = '127.0.0.1';
4
6
  const WS_PORT = 17529;
5
7
  /**
@@ -10,7 +12,7 @@ const WS_PORT = 17529;
10
12
  * We don't shell out via a string command — `execFileSync` with an argv
11
13
  * array avoids any quoting / injection surprises.
12
14
  */
13
- function findPidOnPort(port) {
15
+ export function findPidOnPort(port) {
14
16
  try {
15
17
  if (platform() === 'win32') {
16
18
  // netstat -ano -p TCP produces lines like:
@@ -50,7 +52,7 @@ function findPidOnPort(port) {
50
52
  * else that happens to share the port (some other dev server, malware,
51
53
  * a misconfigured tool, etc.).
52
54
  */
53
- function imageNameOf(pid) {
55
+ export function imageNameOf(pid) {
54
56
  try {
55
57
  if (platform() === 'win32') {
56
58
  // tasklist /FI "PID eq 13212" /FO CSV /NH produces:
@@ -78,7 +80,7 @@ function imageNameOf(pid) {
78
80
  return null;
79
81
  }
80
82
  }
81
- function isNodeImage(image) {
83
+ export function isNodeImage(image) {
82
84
  if (!image)
83
85
  return false;
84
86
  const lc = image.toLowerCase();
@@ -108,6 +110,9 @@ const I18N = {
108
110
  `Refusing to kill it — close that process yourself if you know what it is.`,
109
111
  unknownOwner: (pid) => `✗ Port ${WS_HOST}:${WS_PORT} is held by PID ${pid}, but we could not identify the process. ` +
110
112
  `Refusing to kill it. Close it manually with: taskkill /F /PID ${pid} (Windows) or kill ${pid} (Unix).`,
113
+ othersHeader: 'Other browser-link processes:',
114
+ stopped: '✓ stopped',
115
+ stopFailed: '✗ could not stop',
111
116
  },
112
117
  es: {
113
118
  alreadyFree: `El puerto ${WS_HOST}:${WS_PORT} ya está libre — no hay nada que parar.`,
@@ -117,6 +122,9 @@ const I18N = {
117
122
  `Por seguridad no se mata — cerralo a mano si sabés qué es.`,
118
123
  unknownOwner: (pid) => `✗ El puerto ${WS_HOST}:${WS_PORT} lo tiene el PID ${pid}, pero no pudimos identificar el proceso. ` +
119
124
  `Por seguridad no se mata. Cerralo a mano con: taskkill /F /PID ${pid} (Windows) o kill ${pid} (Unix).`,
125
+ othersHeader: 'Otros procesos de browser-link:',
126
+ stopped: '✓ detenido',
127
+ stopFailed: '✗ no se pudo detener',
120
128
  },
121
129
  };
122
130
  /**
@@ -127,19 +135,75 @@ const I18N = {
127
135
  * This stops a stray browser-link from blocking the next MCP client
128
136
  * without ever risking killing some unrelated user process that happens
129
137
  * to share the port.
138
+ *
139
+ * Since 0.41.0 it then stops every OTHER live browser-link bridge too: the
140
+ * 17530 (IPC) owner when it is a node process, and every process whose
141
+ * command line runs this package with no subcommand or `start` (see
142
+ * `lifecycle/processes.ts`; never this process, its ancestors, or short
143
+ * commands such as `doctor`). Each one gets a line under the original
144
+ * message; with nothing else running, the result is exactly what it was.
130
145
  */
131
- export function runFreePort(language = 'en') {
146
+ export function runFreePort(language = 'en', deps = {}) {
132
147
  const t = I18N[language];
148
+ const primary = stopPortOwner(t);
149
+ const list = (deps.listBridgeProcesses ?? (() => listBridgeProcesses()))();
150
+ const commandOf = (pid, fallback) => {
151
+ const entry = list.find((p) => p.pid === pid);
152
+ return entry ? shortCommand(entry.command) : (fallback ?? '?');
153
+ };
154
+ const processes = [];
155
+ if (primary.pid !== null && primary.attempted) {
156
+ processes.push({
157
+ pid: primary.pid,
158
+ command: commandOf(primary.pid, primary.imageName),
159
+ stopped: primary.ok,
160
+ });
161
+ }
162
+ // Everything else: the IPC owner (node only, same safety rule) and every
163
+ // other bridge, each once, never the 17529 owner a second time.
164
+ const seen = new Set(primary.pid !== null ? [primary.pid] : []);
165
+ const others = [];
166
+ const ipcPid = findPidOnPort(IPC_PORT);
167
+ if (ipcPid !== null && !seen.has(ipcPid) && isNodeImage(imageNameOf(ipcPid))) {
168
+ seen.add(ipcPid);
169
+ others.push({ pid: ipcPid, command: commandOf(ipcPid, 'node') });
170
+ }
171
+ for (const p of list) {
172
+ if (seen.has(p.pid))
173
+ continue;
174
+ seen.add(p.pid);
175
+ others.push({ pid: p.pid, command: shortCommand(p.command) });
176
+ }
177
+ const lines = [primary.message];
178
+ if (others.length > 0)
179
+ lines.push(t.othersHeader);
180
+ let allStopped = true;
181
+ for (const o of others) {
182
+ const stopped = killByPid(o.pid);
183
+ allStopped &&= stopped;
184
+ processes.push({ pid: o.pid, command: o.command, stopped });
185
+ lines.push(` PID ${o.pid} ${o.command} ${stopped ? t.stopped : t.stopFailed}`);
186
+ }
187
+ return {
188
+ ok: primary.ok && allStopped,
189
+ pid: primary.pid,
190
+ imageName: primary.imageName,
191
+ message: lines.join('\n'),
192
+ ...(processes.length > 0 ? { processes } : {}),
193
+ };
194
+ }
195
+ /** The original 17529 rule, unchanged: only a node owner is killed. */
196
+ function stopPortOwner(t) {
133
197
  const pid = findPidOnPort(WS_PORT);
134
198
  if (pid == null) {
135
- return { ok: true, pid: null, imageName: null, message: t.alreadyFree };
199
+ return { ok: true, pid: null, imageName: null, message: t.alreadyFree, attempted: false };
136
200
  }
137
201
  const image = imageNameOf(pid);
138
202
  if (image == null) {
139
- return { ok: false, pid, imageName: null, message: t.unknownOwner(pid) };
203
+ return { ok: false, pid, imageName: null, message: t.unknownOwner(pid), attempted: false };
140
204
  }
141
205
  if (!isNodeImage(image)) {
142
- return { ok: false, pid, imageName: image, message: t.notNode(pid, image) };
206
+ return { ok: false, pid, imageName: image, message: t.notNode(pid, image), attempted: false };
143
207
  }
144
208
  const killed = killByPid(pid);
145
209
  return {
@@ -147,6 +211,7 @@ export function runFreePort(language = 'en') {
147
211
  pid,
148
212
  imageName: image,
149
213
  message: killed ? t.killed(pid) : t.killFailed(pid),
214
+ attempted: true,
150
215
  };
151
216
  }
152
217
  //# sourceMappingURL=free-port.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"free-port.js","sourceRoot":"","sources":["../../src/commands/free-port.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"free-port.js","sourceRoot":"","sources":["../../src/commands/free-port.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Render model for the popup's Admin section.
3
+ *
4
+ * The server describes its administration state and actions as data, with
5
+ * every label already localised (`AdminState`). This module turns that data
6
+ * into flat view rows the popup can render without knowing what any item
7
+ * means, and owns the confirm flow for disk-writing actions as a tiny state
8
+ * machine. Pure: no DOM, no chrome.* — so it is tested, unlike popup.ts.
9
+ */
10
+ import type { AdminActionResult, AdminItemKind, AdminOption, AdminSection, AdminState, AdminUiStrings } from '@browser-link/shared';
11
+ /** Used when the server sent no `ui` block, or when no server answered at all
12
+ * (no tab connected), so the popup still has words to show. */
13
+ export declare const FALLBACK_ADMIN_UI: AdminUiStrings;
14
+ export type AdminControl = 'none' | 'toggle' | 'select' | 'button' | 'link';
15
+ export interface AdminRow {
16
+ sectionId: AdminSection['id'];
17
+ sectionTitle: string;
18
+ itemId: string;
19
+ kind: AdminItemKind;
20
+ label: string;
21
+ description?: string;
22
+ /** Human-readable current value; empty for buttons. */
23
+ valueText: string;
24
+ control: AdminControl;
25
+ /** Toggle only: the current state. */
26
+ checked?: boolean;
27
+ /** Select only: the current option value. */
28
+ selected?: string;
29
+ options?: AdminOption[];
30
+ /** Link only: an http(s) URL, never anything else. */
31
+ href?: string;
32
+ disabled?: boolean;
33
+ hint?: string;
34
+ requiresRestart?: boolean;
35
+ }
36
+ /** What an admin request carries, minus the wire envelope. */
37
+ export interface AdminRequest {
38
+ id: string;
39
+ value?: string | number | boolean;
40
+ confirm?: boolean;
41
+ }
42
+ /** Flatten the server state into rows, section then item order. A malformed
43
+ * state yields no rows: the popup shows an empty section, never a crash. */
44
+ export declare function buildAdminRows(state: AdminState | null | undefined): AdminRow[];
45
+ /** The server's UI strings, or the English fallback. */
46
+ export declare function adminUi(state: AdminState | null | undefined): AdminUiStrings;
47
+ /** `not-connected` is the background's own code for "no open socket"; it
48
+ * reads as the server's (or fallback) sentence. Anything else is shown as is. */
49
+ export declare function describeAdminError(error: string, ui: AdminUiStrings): string;
50
+ export type AdminNextAction = {
51
+ type: 'confirm';
52
+ preview: string;
53
+ confirmLabel: string;
54
+ cancelLabel: string;
55
+ resend: AdminRequest & {
56
+ confirm: true;
57
+ };
58
+ } | {
59
+ type: 'applied';
60
+ message: string;
61
+ output?: string[];
62
+ refresh: true;
63
+ } | {
64
+ type: 'error';
65
+ message: string;
66
+ };
67
+ /** Decide what the popup does with one action result. */
68
+ export declare function nextAction(result: AdminActionResult, request: AdminRequest, ui: AdminUiStrings): AdminNextAction;
69
+ export type ConfirmState = {
70
+ phase: 'idle';
71
+ } | {
72
+ phase: 'confirming';
73
+ preview: string;
74
+ pendingRequest: AdminRequest & {
75
+ confirm: true;
76
+ };
77
+ } | {
78
+ phase: 'applied';
79
+ message: string;
80
+ output?: string[];
81
+ } | {
82
+ phase: 'error';
83
+ message: string;
84
+ };
85
+ export type ConfirmEvent = {
86
+ type: 'result';
87
+ request: AdminRequest;
88
+ result: AdminActionResult;
89
+ ui: AdminUiStrings;
90
+ } | {
91
+ type: 'cancel';
92
+ };
93
+ export declare function initialConfirmState(): ConfirmState;
94
+ /** idle → confirming(preview, pendingRequest) → applied | error; cancel → idle. */
95
+ export declare function reduceConfirm(_state: ConfirmState, event: ConfirmEvent): ConfirmState;
@@ -0,0 +1,164 @@
1
+ /** Used when the server sent no `ui` block, or when no server answered at all
2
+ * (no tab connected), so the popup still has words to show. */
3
+ export const FALLBACK_ADMIN_UI = {
4
+ language: 'en',
5
+ confirm: 'Confirm',
6
+ cancel: 'Cancel',
7
+ apply: 'Apply',
8
+ notConnected: 'Connect a tab to administer the server',
9
+ restartRequired: 'Restart the server to apply this change',
10
+ changed: 'Changed',
11
+ };
12
+ const EMPTY_VALUE = '—';
13
+ function stringifyValue(value) {
14
+ if (value === undefined || value === null || value === '')
15
+ return EMPTY_VALUE;
16
+ if (typeof value === 'boolean')
17
+ return value ? 'on' : 'off';
18
+ return String(value);
19
+ }
20
+ function isHttpUrl(value) {
21
+ if (typeof value !== 'string')
22
+ return false;
23
+ try {
24
+ const url = new URL(value);
25
+ return url.protocol === 'https:' || url.protocol === 'http:';
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ function rowFor(section, item) {
32
+ const row = {
33
+ sectionId: section.id,
34
+ sectionTitle: section.title,
35
+ itemId: item.id,
36
+ kind: item.kind,
37
+ label: item.label,
38
+ valueText: stringifyValue(item.value),
39
+ control: 'none',
40
+ };
41
+ if (item.description !== undefined)
42
+ row.description = item.description;
43
+ switch (item.kind) {
44
+ case 'toggle': {
45
+ row.control = 'toggle';
46
+ if (typeof item.value === 'boolean') {
47
+ row.checked = item.value;
48
+ }
49
+ else {
50
+ row.checked = false;
51
+ row.disabled = true;
52
+ }
53
+ break;
54
+ }
55
+ case 'select': {
56
+ row.control = 'select';
57
+ const options = Array.isArray(item.options) ? item.options : [];
58
+ row.options = options;
59
+ const current = item.value === undefined || item.value === null ? '' : String(item.value);
60
+ row.selected = current;
61
+ const match = options.find((o) => o.value === current);
62
+ if (match)
63
+ row.valueText = match.label;
64
+ if (options.length === 0)
65
+ row.disabled = true;
66
+ break;
67
+ }
68
+ case 'button': {
69
+ row.control = 'button';
70
+ row.valueText = '';
71
+ break;
72
+ }
73
+ case 'link': {
74
+ // Only http(s) becomes clickable: the URL comes off a socket, and a
75
+ // `javascript:` href in an extension page is not something to render.
76
+ if (isHttpUrl(item.value)) {
77
+ row.control = 'link';
78
+ row.href = item.value;
79
+ }
80
+ break;
81
+ }
82
+ default:
83
+ break;
84
+ }
85
+ if (item.hint !== undefined)
86
+ row.hint = item.hint;
87
+ if (item.requiresRestart === true)
88
+ row.requiresRestart = true;
89
+ return row;
90
+ }
91
+ /** Flatten the server state into rows, section then item order. A malformed
92
+ * state yields no rows: the popup shows an empty section, never a crash. */
93
+ export function buildAdminRows(state) {
94
+ if (!state || !Array.isArray(state.sections))
95
+ return [];
96
+ const rows = [];
97
+ // The state arrives off a socket as JSON: entries are typed loosely here so
98
+ // the guards below are checks the compiler keeps, not dead code.
99
+ const sections = state.sections;
100
+ for (const section of sections) {
101
+ if (!section || !Array.isArray(section.items))
102
+ continue;
103
+ const items = section.items;
104
+ for (const item of items) {
105
+ if (!item || typeof item.id !== 'string')
106
+ continue;
107
+ rows.push(rowFor(section, item));
108
+ }
109
+ }
110
+ return rows;
111
+ }
112
+ /** The server's UI strings, or the English fallback. */
113
+ export function adminUi(state) {
114
+ return state?.ui ?? FALLBACK_ADMIN_UI;
115
+ }
116
+ /** `not-connected` is the background's own code for "no open socket"; it
117
+ * reads as the server's (or fallback) sentence. Anything else is shown as is. */
118
+ export function describeAdminError(error, ui) {
119
+ return error === 'not-connected' ? ui.notConnected : error;
120
+ }
121
+ /** Decide what the popup does with one action result. */
122
+ export function nextAction(result, request, ui) {
123
+ if (!result.ok)
124
+ return { type: 'error', message: describeAdminError(result.error, ui) };
125
+ if (!result.applied) {
126
+ const resend = { id: request.id, confirm: true };
127
+ if (request.value !== undefined)
128
+ resend.value = request.value;
129
+ return {
130
+ type: 'confirm',
131
+ preview: result.preview,
132
+ confirmLabel: ui.confirm,
133
+ cancelLabel: ui.cancel,
134
+ resend,
135
+ };
136
+ }
137
+ const applied = {
138
+ type: 'applied',
139
+ message: result.requiresRestart === true ? ui.restartRequired : ui.changed,
140
+ refresh: true,
141
+ };
142
+ if (Array.isArray(result.output))
143
+ applied.output = result.output;
144
+ return applied;
145
+ }
146
+ export function initialConfirmState() {
147
+ return { phase: 'idle' };
148
+ }
149
+ /** idle → confirming(preview, pendingRequest) → applied | error; cancel → idle. */
150
+ export function reduceConfirm(_state, event) {
151
+ if (event.type === 'cancel')
152
+ return { phase: 'idle' };
153
+ const action = nextAction(event.result, event.request, event.ui);
154
+ if (action.type === 'confirm') {
155
+ return { phase: 'confirming', preview: action.preview, pendingRequest: action.resend };
156
+ }
157
+ if (action.type === 'error')
158
+ return { phase: 'error', message: action.message };
159
+ const applied = { phase: 'applied', message: action.message };
160
+ if (action.output)
161
+ applied.output = action.output;
162
+ return applied;
163
+ }
164
+ //# sourceMappingURL=admin-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-view.js","sourceRoot":"","sources":["../src/admin-view.ts"],"names":[],"mappings":"AAmBA;+DAC+D;AAC/D,MAAM,CAAC,MAAM,iBAAiB,GAAmB;IAC/C,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,YAAY,EAAE,wCAAwC;IACtD,eAAe,EAAE,yCAAyC;IAC1D,OAAO,EAAE,SAAS;CACnB,CAAC;AAiCF,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB,SAAS,cAAc,CAAC,KAAyB;IAC/C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,WAAW,CAAC;IAC9E,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IAC5D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,OAAqB,EAAE,IAAe;IACpD,MAAM,GAAG,GAAa;QACpB,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,YAAY,EAAE,OAAO,CAAC,KAAK;QAC3B,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC;QACrC,OAAO,EAAE,MAAM;KAChB,CAAC;IACF,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS;QAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IAEvE,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,GAAG,CAAC,OAAO,GAAG,QAAQ,CAAC;YACvB,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACpC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,OAAO,GAAG,KAAK,CAAC;gBACpB,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;YACtB,CAAC;YACD,MAAM;QACR,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,GAAG,CAAC,OAAO,GAAG,QAAQ,CAAC;YACvB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;YACtB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1F,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC;YACvB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;YACvD,IAAI,KAAK;gBAAE,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;YACvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC;YAC9C,MAAM;QACR,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,GAAG,CAAC,OAAO,GAAG,QAAQ,CAAC;YACvB,GAAG,CAAC,SAAS,GAAG,EAAE,CAAC;YACnB,MAAM;QACR,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,oEAAoE;YACpE,sEAAsE;YACtE,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1B,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC;gBACrB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;YACxB,CAAC;YACD,MAAM;QACR,CAAC;QACD;YACE,MAAM;IACV,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IAClD,IAAI,IAAI,CAAC,eAAe,KAAK,IAAI;QAAE,GAAG,CAAC,eAAe,GAAG,IAAI,CAAC;IAC9D,OAAO,GAAG,CAAC;AACb,CAAC;AAED;4EAC4E;AAC5E,MAAM,UAAU,cAAc,CAAC,KAAoC;IACjE,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACxD,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,4EAA4E;IAC5E,iEAAiE;IACjE,MAAM,QAAQ,GAAG,KAAK,CAAC,QAA+C,CAAC;IACvE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,SAAS;QACxD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAyC,CAAC;QAChE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ;gBAAE,SAAS;YACnD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,OAAO,CAAC,KAAoC;IAC1D,OAAO,KAAK,EAAE,EAAE,IAAI,iBAAiB,CAAC;AACxC,CAAC;AAED;iFACiF;AACjF,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,EAAkB;IAClE,OAAO,KAAK,KAAK,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7D,CAAC;AAaD,yDAAyD;AACzD,MAAM,UAAU,UAAU,CACxB,MAAyB,EACzB,OAAqB,EACrB,EAAkB;IAElB,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;IACxF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAqC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACnF,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC9D,OAAO;YACL,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,YAAY,EAAE,EAAE,CAAC,OAAO;YACxB,WAAW,EAAE,EAAE,CAAC,MAAM;YACtB,MAAM;SACP,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAoB;QAC/B,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,MAAM,CAAC,eAAe,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO;QAC1E,OAAO,EAAE,IAAI;KACd,CAAC;IACF,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;QAAE,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IACjE,OAAO,OAAO,CAAC;AACjB,CAAC;AAYD,MAAM,UAAU,mBAAmB;IACjC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,aAAa,CAAC,MAAoB,EAAE,KAAmB;IACrE,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACtD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IACjE,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACzF,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IAChF,MAAM,OAAO,GAAiB,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IAC5E,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,OAAO,OAAO,CAAC;AACjB,CAAC"}