@kizenapps/cli 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{devtools-PDXM3L35.js → devtools-LZRAH4XS.js} +30 -7
- package/dist/devtools-LZRAH4XS.js.map +1 -0
- package/dist/index.js +645 -554
- package/dist/index.js.map +1 -1
- package/dist/viewer/assets/AppDetailPage-BJrg5Wsz.js +1 -0
- package/dist/viewer/assets/BootstrapContext-D3lhzWap.js +1 -0
- package/dist/viewer/assets/Card-CPMAuqAb.js +1 -0
- package/dist/viewer/assets/ConfigurationPage-D8I8rWjF.js +1 -0
- package/dist/viewer/assets/CredentialsContext-BLZX6RwF.js +1 -0
- package/dist/viewer/assets/DevSidebar-BiROAoKF.js +1 -0
- package/dist/viewer/assets/SandboxPage-ByixszHi.js +1 -0
- package/dist/viewer/assets/SidebarContext-Byo6PYOF.js +1 -0
- package/dist/viewer/assets/VersionsPage-BKul6bXI.js +1 -0
- package/dist/viewer/assets/{fa-core-DAYjf9Yn.js → fa-core-mHW_3JUd.js} +1 -1
- package/dist/viewer/assets/index-BoSQQwMQ.css +2 -0
- package/dist/viewer/assets/index-Bomh3C3X.js +5 -0
- package/dist/viewer/assets/{react-C90crogl.js → react-D_K8ni3_.js} +1 -1
- package/dist/viewer/assets/useObjectLookups-Cx6A7PGj.js +14 -0
- package/dist/viewer/assets/validIcons-TcFXfn-E.js +1 -0
- package/dist/viewer/index.html +8 -5
- package/package.json +10 -6
- package/dist/chromium-extension/manifest.json +0 -17
- package/dist/chromium-extension/rules.json +0 -17
- package/dist/chunk-4OYGMEFM.js +0 -3675
- package/dist/chunk-4OYGMEFM.js.map +0 -1
- package/dist/chunk-5WPGAZLP.js +0 -6136
- package/dist/chunk-5WPGAZLP.js.map +0 -1
- package/dist/chunk-6XGFZ4W5.js +0 -3673
- package/dist/chunk-6XGFZ4W5.js.map +0 -1
- package/dist/chunk-KMKDY2I6.js +0 -46
- package/dist/chunk-KMKDY2I6.js.map +0 -1
- package/dist/chunk-NNDSADQG.js +0 -3641
- package/dist/chunk-NNDSADQG.js.map +0 -1
- package/dist/devtools-HNR7DD7Q.js +0 -68
- package/dist/devtools-HNR7DD7Q.js.map +0 -1
- package/dist/devtools-HW3UQAHH.js +0 -69
- package/dist/devtools-HW3UQAHH.js.map +0 -1
- package/dist/devtools-KXIXZGBY.js +0 -64
- package/dist/devtools-KXIXZGBY.js.map +0 -1
- package/dist/devtools-PDXM3L35.js.map +0 -1
- package/dist/devtools-SDEASRYI.js +0 -66
- package/dist/devtools-SDEASRYI.js.map +0 -1
- package/dist/devtools-XBEEGBQ4.js +0 -66
- package/dist/devtools-XBEEGBQ4.js.map +0 -1
- package/dist/dist-4P5P64FK.js +0 -8474
- package/dist/dist-4P5P64FK.js.map +0 -1
- package/dist/dist-AVHDSU4X.js +0 -137
- package/dist/dist-AVHDSU4X.js.map +0 -1
- package/dist/electron/icon.png +0 -0
- package/dist/electron/main.js +0 -201
- package/dist/electron/main.js.map +0 -1
- package/dist/electron/preload.cjs +0 -9
- package/dist/gzip-size-SHZBT5GU.js +0 -139
- package/dist/gzip-size-SHZBT5GU.js.map +0 -1
- package/dist/nwjs/shell/icon.png +0 -0
- package/dist/nwjs/shell/index.html +0 -200
- package/dist/nwjs/shell/package.json +0 -16
- package/dist/viewer/assets/fa-core-BU3ZZt7W.js +0 -558
- package/dist/viewer/assets/fa-core-Ff8SZmm_.js +0 -558
- package/dist/viewer/assets/index-47Vh9MH0.js +0 -17
- package/dist/viewer/assets/index-6uunWX8M.js +0 -17
- package/dist/viewer/assets/index-B48OpZHg.js +0 -17
- package/dist/viewer/assets/index-BFfw7eD7.js +0 -17
- package/dist/viewer/assets/index-BFyUUb06.js +0 -17
- package/dist/viewer/assets/index-BL-Yu7Bf.js +0 -17
- package/dist/viewer/assets/index-BUmv8vz7.js +0 -17
- package/dist/viewer/assets/index-BZ4HmEz8.js +0 -17
- package/dist/viewer/assets/index-BZIXccTd.js +0 -17
- package/dist/viewer/assets/index-Bk9hnfnO.js +0 -17
- package/dist/viewer/assets/index-C0SIHm9A.js +0 -17
- package/dist/viewer/assets/index-CDd-WK6Y.js +0 -17
- package/dist/viewer/assets/index-CDxQqP40.js +0 -17
- package/dist/viewer/assets/index-CGJzvpL5.js +0 -17
- package/dist/viewer/assets/index-CIarX3Lt.js +0 -17
- package/dist/viewer/assets/index-CIfVP45E.js +0 -17
- package/dist/viewer/assets/index-CJeb7uFu.css +0 -2
- package/dist/viewer/assets/index-CbwLb2S_.js +0 -17
- package/dist/viewer/assets/index-CsfWgoID.js +0 -17
- package/dist/viewer/assets/index-CvWmkIY5.js +0 -17
- package/dist/viewer/assets/index-Cy-weKfG.css +0 -2
- package/dist/viewer/assets/index-Cym12l2M.js +0 -17
- package/dist/viewer/assets/index-D0W0oANg.js +0 -17
- package/dist/viewer/assets/index-DCPtqd3W.js +0 -17
- package/dist/viewer/assets/index-DF_zYdLw.js +0 -17
- package/dist/viewer/assets/index-DGqxQcUx.js +0 -17
- package/dist/viewer/assets/index-DK0OVb7V.js +0 -17
- package/dist/viewer/assets/index-DKjVFdzw.js +0 -17
- package/dist/viewer/assets/index-DLhj0I_2.js +0 -17
- package/dist/viewer/assets/index-DPS_ZjbM.js +0 -17
- package/dist/viewer/assets/index-DSbHkhcS.js +0 -17
- package/dist/viewer/assets/index-DTbmNtEU.js +0 -17
- package/dist/viewer/assets/index-DUYd6RpI.js +0 -17
- package/dist/viewer/assets/index-DZwYe1wZ.css +0 -2
- package/dist/viewer/assets/index-DkRokbYc.js +0 -17
- package/dist/viewer/assets/index-DtOWzkR5.js +0 -17
- package/dist/viewer/assets/index-DuvXujkm.js +0 -17
- package/dist/viewer/assets/index-Dv0mX-oM.js +0 -17
- package/dist/viewer/assets/index-DyXisBY9.css +0 -2
- package/dist/viewer/assets/index-Nm1xKWTO.js +0 -17
- package/dist/viewer/assets/index-ZBdAq6dF.js +0 -17
- package/dist/viewer/assets/index-ZOxL_JJZ.js +0 -17
- package/dist/viewer/assets/index-kMMOwjlY.js +0 -17
- package/dist/viewer/assets/index-ov2oU6RI.js +0 -17
- package/dist/viewer/assets/index-uF6u0kT8.js +0 -17
- package/dist/viewer/assets/index-xbDHMSaa.css +0 -2
- package/dist/viewer/assets/react-D7PmSb6e.js +0 -9
- package/dist/viewer/assets/react-DIjeYlvh.js +0 -9
- /package/dist/viewer/assets/{fa-pro-icons-D4afj0tU.js → fa-pro-icons-CIQGXozY.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -8,8 +8,8 @@ import { createElement } from "react";
|
|
|
8
8
|
import { render } from "ink";
|
|
9
9
|
|
|
10
10
|
// src/ui/BuildUI.tsx
|
|
11
|
-
import { useEffect, useState } from "react";
|
|
12
|
-
import { Box as
|
|
11
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
12
|
+
import { Box as Box3, Text as Text4, useApp } from "ink";
|
|
13
13
|
|
|
14
14
|
// src/lib/runBuild.ts
|
|
15
15
|
import { mkdir, writeFile } from "fs/promises";
|
|
@@ -88,9 +88,26 @@ async function runBuild(pluginDir, outputDir, onStep) {
|
|
|
88
88
|
})).sort((a, b) => b.version.localeCompare(a.version, void 0, { numeric: true })) : [];
|
|
89
89
|
return serializePlugin(plugin, allReleaseNotes);
|
|
90
90
|
});
|
|
91
|
-
|
|
91
|
+
const jsonStr = JSON.stringify(bundle, null, 2);
|
|
92
|
+
const bundleSize = Buffer.byteLength(jsonStr, "utf-8");
|
|
93
|
+
await writeFile(join2(outputDir, "bundle.json"), jsonStr, "utf-8");
|
|
94
|
+
return { bundleSize };
|
|
92
95
|
}
|
|
93
96
|
|
|
97
|
+
// src/lib/formatBytes.ts
|
|
98
|
+
function formatBytes(n) {
|
|
99
|
+
if (n < 1024) {
|
|
100
|
+
return `${String(n)} B`;
|
|
101
|
+
}
|
|
102
|
+
if (n < 1024 * 1024) {
|
|
103
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
104
|
+
}
|
|
105
|
+
return `${(n / (1024 * 1024)).toFixed(2)} MB`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/ui/AppHeader.tsx
|
|
109
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
110
|
+
|
|
94
111
|
// src/ui/Logo.tsx
|
|
95
112
|
import { Box, Text } from "ink";
|
|
96
113
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -116,8 +133,20 @@ var LOGO_LINES = [
|
|
|
116
133
|
];
|
|
117
134
|
var Logo = () => /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: LOGO_LINES.map((line, i) => /* @__PURE__ */ jsx(Text, { color: "cyan", children: line }, i)) });
|
|
118
135
|
|
|
119
|
-
// src/ui/
|
|
136
|
+
// src/ui/AppHeader.tsx
|
|
120
137
|
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
138
|
+
var AppHeader = ({ marginBottom = 0 }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
139
|
+
/* @__PURE__ */ jsx2(Logo, {}),
|
|
140
|
+
/* @__PURE__ */ jsxs(Box2, { flexDirection: "column", marginTop: 1, marginBottom, children: [
|
|
141
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
142
|
+
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2500".repeat(24) })
|
|
143
|
+
] })
|
|
144
|
+
] });
|
|
145
|
+
|
|
146
|
+
// src/ui/Spinner.tsx
|
|
147
|
+
import { useEffect, useState } from "react";
|
|
148
|
+
import { Text as Text3 } from "ink";
|
|
149
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
121
150
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
122
151
|
var Spinner = () => {
|
|
123
152
|
const [frame, setFrame] = useState(0);
|
|
@@ -129,8 +158,11 @@ var Spinner = () => {
|
|
|
129
158
|
clearInterval(id);
|
|
130
159
|
};
|
|
131
160
|
}, []);
|
|
132
|
-
return /* @__PURE__ */
|
|
161
|
+
return /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: SPINNER_FRAMES[frame] ?? "\u280B" });
|
|
133
162
|
};
|
|
163
|
+
|
|
164
|
+
// src/ui/BuildUI.tsx
|
|
165
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
134
166
|
var STEPS = [
|
|
135
167
|
"creating-dir",
|
|
136
168
|
"reading-files",
|
|
@@ -147,10 +179,12 @@ var STEP_LABELS = {
|
|
|
147
179
|
};
|
|
148
180
|
var BuildUI = ({ outputDir, pluginDir }) => {
|
|
149
181
|
const app = useApp();
|
|
150
|
-
const [step, setStep] =
|
|
151
|
-
const [errorMessage, setErrorMessage] =
|
|
152
|
-
|
|
153
|
-
|
|
182
|
+
const [step, setStep] = useState2("creating-dir");
|
|
183
|
+
const [errorMessage, setErrorMessage] = useState2(null);
|
|
184
|
+
const [bundleSize, setBundleSize] = useState2(null);
|
|
185
|
+
useEffect2(() => {
|
|
186
|
+
void runBuild(pluginDir, outputDir, setStep).then(({ bundleSize: size }) => {
|
|
187
|
+
setBundleSize(size);
|
|
154
188
|
setStep("done");
|
|
155
189
|
app.exit();
|
|
156
190
|
}).catch((err) => {
|
|
@@ -163,32 +197,32 @@ var BuildUI = ({ outputDir, pluginDir }) => {
|
|
|
163
197
|
const currentIndex = STEPS.indexOf(step);
|
|
164
198
|
const isError = step === "error";
|
|
165
199
|
const isDone = step === "done";
|
|
166
|
-
return /* @__PURE__ */
|
|
167
|
-
/* @__PURE__ */
|
|
168
|
-
/* @__PURE__ */
|
|
169
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
170
|
-
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2500".repeat(24) })
|
|
171
|
-
] }),
|
|
172
|
-
/* @__PURE__ */ jsxs(Box2, { flexDirection: "column", gap: 0, children: [
|
|
200
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, children: [
|
|
201
|
+
/* @__PURE__ */ jsx4(AppHeader, { marginBottom: 1 }),
|
|
202
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
173
203
|
STEPS.map((s, i) => {
|
|
174
204
|
const isActive = step === s;
|
|
175
205
|
const isStepDone = isDone || currentIndex > i;
|
|
176
206
|
const isFailed = isError && i === currentIndex;
|
|
177
|
-
return /* @__PURE__ */
|
|
207
|
+
return /* @__PURE__ */ jsx4(Box3, { gap: 1, children: isFailed ? /* @__PURE__ */ jsxs2(Text4, { color: "red", children: [
|
|
178
208
|
"\u2717 ",
|
|
179
209
|
STEP_LABELS[s]
|
|
180
|
-
] }) : isStepDone ? /* @__PURE__ */
|
|
210
|
+
] }) : isStepDone ? /* @__PURE__ */ jsxs2(Text4, { color: "green", children: [
|
|
181
211
|
"\u2713 ",
|
|
182
212
|
STEP_LABELS[s]
|
|
183
|
-
] }) : isActive ? /* @__PURE__ */
|
|
184
|
-
/* @__PURE__ */
|
|
185
|
-
/* @__PURE__ */
|
|
186
|
-
] }) : /* @__PURE__ */
|
|
213
|
+
] }) : isActive ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
214
|
+
/* @__PURE__ */ jsx4(Spinner, {}),
|
|
215
|
+
/* @__PURE__ */ jsx4(Text4, { children: STEP_LABELS[s] })
|
|
216
|
+
] }) : /* @__PURE__ */ jsxs2(Text4, { dimColor: true, children: [
|
|
187
217
|
" ",
|
|
188
218
|
STEP_LABELS[s]
|
|
189
219
|
] }) }, s);
|
|
190
220
|
}),
|
|
191
|
-
|
|
221
|
+
isDone && bundleSize !== null && /* @__PURE__ */ jsx4(Box3, { marginTop: 1, gap: 1, children: /* @__PURE__ */ jsxs2(Text4, { color: "green", children: [
|
|
222
|
+
"\u2713 bundle.json \u2014 ",
|
|
223
|
+
formatBytes(bundleSize)
|
|
224
|
+
] }) }),
|
|
225
|
+
errorMessage !== null && /* @__PURE__ */ jsx4(Box3, { marginTop: 1, borderStyle: "single", borderColor: "red", paddingX: 1, children: /* @__PURE__ */ jsx4(Text4, { color: "red", children: errorMessage }) })
|
|
192
226
|
] })
|
|
193
227
|
] });
|
|
194
228
|
};
|
|
@@ -227,22 +261,350 @@ import { createElement as createElement2 } from "react";
|
|
|
227
261
|
import { render as render2 } from "ink";
|
|
228
262
|
|
|
229
263
|
// src/ui/DevUI.tsx
|
|
230
|
-
import { useCallback as
|
|
231
|
-
import { Box as
|
|
232
|
-
import {
|
|
233
|
-
import { access, readFile as readFile5 } from "fs/promises";
|
|
264
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useRef, useState as useState5 } from "react";
|
|
265
|
+
import { Box as Box5, Text as Text6, useInput as useInput2 } from "ink";
|
|
266
|
+
import { watch } from "fs";
|
|
234
267
|
import { createServer } from "http";
|
|
235
|
-
import {
|
|
236
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
268
|
+
import { join as join8 } from "path";
|
|
237
269
|
import { WebSocketServer } from "ws";
|
|
238
270
|
|
|
271
|
+
// src/server/requestHandler.ts
|
|
272
|
+
import { createReadStream } from "fs";
|
|
273
|
+
import { access, readFile as readFile4 } from "fs/promises";
|
|
274
|
+
import { dirname as dirname2, extname, join as join6 } from "path";
|
|
275
|
+
import { fileURLToPath } from "url";
|
|
276
|
+
|
|
277
|
+
// src/lib/proxyCache.ts
|
|
278
|
+
function createProxyCache(options = {}) {
|
|
279
|
+
const cache = /* @__PURE__ */ new Map();
|
|
280
|
+
const { onChange } = options;
|
|
281
|
+
const emitChange = () => {
|
|
282
|
+
onChange?.(cache.size);
|
|
283
|
+
};
|
|
284
|
+
return {
|
|
285
|
+
get(key, fetcher) {
|
|
286
|
+
const existing = cache.get(key);
|
|
287
|
+
if (existing !== void 0) {
|
|
288
|
+
return existing.then((response) => ({ response, fromCache: true }));
|
|
289
|
+
}
|
|
290
|
+
const pending = fetcher().then(async (response) => {
|
|
291
|
+
const headers = Object.fromEntries(response.headers);
|
|
292
|
+
delete headers["content-encoding"];
|
|
293
|
+
delete headers["content-length"];
|
|
294
|
+
return {
|
|
295
|
+
status: response.status,
|
|
296
|
+
headers,
|
|
297
|
+
body: Buffer.from(await response.arrayBuffer())
|
|
298
|
+
};
|
|
299
|
+
}).catch((error) => {
|
|
300
|
+
cache.delete(key);
|
|
301
|
+
emitChange();
|
|
302
|
+
throw error;
|
|
303
|
+
});
|
|
304
|
+
cache.set(key, pending);
|
|
305
|
+
emitChange();
|
|
306
|
+
return pending.then((response) => {
|
|
307
|
+
if (response.status >= 400) {
|
|
308
|
+
cache.delete(key);
|
|
309
|
+
emitChange();
|
|
310
|
+
}
|
|
311
|
+
return { response, fromCache: false };
|
|
312
|
+
});
|
|
313
|
+
},
|
|
314
|
+
clear() {
|
|
315
|
+
cache.clear();
|
|
316
|
+
emitChange();
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/lib/constants.ts
|
|
322
|
+
var LOG_LIMIT = 50;
|
|
323
|
+
var LOG_DISPLAY = 8;
|
|
324
|
+
var FILE_WATCH_DEBOUNCE_MS = 150;
|
|
325
|
+
var MIME_TYPES = {
|
|
326
|
+
".html": "text/html; charset=utf-8",
|
|
327
|
+
".js": "application/javascript; charset=utf-8",
|
|
328
|
+
".mjs": "application/javascript; charset=utf-8",
|
|
329
|
+
".css": "text/css; charset=utf-8",
|
|
330
|
+
".png": "image/png",
|
|
331
|
+
".jpg": "image/jpeg",
|
|
332
|
+
".svg": "image/svg+xml",
|
|
333
|
+
".ico": "image/x-icon",
|
|
334
|
+
".json": "application/json; charset=utf-8",
|
|
335
|
+
".woff": "font/woff",
|
|
336
|
+
".woff2": "font/woff2",
|
|
337
|
+
".ttf": "font/ttf",
|
|
338
|
+
".map": "application/json"
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
// src/lib/credentials.ts
|
|
342
|
+
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir2, writeFile as writeFile2 } from "fs/promises";
|
|
343
|
+
import { homedir } from "os";
|
|
344
|
+
import { dirname, join as join4 } from "path";
|
|
345
|
+
var ENVIRONMENTS = ["go", "fmo", "staging", "integration", "test1"];
|
|
346
|
+
var GLOBAL_CREDENTIALS_DIR = join4(homedir(), ".kizenappbuilder");
|
|
347
|
+
var GLOBAL_CREDENTIALS_PATH = join4(GLOBAL_CREDENTIALS_DIR, "credentials.json");
|
|
348
|
+
var DEFAULT_PROFILE_NAME = "credentials";
|
|
349
|
+
function isValidEnvironment(value) {
|
|
350
|
+
return ENVIRONMENTS.includes(value);
|
|
351
|
+
}
|
|
352
|
+
function parseCredentials(raw) {
|
|
353
|
+
if (typeof raw !== "object" || raw === null) {
|
|
354
|
+
throw new Error("Credentials must be a JSON object");
|
|
355
|
+
}
|
|
356
|
+
const obj = raw;
|
|
357
|
+
const env = obj.environment;
|
|
358
|
+
return {
|
|
359
|
+
apiKey: typeof obj.apiKey === "string" ? obj.apiKey : "",
|
|
360
|
+
userId: typeof obj.userId === "string" ? obj.userId : "",
|
|
361
|
+
businessId: typeof obj.businessId === "string" ? obj.businessId : "",
|
|
362
|
+
environment: isValidEnvironment(env) ? env : "go"
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
async function loadCredentialsFromFile(filePath) {
|
|
366
|
+
const content = await readFile2(filePath, "utf-8");
|
|
367
|
+
return parseCredentials(JSON.parse(content));
|
|
368
|
+
}
|
|
369
|
+
async function loadGlobalCredentials() {
|
|
370
|
+
try {
|
|
371
|
+
return await loadCredentialsFromFile(GLOBAL_CREDENTIALS_PATH);
|
|
372
|
+
} catch {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async function saveGlobalCredentials(credentials) {
|
|
377
|
+
await mkdir2(dirname(GLOBAL_CREDENTIALS_PATH), { recursive: true });
|
|
378
|
+
await writeFile2(GLOBAL_CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), "utf-8");
|
|
379
|
+
}
|
|
380
|
+
function getProfilePath(name) {
|
|
381
|
+
return join4(GLOBAL_CREDENTIALS_DIR, `${name}.json`);
|
|
382
|
+
}
|
|
383
|
+
async function listCredentialProfiles() {
|
|
384
|
+
const profiles = [
|
|
385
|
+
{ name: DEFAULT_PROFILE_NAME, path: GLOBAL_CREDENTIALS_PATH, isDefault: true }
|
|
386
|
+
];
|
|
387
|
+
try {
|
|
388
|
+
const entries = await readdir2(GLOBAL_CREDENTIALS_DIR);
|
|
389
|
+
for (const entry of entries) {
|
|
390
|
+
if (!entry.endsWith(".json")) {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
const name = entry.slice(0, -5);
|
|
394
|
+
if (name === DEFAULT_PROFILE_NAME) {
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
profiles.push({ name, path: join4(GLOBAL_CREDENTIALS_DIR, entry), isDefault: false });
|
|
398
|
+
}
|
|
399
|
+
} catch {
|
|
400
|
+
}
|
|
401
|
+
return profiles;
|
|
402
|
+
}
|
|
403
|
+
async function saveCredentialProfile(name, credentials) {
|
|
404
|
+
if (name === DEFAULT_PROFILE_NAME) {
|
|
405
|
+
await saveGlobalCredentials(credentials);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
await mkdir2(GLOBAL_CREDENTIALS_DIR, { recursive: true });
|
|
409
|
+
await writeFile2(getProfilePath(name), JSON.stringify(credentials, null, 2), "utf-8");
|
|
410
|
+
}
|
|
411
|
+
async function loadCredentialProfile(name) {
|
|
412
|
+
try {
|
|
413
|
+
return await loadCredentialsFromFile(getProfilePath(name));
|
|
414
|
+
} catch {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// src/lib/config.ts
|
|
420
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
421
|
+
import { join as join5 } from "path";
|
|
422
|
+
async function loadConfig(outputDir) {
|
|
423
|
+
try {
|
|
424
|
+
const content = await readFile3(join5(outputDir, "config.json"), "utf-8");
|
|
425
|
+
return JSON.parse(content);
|
|
426
|
+
} catch {
|
|
427
|
+
return {};
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
async function saveConfig(outputDir, config) {
|
|
431
|
+
await mkdir3(outputDir, { recursive: true });
|
|
432
|
+
await writeFile3(join5(outputDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/server/requestHandler.ts
|
|
436
|
+
function proxyLogEntryToString(entry) {
|
|
437
|
+
if (entry.kind === "info") {
|
|
438
|
+
return entry.message;
|
|
439
|
+
}
|
|
440
|
+
const cache = entry.fromCache ? " [cache]" : "";
|
|
441
|
+
return `${entry.method} ${entry.url} \u2192 ${String(entry.status)}${cache}`;
|
|
442
|
+
}
|
|
443
|
+
function getViewerPath() {
|
|
444
|
+
const filename = fileURLToPath(import.meta.url);
|
|
445
|
+
return join6(dirname2(filename), "viewer");
|
|
446
|
+
}
|
|
447
|
+
async function fileExists(filePath) {
|
|
448
|
+
try {
|
|
449
|
+
await access(filePath);
|
|
450
|
+
return true;
|
|
451
|
+
} catch {
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast, onProxyCacheChange) {
|
|
456
|
+
const proxyCache = createProxyCache({ onChange: onProxyCacheChange });
|
|
457
|
+
return (req, res) => {
|
|
458
|
+
void (async () => {
|
|
459
|
+
const url = req.url ?? "/";
|
|
460
|
+
try {
|
|
461
|
+
createServerLog(`Received request: ${url}`);
|
|
462
|
+
if (url === "/api/credentials") {
|
|
463
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
464
|
+
res.end(credentialsRef.current !== null ? JSON.stringify(credentialsRef.current) : "{}");
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (url === "/api/credential-profiles" && req.method === "GET") {
|
|
468
|
+
const profiles = await listCredentialProfiles();
|
|
469
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
470
|
+
res.end(JSON.stringify({ profiles, active: activeProfileRef.current }));
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (url === "/api/credentials/switch" && req.method === "POST") {
|
|
474
|
+
const chunks = [];
|
|
475
|
+
for await (const chunk of req) {
|
|
476
|
+
chunks.push(chunk);
|
|
477
|
+
}
|
|
478
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}");
|
|
479
|
+
const profileName = body.profile;
|
|
480
|
+
const creds = profileName === void 0 || profileName === "" ? await loadGlobalCredentials() : await loadCredentialProfile(profileName);
|
|
481
|
+
if (creds !== null) {
|
|
482
|
+
credentialsRef.current = creds;
|
|
483
|
+
activeProfileRef.current = profileName ?? void 0;
|
|
484
|
+
const active = activeProfileRef.current;
|
|
485
|
+
await saveConfig(outputDir, {
|
|
486
|
+
credentialMode: "global",
|
|
487
|
+
...active !== void 0 && { activeCredentialProfile: active }
|
|
488
|
+
});
|
|
489
|
+
broadcast({ type: "credentials-updated", credentials: creds });
|
|
490
|
+
}
|
|
491
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
492
|
+
res.end(JSON.stringify({ ok: creds !== null }));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (url === "/api/bundle") {
|
|
496
|
+
const bundlePath = join6(process.cwd(), ".kizenapp", "bundle.json");
|
|
497
|
+
try {
|
|
498
|
+
const content = await readFile4(bundlePath, "utf-8");
|
|
499
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
500
|
+
res.end(content);
|
|
501
|
+
} catch {
|
|
502
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
503
|
+
res.end("{}");
|
|
504
|
+
}
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
if (url === "/api/proxy-cache/clear") {
|
|
508
|
+
proxyCache.clear();
|
|
509
|
+
createProxyLog({ kind: "info", message: "Proxy cache cleared" });
|
|
510
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
511
|
+
res.end('{"ok":true}');
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
if (url.startsWith("/api/proxy")) {
|
|
515
|
+
const proxyTarget = req.headers["x-proxy-target"];
|
|
516
|
+
if (typeof proxyTarget !== "string") {
|
|
517
|
+
res.writeHead(400);
|
|
518
|
+
res.end("Missing x-proxy-target header");
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const upstreamPath = url.slice("/api/proxy".length) || "/";
|
|
522
|
+
const upstreamUrl = `${proxyTarget}${upstreamPath}`;
|
|
523
|
+
const method = req.method ?? "GET";
|
|
524
|
+
const chunks = [];
|
|
525
|
+
for await (const chunk of req) {
|
|
526
|
+
chunks.push(chunk);
|
|
527
|
+
}
|
|
528
|
+
const { host, "x-proxy-target": _drop, ...forwardHeaders } = req.headers;
|
|
529
|
+
if (method === "GET") {
|
|
530
|
+
const cacheKey = `GET::${upstreamUrl}`;
|
|
531
|
+
const { response: cached, fromCache } = await proxyCache.get(
|
|
532
|
+
cacheKey,
|
|
533
|
+
() => fetch(upstreamUrl, {
|
|
534
|
+
method: "GET",
|
|
535
|
+
headers: forwardHeaders
|
|
536
|
+
})
|
|
537
|
+
);
|
|
538
|
+
createProxyLog({
|
|
539
|
+
kind: "request",
|
|
540
|
+
method: "GET",
|
|
541
|
+
status: cached.status,
|
|
542
|
+
fromCache,
|
|
543
|
+
url: upstreamPath
|
|
544
|
+
});
|
|
545
|
+
res.writeHead(cached.status, cached.headers);
|
|
546
|
+
res.end(cached.body);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
|
|
550
|
+
const resolvedBody = body && body.length > 0 ? body : void 0;
|
|
551
|
+
const upstream = await fetch(upstreamUrl, {
|
|
552
|
+
method,
|
|
553
|
+
headers: forwardHeaders,
|
|
554
|
+
...resolvedBody !== void 0 && { body: resolvedBody }
|
|
555
|
+
});
|
|
556
|
+
createProxyLog({
|
|
557
|
+
kind: "request",
|
|
558
|
+
method,
|
|
559
|
+
status: upstream.status,
|
|
560
|
+
fromCache: false,
|
|
561
|
+
url: upstreamPath
|
|
562
|
+
});
|
|
563
|
+
const responseHeaders = Object.fromEntries(upstream.headers);
|
|
564
|
+
delete responseHeaders["content-encoding"];
|
|
565
|
+
delete responseHeaders["content-length"];
|
|
566
|
+
res.writeHead(upstream.status, responseHeaders);
|
|
567
|
+
res.end(Buffer.from(await upstream.arrayBuffer()));
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
const rawPath = url === "/" ? "/index.html" : url;
|
|
571
|
+
const filePath = join6(viewerPath, rawPath);
|
|
572
|
+
const resolvedPath = await fileExists(filePath) ? filePath : join6(viewerPath, "index.html");
|
|
573
|
+
const ext = extname(resolvedPath);
|
|
574
|
+
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
575
|
+
res.writeHead(200, { "Content-Type": mimeType });
|
|
576
|
+
createReadStream(resolvedPath).pipe(res);
|
|
577
|
+
} catch (err) {
|
|
578
|
+
if (url.startsWith("/api/proxy")) {
|
|
579
|
+
createProxyLog({
|
|
580
|
+
kind: "request",
|
|
581
|
+
method: req.method ?? "GET",
|
|
582
|
+
status: 502,
|
|
583
|
+
fromCache: false,
|
|
584
|
+
url: url.slice("/api/proxy".length) || "/"
|
|
585
|
+
});
|
|
586
|
+
} else {
|
|
587
|
+
createProxyLog({
|
|
588
|
+
kind: "info",
|
|
589
|
+
message: `Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
if (!res.headersSent) {
|
|
593
|
+
res.writeHead(502);
|
|
594
|
+
res.end("Bad Gateway");
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
})();
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
239
601
|
// src/chrome/launcher.ts
|
|
240
602
|
import { launch } from "chrome-launcher";
|
|
241
603
|
import { createRequire } from "module";
|
|
242
604
|
import { mkdirSync } from "fs";
|
|
243
|
-
import { readFile as
|
|
244
|
-
import { dirname, join as
|
|
245
|
-
import { fileURLToPath } from "url";
|
|
605
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
606
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
607
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
246
608
|
var CDP = createRequire(import.meta.url)("chrome-remote-interface");
|
|
247
609
|
var CSP_HEADERS = /* @__PURE__ */ new Set([
|
|
248
610
|
"content-security-policy",
|
|
@@ -259,30 +621,44 @@ function isKizenUrl(url) {
|
|
|
259
621
|
}
|
|
260
622
|
}
|
|
261
623
|
function parseProp(prop) {
|
|
262
|
-
if (prop.type === "number")
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (prop.type === "
|
|
624
|
+
if (prop.type === "number") {
|
|
625
|
+
return Number(prop.value);
|
|
626
|
+
}
|
|
627
|
+
if (prop.type === "boolean") {
|
|
628
|
+
return prop.value === "true";
|
|
629
|
+
}
|
|
630
|
+
if (prop.type === "undefined") {
|
|
631
|
+
return void 0;
|
|
632
|
+
}
|
|
633
|
+
if (prop.type === "object" && prop.value === "null") {
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
266
636
|
if (prop.type === "object" && prop.valuePreview) {
|
|
267
637
|
const { valuePreview } = prop;
|
|
268
638
|
if (valuePreview.subtype === "array") {
|
|
269
639
|
return valuePreview.properties.filter((p) => /^\d+$/.test(p.name)).sort((a, b) => parseInt(a.name) - parseInt(b.name)).map(parseProp);
|
|
270
640
|
}
|
|
271
641
|
const obj = {};
|
|
272
|
-
for (const p of valuePreview.properties)
|
|
642
|
+
for (const p of valuePreview.properties) {
|
|
643
|
+
obj[p.name] = parseProp(p);
|
|
644
|
+
}
|
|
273
645
|
return obj;
|
|
274
646
|
}
|
|
275
647
|
return prop.value ?? `[${prop.type}]`;
|
|
276
648
|
}
|
|
277
649
|
function serializeArg(arg) {
|
|
278
|
-
if (arg.value !== void 0)
|
|
650
|
+
if (arg.value !== void 0) {
|
|
651
|
+
return arg.value;
|
|
652
|
+
}
|
|
279
653
|
if (arg.preview) {
|
|
280
654
|
const { preview } = arg;
|
|
281
655
|
if (preview.subtype === "array") {
|
|
282
656
|
return preview.properties.filter((p) => /^\d+$/.test(p.name)).sort((a, b) => parseInt(a.name) - parseInt(b.name)).map(parseProp);
|
|
283
657
|
}
|
|
284
658
|
const obj = {};
|
|
285
|
-
for (const prop of preview.properties)
|
|
659
|
+
for (const prop of preview.properties) {
|
|
660
|
+
obj[prop.name] = parseProp(prop);
|
|
661
|
+
}
|
|
286
662
|
return obj;
|
|
287
663
|
}
|
|
288
664
|
return arg.description ?? `[${arg.type}]`;
|
|
@@ -296,7 +672,9 @@ async function serializeArgAsync(client, arg) {
|
|
|
296
672
|
returnByValue: true
|
|
297
673
|
});
|
|
298
674
|
const val = result.result.value;
|
|
299
|
-
if (typeof val === "string")
|
|
675
|
+
if (typeof val === "string") {
|
|
676
|
+
return JSON.parse(val);
|
|
677
|
+
}
|
|
300
678
|
} catch {
|
|
301
679
|
}
|
|
302
680
|
}
|
|
@@ -304,8 +682,8 @@ async function serializeArgAsync(client, arg) {
|
|
|
304
682
|
}
|
|
305
683
|
async function installDockIcon(client) {
|
|
306
684
|
try {
|
|
307
|
-
const iconPath =
|
|
308
|
-
const icon = await
|
|
685
|
+
const iconPath = join7(dirname3(fileURLToPath2(import.meta.url)), "viewer", "icon.png");
|
|
686
|
+
const icon = await readFile5(iconPath);
|
|
309
687
|
await client.Browser.setDockTile({ image: icon.toString("base64") });
|
|
310
688
|
} catch {
|
|
311
689
|
}
|
|
@@ -313,9 +691,9 @@ async function installDockIcon(client) {
|
|
|
313
691
|
async function launchChromeViewer(opts) {
|
|
314
692
|
mkdirSync(opts.userDataDir, { recursive: true });
|
|
315
693
|
const chrome = await launch({
|
|
316
|
-
startingUrl: `http://localhost:${opts.port}`,
|
|
694
|
+
startingUrl: `http://localhost:${String(opts.port)}`,
|
|
317
695
|
chromeFlags: [
|
|
318
|
-
`--app=http://localhost:${opts.port}`,
|
|
696
|
+
`--app=http://localhost:${String(opts.port)}`,
|
|
319
697
|
"--no-first-run",
|
|
320
698
|
"--no-default-browser-check",
|
|
321
699
|
"--disable-extensions"
|
|
@@ -326,7 +704,7 @@ async function launchChromeViewer(opts) {
|
|
|
326
704
|
});
|
|
327
705
|
let client = null;
|
|
328
706
|
let cookieTimer = null;
|
|
329
|
-
|
|
707
|
+
const cdpPort = chrome.port;
|
|
330
708
|
for (let attempt = 0; attempt < 10; attempt++) {
|
|
331
709
|
await new Promise((r) => setTimeout(r, 300));
|
|
332
710
|
try {
|
|
@@ -335,14 +713,18 @@ async function launchChromeViewer(opts) {
|
|
|
335
713
|
} catch {
|
|
336
714
|
if (attempt === 9) {
|
|
337
715
|
return {
|
|
338
|
-
kill: () =>
|
|
716
|
+
kill: () => {
|
|
717
|
+
chrome.kill();
|
|
718
|
+
}
|
|
339
719
|
};
|
|
340
720
|
}
|
|
341
721
|
}
|
|
342
722
|
}
|
|
343
723
|
if (!client) {
|
|
344
724
|
return {
|
|
345
|
-
kill: () =>
|
|
725
|
+
kill: () => {
|
|
726
|
+
chrome.kill();
|
|
727
|
+
}
|
|
346
728
|
};
|
|
347
729
|
}
|
|
348
730
|
const c = client;
|
|
@@ -357,13 +739,17 @@ async function launchChromeViewer(opts) {
|
|
|
357
739
|
void (async () => {
|
|
358
740
|
const params = rawParams;
|
|
359
741
|
const { requestId, request, responseHeaders, responseStatusCode } = params;
|
|
360
|
-
const url = request
|
|
742
|
+
const url = request.url;
|
|
361
743
|
const filtered = [];
|
|
362
744
|
for (const h of responseHeaders ?? []) {
|
|
363
|
-
if (CSP_HEADERS.has(h.name.toLowerCase()))
|
|
745
|
+
if (CSP_HEADERS.has(h.name.toLowerCase())) {
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
364
748
|
if (h.name.toLowerCase() === "set-cookie" && isKizenUrl(url)) {
|
|
365
749
|
const patched = h.value.split("\n").map((cookie) => {
|
|
366
|
-
if (!/SameSite=/i.test(cookie))
|
|
750
|
+
if (!/SameSite=/i.test(cookie)) {
|
|
751
|
+
return cookie + "; SameSite=None; Secure";
|
|
752
|
+
}
|
|
367
753
|
return cookie.replace(/SameSite=\w+/i, "SameSite=None");
|
|
368
754
|
}).join("\n");
|
|
369
755
|
filtered.push({ name: h.name, value: patched });
|
|
@@ -393,8 +779,12 @@ async function launchChromeViewer(opts) {
|
|
|
393
779
|
try {
|
|
394
780
|
const { cookies } = await c.Network.getAllCookies();
|
|
395
781
|
for (const cookie of cookies) {
|
|
396
|
-
if (!isKizenUrl(`https://${cookie.domain ?? ""}`))
|
|
397
|
-
|
|
782
|
+
if (!isKizenUrl(`https://${cookie.domain ?? ""}`)) {
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
if (cookie.sameSite === "None") {
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
398
788
|
const raw = cookie.domain ?? "";
|
|
399
789
|
const bare = raw.startsWith(".") ? raw.slice(1) : raw;
|
|
400
790
|
await c.Network.setCookie({
|
|
@@ -437,173 +827,63 @@ async function launchChromeViewer(opts) {
|
|
|
437
827
|
c.on("Runtime.consoleAPICalled", (rawParams) => {
|
|
438
828
|
void (async () => {
|
|
439
829
|
const { type, args } = rawParams;
|
|
440
|
-
if (args[0]?.type === "string" && String(args[0].value).includes("Chrome Security"))
|
|
441
|
-
|
|
442
|
-
const serialized = await Promise.all(args.map((arg) => serializeArgAsync(c, arg)));
|
|
443
|
-
opts.broadcast({ type: "console-message", level, args: serialized });
|
|
444
|
-
})().catch(() => {
|
|
445
|
-
});
|
|
446
|
-
});
|
|
447
|
-
const kill = () => {
|
|
448
|
-
if (cookieTimer !== null) clearInterval(cookieTimer);
|
|
449
|
-
try {
|
|
450
|
-
void c.close();
|
|
451
|
-
} catch {
|
|
452
|
-
}
|
|
453
|
-
chrome.kill();
|
|
454
|
-
};
|
|
455
|
-
return { kill };
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// src/lib/proxyCache.ts
|
|
459
|
-
function createProxyCache() {
|
|
460
|
-
const cache = /* @__PURE__ */ new Map();
|
|
461
|
-
return {
|
|
462
|
-
get(key, fetcher) {
|
|
463
|
-
const existing = cache.get(key);
|
|
464
|
-
if (existing !== void 0) {
|
|
465
|
-
return existing.then((response) => ({ response, fromCache: true }));
|
|
466
|
-
}
|
|
467
|
-
const pending = fetcher().then(async (response) => {
|
|
468
|
-
const headers = Object.fromEntries(response.headers);
|
|
469
|
-
delete headers["content-encoding"];
|
|
470
|
-
delete headers["content-length"];
|
|
471
|
-
return {
|
|
472
|
-
status: response.status,
|
|
473
|
-
headers,
|
|
474
|
-
body: Buffer.from(await response.arrayBuffer())
|
|
475
|
-
};
|
|
476
|
-
}).catch((error) => {
|
|
477
|
-
cache.delete(key);
|
|
478
|
-
throw error;
|
|
479
|
-
});
|
|
480
|
-
cache.set(key, pending);
|
|
481
|
-
return pending.then((response) => ({ response, fromCache: false }));
|
|
482
|
-
},
|
|
483
|
-
clear() {
|
|
484
|
-
cache.clear();
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// src/lib/credentials.ts
|
|
490
|
-
import { mkdir as mkdir2, readFile as readFile3, readdir as readdir2, writeFile as writeFile2 } from "fs/promises";
|
|
491
|
-
import { homedir } from "os";
|
|
492
|
-
import { dirname as dirname2, join as join5 } from "path";
|
|
493
|
-
var ENVIRONMENTS = ["go", "fmo", "staging", "integration", "test1"];
|
|
494
|
-
var GLOBAL_CREDENTIALS_DIR = join5(homedir(), ".kizenappbuilder");
|
|
495
|
-
var GLOBAL_CREDENTIALS_PATH = join5(GLOBAL_CREDENTIALS_DIR, "credentials.json");
|
|
496
|
-
var DEFAULT_PROFILE_NAME = "credentials";
|
|
497
|
-
function isValidEnvironment(value) {
|
|
498
|
-
return ENVIRONMENTS.includes(value);
|
|
499
|
-
}
|
|
500
|
-
function parseCredentials(raw) {
|
|
501
|
-
if (typeof raw !== "object" || raw === null) {
|
|
502
|
-
throw new Error("Credentials must be a JSON object");
|
|
503
|
-
}
|
|
504
|
-
const obj = raw;
|
|
505
|
-
const env = obj.environment;
|
|
506
|
-
return {
|
|
507
|
-
apiKey: typeof obj.apiKey === "string" ? obj.apiKey : "",
|
|
508
|
-
userId: typeof obj.userId === "string" ? obj.userId : "",
|
|
509
|
-
businessId: typeof obj.businessId === "string" ? obj.businessId : "",
|
|
510
|
-
environment: isValidEnvironment(env) ? env : "go"
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
async function loadCredentialsFromFile(filePath) {
|
|
514
|
-
const content = await readFile3(filePath, "utf-8");
|
|
515
|
-
return parseCredentials(JSON.parse(content));
|
|
516
|
-
}
|
|
517
|
-
async function loadGlobalCredentials() {
|
|
518
|
-
try {
|
|
519
|
-
return await loadCredentialsFromFile(GLOBAL_CREDENTIALS_PATH);
|
|
520
|
-
} catch {
|
|
521
|
-
return null;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
async function saveGlobalCredentials(credentials) {
|
|
525
|
-
await mkdir2(dirname2(GLOBAL_CREDENTIALS_PATH), { recursive: true });
|
|
526
|
-
await writeFile2(GLOBAL_CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), "utf-8");
|
|
527
|
-
}
|
|
528
|
-
function getProfilePath(name) {
|
|
529
|
-
return join5(GLOBAL_CREDENTIALS_DIR, `${name}.json`);
|
|
530
|
-
}
|
|
531
|
-
async function listCredentialProfiles() {
|
|
532
|
-
const profiles = [
|
|
533
|
-
{ name: DEFAULT_PROFILE_NAME, path: GLOBAL_CREDENTIALS_PATH, isDefault: true }
|
|
534
|
-
];
|
|
535
|
-
try {
|
|
536
|
-
const entries = await readdir2(GLOBAL_CREDENTIALS_DIR);
|
|
537
|
-
for (const entry of entries) {
|
|
538
|
-
if (!entry.endsWith(".json")) {
|
|
539
|
-
continue;
|
|
540
|
-
}
|
|
541
|
-
const name = entry.slice(0, -5);
|
|
542
|
-
if (name === DEFAULT_PROFILE_NAME) {
|
|
543
|
-
continue;
|
|
830
|
+
if (args[0]?.type === "string" && String(args[0].value).includes("Chrome Security")) {
|
|
831
|
+
return;
|
|
544
832
|
}
|
|
545
|
-
|
|
833
|
+
const level = type === "warning" ? "warn" : ["log", "warn", "error", "info"].includes(type) ? type : "log";
|
|
834
|
+
const serialized = await Promise.all(args.map((arg) => serializeArgAsync(c, arg)));
|
|
835
|
+
opts.broadcast({ type: "console-message", level, args: serialized });
|
|
836
|
+
})().catch(() => {
|
|
837
|
+
});
|
|
838
|
+
});
|
|
839
|
+
const kill = () => {
|
|
840
|
+
clearInterval(cookieTimer);
|
|
841
|
+
try {
|
|
842
|
+
void c.close();
|
|
843
|
+
} catch {
|
|
546
844
|
}
|
|
547
|
-
|
|
548
|
-
}
|
|
549
|
-
return
|
|
550
|
-
}
|
|
551
|
-
async function saveCredentialProfile(name, credentials) {
|
|
552
|
-
if (name === DEFAULT_PROFILE_NAME) {
|
|
553
|
-
await saveGlobalCredentials(credentials);
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
await mkdir2(GLOBAL_CREDENTIALS_DIR, { recursive: true });
|
|
557
|
-
await writeFile2(getProfilePath(name), JSON.stringify(credentials, null, 2), "utf-8");
|
|
558
|
-
}
|
|
559
|
-
async function loadCredentialProfile(name) {
|
|
560
|
-
try {
|
|
561
|
-
return await loadCredentialsFromFile(getProfilePath(name));
|
|
562
|
-
} catch {
|
|
563
|
-
return null;
|
|
564
|
-
}
|
|
845
|
+
chrome.kill();
|
|
846
|
+
};
|
|
847
|
+
return { kill };
|
|
565
848
|
}
|
|
566
849
|
|
|
567
|
-
// src/
|
|
568
|
-
import {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
async function saveConfig(outputDir, config) {
|
|
579
|
-
await mkdir3(outputDir, { recursive: true });
|
|
580
|
-
await writeFile3(join6(outputDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
850
|
+
// src/hooks/useLogHistory.ts
|
|
851
|
+
import { useCallback, useState as useState3 } from "react";
|
|
852
|
+
function useLogHistory(limit) {
|
|
853
|
+
const [history, setHistory] = useState3([]);
|
|
854
|
+
const append = useCallback(
|
|
855
|
+
(message) => {
|
|
856
|
+
setHistory((h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-limit));
|
|
857
|
+
},
|
|
858
|
+
[limit]
|
|
859
|
+
);
|
|
860
|
+
return [history, append];
|
|
581
861
|
}
|
|
582
862
|
|
|
583
863
|
// src/ui/CredentialSetupUI.tsx
|
|
584
|
-
import { useCallback, useEffect as
|
|
585
|
-
import { Box as
|
|
586
|
-
import { jsx as
|
|
864
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useState as useState4 } from "react";
|
|
865
|
+
import { Box as Box4, Text as Text5, useInput } from "ink";
|
|
866
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
587
867
|
var FIELDS = ["apiKey", "userId", "businessId"];
|
|
588
868
|
var FIELD_LABELS = {
|
|
589
869
|
apiKey: "API Key",
|
|
590
870
|
userId: "User ID",
|
|
591
871
|
businessId: "Business ID"
|
|
592
872
|
};
|
|
593
|
-
var Hint = ({ text }) => /* @__PURE__ */
|
|
873
|
+
var Hint = ({ text }) => /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: text });
|
|
594
874
|
var CredentialSetupUI = ({
|
|
595
875
|
initialMode,
|
|
596
876
|
showProfileManager,
|
|
597
877
|
onComplete,
|
|
598
878
|
onCancel
|
|
599
879
|
}) => {
|
|
600
|
-
const [phase, setPhase] =
|
|
880
|
+
const [phase, setPhase] = useState4(
|
|
601
881
|
initialMode === "global" && !showProfileManager ? { type: "loading" } : initialMode === "global" && showProfileManager ? { type: "profile-loading" } : { type: "mode-select", cursor: 0 }
|
|
602
882
|
);
|
|
603
|
-
const [inputBuffer, setInputBuffer] =
|
|
604
|
-
const [error, setError] =
|
|
605
|
-
const [activeProfileName, setActiveProfileName] =
|
|
606
|
-
const handleModeChosen =
|
|
883
|
+
const [inputBuffer, setInputBuffer] = useState4("");
|
|
884
|
+
const [error, setError] = useState4(null);
|
|
885
|
+
const [activeProfileName, setActiveProfileName] = useState4(void 0);
|
|
886
|
+
const handleModeChosen = useCallback2(
|
|
607
887
|
(mode) => {
|
|
608
888
|
if (mode === "local") {
|
|
609
889
|
onComplete({ mode: "local", credentials: null });
|
|
@@ -613,7 +893,7 @@ var CredentialSetupUI = ({
|
|
|
613
893
|
},
|
|
614
894
|
[onComplete]
|
|
615
895
|
);
|
|
616
|
-
const handleProfileChosen =
|
|
896
|
+
const handleProfileChosen = useCallback2(async (profile) => {
|
|
617
897
|
if (profile === null) {
|
|
618
898
|
setPhase({ type: "profile-loading" });
|
|
619
899
|
const profiles = await listCredentialProfiles();
|
|
@@ -626,7 +906,7 @@ var CredentialSetupUI = ({
|
|
|
626
906
|
const envCursor2 = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;
|
|
627
907
|
setPhase({ type: "creds-entry", field: 0, values: existing ?? {}, envCursor: envCursor2 });
|
|
628
908
|
}, []);
|
|
629
|
-
const handleSave =
|
|
909
|
+
const handleSave = useCallback2(
|
|
630
910
|
async (values2, envCursor2) => {
|
|
631
911
|
const environment = ENVIRONMENTS[envCursor2] ?? "go";
|
|
632
912
|
const credentials = {
|
|
@@ -767,16 +1047,16 @@ var CredentialSetupUI = ({
|
|
|
767
1047
|
}
|
|
768
1048
|
}
|
|
769
1049
|
});
|
|
770
|
-
const loadProfileList =
|
|
1050
|
+
const loadProfileList = useCallback2(async () => {
|
|
771
1051
|
const profiles = await listCredentialProfiles();
|
|
772
1052
|
setPhase({ type: "profile-select", profiles, cursor: 0 });
|
|
773
1053
|
}, []);
|
|
774
|
-
|
|
1054
|
+
useEffect3(() => {
|
|
775
1055
|
if (phase.type === "profile-loading") {
|
|
776
1056
|
void loadProfileList();
|
|
777
1057
|
}
|
|
778
1058
|
}, [phase.type, loadProfileList]);
|
|
779
|
-
|
|
1059
|
+
useEffect3(() => {
|
|
780
1060
|
if (initialMode === "global" && !showProfileManager) {
|
|
781
1061
|
void (async () => {
|
|
782
1062
|
const existing = await loadGlobalCredentials();
|
|
@@ -785,14 +1065,14 @@ var CredentialSetupUI = ({
|
|
|
785
1065
|
})();
|
|
786
1066
|
}
|
|
787
1067
|
}, []);
|
|
788
|
-
|
|
1068
|
+
useEffect3(() => {
|
|
789
1069
|
if (phase.type === "creds-entry" && phase.field === 0) {
|
|
790
1070
|
setInputBuffer(phase.values.apiKey ?? "");
|
|
791
1071
|
}
|
|
792
1072
|
}, [phase.type]);
|
|
793
1073
|
if (phase.type === "loading" || phase.type === "saving" || phase.type === "profile-loading") {
|
|
794
1074
|
const label = phase.type === "saving" ? "Saving credentials\u2026" : phase.type === "profile-loading" ? "Loading profiles\u2026" : "Loading credentials\u2026";
|
|
795
|
-
return /* @__PURE__ */
|
|
1075
|
+
return /* @__PURE__ */ jsx5(Box4, { paddingY: 1, paddingX: 2, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: label }) });
|
|
796
1076
|
}
|
|
797
1077
|
if (phase.type === "done") {
|
|
798
1078
|
return null;
|
|
@@ -802,49 +1082,41 @@ var CredentialSetupUI = ({
|
|
|
802
1082
|
{ label: "Global", desc: `~/.kizenappbuilder/credentials.json`, mode: "global" },
|
|
803
1083
|
{ label: "Local", desc: "Enter credentials in the browser dev tools", mode: "local" }
|
|
804
1084
|
];
|
|
805
|
-
return /* @__PURE__ */
|
|
806
|
-
/* @__PURE__ */
|
|
807
|
-
/* @__PURE__ */
|
|
808
|
-
/* @__PURE__ */
|
|
809
|
-
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
810
|
-
] }),
|
|
811
|
-
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
812
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Credential mode" }),
|
|
1085
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
1086
|
+
/* @__PURE__ */ jsx5(AppHeader, {}),
|
|
1087
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 0, children: [
|
|
1088
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: "Credential mode" }),
|
|
813
1089
|
options.map((opt, i) => {
|
|
814
1090
|
const selected = phase.cursor === i;
|
|
815
|
-
return /* @__PURE__ */
|
|
816
|
-
/* @__PURE__ */
|
|
817
|
-
/* @__PURE__ */
|
|
818
|
-
/* @__PURE__ */
|
|
1091
|
+
return /* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1092
|
+
/* @__PURE__ */ jsx5(Text5, { ...selected && { color: "cyan" }, children: selected ? "\u276F" : " " }),
|
|
1093
|
+
/* @__PURE__ */ jsx5(Text5, { bold: selected, ...selected && { color: "cyan" }, children: opt.label }),
|
|
1094
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: opt.desc })
|
|
819
1095
|
] }, opt.mode);
|
|
820
1096
|
})
|
|
821
1097
|
] }),
|
|
822
|
-
/* @__PURE__ */
|
|
1098
|
+
/* @__PURE__ */ jsx5(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit" })
|
|
823
1099
|
] });
|
|
824
1100
|
}
|
|
825
1101
|
if (phase.type === "profile-select") {
|
|
826
1102
|
const { profiles, cursor } = phase;
|
|
827
1103
|
const addNewIdx = profiles.length;
|
|
828
|
-
return /* @__PURE__ */
|
|
829
|
-
/* @__PURE__ */
|
|
830
|
-
/* @__PURE__ */
|
|
831
|
-
/* @__PURE__ */
|
|
832
|
-
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
833
|
-
] }),
|
|
834
|
-
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
835
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Credential profiles" }),
|
|
1104
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
1105
|
+
/* @__PURE__ */ jsx5(AppHeader, {}),
|
|
1106
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 0, children: [
|
|
1107
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: "Credential profiles" }),
|
|
836
1108
|
profiles.map((profile, i) => {
|
|
837
1109
|
const selected = cursor === i;
|
|
838
|
-
return /* @__PURE__ */
|
|
839
|
-
/* @__PURE__ */
|
|
840
|
-
/* @__PURE__ */
|
|
841
|
-
/* @__PURE__ */
|
|
1110
|
+
return /* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1111
|
+
/* @__PURE__ */ jsx5(Text5, { ...selected && { color: "cyan" }, children: selected ? "\u276F" : " " }),
|
|
1112
|
+
/* @__PURE__ */ jsx5(Text5, { bold: selected, ...selected && { color: "cyan" }, children: profile.isDefault ? "Default" : profile.name }),
|
|
1113
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: profile.path })
|
|
842
1114
|
] }, profile.name);
|
|
843
1115
|
}),
|
|
844
|
-
/* @__PURE__ */
|
|
845
|
-
/* @__PURE__ */
|
|
846
|
-
/* @__PURE__ */
|
|
847
|
-
|
|
1116
|
+
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1117
|
+
/* @__PURE__ */ jsx5(Text5, { ...cursor === addNewIdx && { color: "cyan" }, children: cursor === addNewIdx ? "\u276F" : " " }),
|
|
1118
|
+
/* @__PURE__ */ jsx5(
|
|
1119
|
+
Text5,
|
|
848
1120
|
{
|
|
849
1121
|
bold: cursor === addNewIdx,
|
|
850
1122
|
...cursor === addNewIdx && { color: "cyan" },
|
|
@@ -853,77 +1125,69 @@ var CredentialSetupUI = ({
|
|
|
853
1125
|
)
|
|
854
1126
|
] })
|
|
855
1127
|
] }),
|
|
856
|
-
/* @__PURE__ */
|
|
1128
|
+
/* @__PURE__ */ jsx5(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel" })
|
|
857
1129
|
] });
|
|
858
1130
|
}
|
|
859
1131
|
if (phase.type === "name-entry") {
|
|
860
1132
|
const { nameBuffer, nameError } = phase;
|
|
861
|
-
return /* @__PURE__ */
|
|
862
|
-
/* @__PURE__ */
|
|
863
|
-
/* @__PURE__ */
|
|
864
|
-
|
|
865
|
-
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
866
|
-
] }),
|
|
867
|
-
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", gap: 0, children: /* @__PURE__ */ jsx3(Text3, { bold: true, children: "New credential profile" }) }),
|
|
868
|
-
nameError && /* @__PURE__ */ jsxs2(Text3, { color: "red", children: [
|
|
1133
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
1134
|
+
/* @__PURE__ */ jsx5(AppHeader, {}),
|
|
1135
|
+
/* @__PURE__ */ jsx5(Box4, { flexDirection: "column", gap: 0, children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "New credential profile" }) }),
|
|
1136
|
+
nameError && /* @__PURE__ */ jsxs3(Text5, { color: "red", children: [
|
|
869
1137
|
"Error: ",
|
|
870
1138
|
nameError
|
|
871
1139
|
] }),
|
|
872
|
-
/* @__PURE__ */
|
|
873
|
-
/* @__PURE__ */
|
|
874
|
-
/* @__PURE__ */
|
|
875
|
-
/* @__PURE__ */
|
|
876
|
-
/* @__PURE__ */
|
|
1140
|
+
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1141
|
+
/* @__PURE__ */ jsx5(Box4, { width: 12, children: /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: "Profile name" }) }),
|
|
1142
|
+
/* @__PURE__ */ jsx5(Text5, { color: "cyan", children: ">" }),
|
|
1143
|
+
/* @__PURE__ */ jsx5(Text5, { children: nameBuffer }),
|
|
1144
|
+
/* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2588" })
|
|
877
1145
|
] }),
|
|
878
|
-
/* @__PURE__ */
|
|
1146
|
+
/* @__PURE__ */ jsx5(Hint, { text: "Type a name \xB7 Enter to confirm \xB7 Esc to go back" })
|
|
879
1147
|
] });
|
|
880
1148
|
}
|
|
881
1149
|
const { field: activeField, values, envCursor } = phase;
|
|
882
1150
|
const isEnvField = activeField === FIELDS.length;
|
|
883
1151
|
const profileLabel = activeProfileName ?? DEFAULT_PROFILE_NAME;
|
|
884
|
-
return /* @__PURE__ */
|
|
885
|
-
/* @__PURE__ */
|
|
886
|
-
/* @__PURE__ */
|
|
887
|
-
/* @__PURE__ */
|
|
888
|
-
/* @__PURE__ */
|
|
889
|
-
] }),
|
|
890
|
-
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
891
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children: activeProfileName !== void 0 ? `Profile: ${activeProfileName}` : "Global credentials" }),
|
|
892
|
-
/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
|
|
1152
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
1153
|
+
/* @__PURE__ */ jsx5(AppHeader, {}),
|
|
1154
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 0, children: [
|
|
1155
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: activeProfileName !== void 0 ? `Profile: ${activeProfileName}` : "Global credentials" }),
|
|
1156
|
+
/* @__PURE__ */ jsxs3(Text5, { dimColor: true, children: [
|
|
893
1157
|
"Saved to:",
|
|
894
1158
|
" ",
|
|
895
1159
|
activeProfileName !== void 0 ? `~/.kizenappbuilder/${activeProfileName}.json` : GLOBAL_CREDENTIALS_PATH
|
|
896
1160
|
] })
|
|
897
1161
|
] }),
|
|
898
|
-
error && /* @__PURE__ */
|
|
1162
|
+
error && /* @__PURE__ */ jsxs3(Text5, { color: "red", children: [
|
|
899
1163
|
"Error: ",
|
|
900
1164
|
error
|
|
901
1165
|
] }),
|
|
902
|
-
/* @__PURE__ */
|
|
1166
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 0, children: [
|
|
903
1167
|
FIELDS.map((name, i) => {
|
|
904
1168
|
const isActive = activeField === i;
|
|
905
1169
|
const displayValue = isActive ? inputBuffer : values[name] ?? "";
|
|
906
|
-
return /* @__PURE__ */
|
|
907
|
-
/* @__PURE__ */
|
|
908
|
-
/* @__PURE__ */
|
|
909
|
-
/* @__PURE__ */
|
|
910
|
-
isActive && /* @__PURE__ */
|
|
1170
|
+
return /* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1171
|
+
/* @__PURE__ */ jsx5(Box4, { width: 12, children: /* @__PURE__ */ jsx5(Text5, { bold: isActive, ...isActive && { color: "cyan" }, children: FIELD_LABELS[name] }) }),
|
|
1172
|
+
/* @__PURE__ */ jsx5(Text5, { ...isActive && { color: "cyan" }, children: ">" }),
|
|
1173
|
+
/* @__PURE__ */ jsx5(Text5, { children: displayValue }),
|
|
1174
|
+
isActive && /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2588" })
|
|
911
1175
|
] }, name);
|
|
912
1176
|
}),
|
|
913
|
-
/* @__PURE__ */
|
|
914
|
-
/* @__PURE__ */
|
|
915
|
-
/* @__PURE__ */
|
|
916
|
-
/* @__PURE__ */
|
|
1177
|
+
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1178
|
+
/* @__PURE__ */ jsx5(Box4, { width: 12, children: /* @__PURE__ */ jsx5(Text5, { bold: isEnvField, ...isEnvField && { color: "cyan" }, children: "Environment" }) }),
|
|
1179
|
+
/* @__PURE__ */ jsx5(Text5, { ...isEnvField && { color: "cyan" }, children: ">" }),
|
|
1180
|
+
/* @__PURE__ */ jsx5(Box4, { gap: 1, children: ENVIRONMENTS.map((env, i) => {
|
|
917
1181
|
const isSelected = i === envCursor;
|
|
918
1182
|
if (isEnvField) {
|
|
919
|
-
return /* @__PURE__ */
|
|
1183
|
+
return /* @__PURE__ */ jsx5(Text5, { bold: isSelected, ...isSelected && { color: "cyan" }, children: isSelected ? `[${env}]` : env }, env);
|
|
920
1184
|
}
|
|
921
|
-
return /* @__PURE__ */
|
|
1185
|
+
return /* @__PURE__ */ jsx5(Text5, { dimColor: !isSelected, bold: isSelected, children: env }, env);
|
|
922
1186
|
}) })
|
|
923
1187
|
] })
|
|
924
1188
|
] }),
|
|
925
|
-
isEnvField ? /* @__PURE__ */
|
|
926
|
-
/* @__PURE__ */
|
|
1189
|
+
isEnvField ? /* @__PURE__ */ jsx5(Hint, { text: "\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel" }) : /* @__PURE__ */ jsx5(Hint, { text: "\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel" }),
|
|
1190
|
+
/* @__PURE__ */ jsxs3(Text5, { dimColor: true, children: [
|
|
927
1191
|
"Profile: ",
|
|
928
1192
|
profileLabel
|
|
929
1193
|
] })
|
|
@@ -931,202 +1195,8 @@ var CredentialSetupUI = ({
|
|
|
931
1195
|
};
|
|
932
1196
|
|
|
933
1197
|
// src/ui/DevUI.tsx
|
|
934
|
-
import { jsx as
|
|
935
|
-
function proxyLogEntryToString(entry) {
|
|
936
|
-
if (entry.kind === "info") {
|
|
937
|
-
return entry.message;
|
|
938
|
-
}
|
|
939
|
-
const cache = entry.fromCache ? " [cache]" : "";
|
|
940
|
-
return `${entry.method} ${entry.url} \u2192 ${String(entry.status)}${cache}`;
|
|
941
|
-
}
|
|
1198
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
942
1199
|
var SKIP_WATCH_PREFIXES = [".kizenapp", ".git"];
|
|
943
|
-
var LOG_LIMIT = 50;
|
|
944
|
-
var LOG_DISPLAY = 8;
|
|
945
|
-
var MIME_TYPES = {
|
|
946
|
-
".html": "text/html; charset=utf-8",
|
|
947
|
-
".js": "application/javascript; charset=utf-8",
|
|
948
|
-
".mjs": "application/javascript; charset=utf-8",
|
|
949
|
-
".css": "text/css; charset=utf-8",
|
|
950
|
-
".png": "image/png",
|
|
951
|
-
".jpg": "image/jpeg",
|
|
952
|
-
".svg": "image/svg+xml",
|
|
953
|
-
".ico": "image/x-icon",
|
|
954
|
-
".json": "application/json; charset=utf-8",
|
|
955
|
-
".woff": "font/woff",
|
|
956
|
-
".woff2": "font/woff2",
|
|
957
|
-
".ttf": "font/ttf",
|
|
958
|
-
".map": "application/json"
|
|
959
|
-
};
|
|
960
|
-
var SPINNER_FRAMES2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
961
|
-
var Spinner2 = () => {
|
|
962
|
-
const [frame, setFrame] = useState3(0);
|
|
963
|
-
useEffect3(() => {
|
|
964
|
-
const id = setInterval(() => {
|
|
965
|
-
setFrame((prev) => (prev + 1) % SPINNER_FRAMES2.length);
|
|
966
|
-
}, 80);
|
|
967
|
-
return () => {
|
|
968
|
-
clearInterval(id);
|
|
969
|
-
};
|
|
970
|
-
}, []);
|
|
971
|
-
return /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: SPINNER_FRAMES2[frame] ?? "\u280B" });
|
|
972
|
-
};
|
|
973
|
-
function getViewerPath() {
|
|
974
|
-
const filename = fileURLToPath2(import.meta.url);
|
|
975
|
-
return join7(dirname3(filename), "viewer");
|
|
976
|
-
}
|
|
977
|
-
async function fileExists(filePath) {
|
|
978
|
-
try {
|
|
979
|
-
await access(filePath);
|
|
980
|
-
return true;
|
|
981
|
-
} catch {
|
|
982
|
-
return false;
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast) {
|
|
986
|
-
const proxyCache = createProxyCache();
|
|
987
|
-
return (req, res) => {
|
|
988
|
-
void (async () => {
|
|
989
|
-
const url = req.url ?? "/";
|
|
990
|
-
try {
|
|
991
|
-
createServerLog(`Received request: ${url}`);
|
|
992
|
-
if (url === "/api/credentials") {
|
|
993
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
994
|
-
res.end(credentialsRef.current !== null ? JSON.stringify(credentialsRef.current) : "{}");
|
|
995
|
-
return;
|
|
996
|
-
}
|
|
997
|
-
if (url === "/api/credential-profiles" && req.method === "GET") {
|
|
998
|
-
const profiles = await listCredentialProfiles();
|
|
999
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1000
|
-
res.end(JSON.stringify({ profiles, active: activeProfileRef.current }));
|
|
1001
|
-
return;
|
|
1002
|
-
}
|
|
1003
|
-
if (url === "/api/credentials/switch" && req.method === "POST") {
|
|
1004
|
-
const chunks = [];
|
|
1005
|
-
for await (const chunk of req) {
|
|
1006
|
-
chunks.push(chunk);
|
|
1007
|
-
}
|
|
1008
|
-
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}");
|
|
1009
|
-
const profileName = body.profile;
|
|
1010
|
-
const creds = profileName === void 0 || profileName === "" ? await loadGlobalCredentials() : await loadCredentialProfile(profileName);
|
|
1011
|
-
if (creds !== null) {
|
|
1012
|
-
credentialsRef.current = creds;
|
|
1013
|
-
activeProfileRef.current = profileName ?? void 0;
|
|
1014
|
-
const active = activeProfileRef.current;
|
|
1015
|
-
await saveConfig(outputDir, {
|
|
1016
|
-
credentialMode: "global",
|
|
1017
|
-
...active !== void 0 && { activeCredentialProfile: active }
|
|
1018
|
-
});
|
|
1019
|
-
broadcast({ type: "credentials-updated", credentials: creds });
|
|
1020
|
-
}
|
|
1021
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1022
|
-
res.end(JSON.stringify({ ok: creds !== null }));
|
|
1023
|
-
return;
|
|
1024
|
-
}
|
|
1025
|
-
if (url === "/api/bundle") {
|
|
1026
|
-
const bundlePath = join7(process.cwd(), ".kizenapp", "bundle.json");
|
|
1027
|
-
try {
|
|
1028
|
-
const content = await readFile5(bundlePath, "utf-8");
|
|
1029
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1030
|
-
res.end(content);
|
|
1031
|
-
} catch {
|
|
1032
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1033
|
-
res.end("{}");
|
|
1034
|
-
}
|
|
1035
|
-
return;
|
|
1036
|
-
}
|
|
1037
|
-
if (url === "/api/proxy-cache/clear") {
|
|
1038
|
-
proxyCache.clear();
|
|
1039
|
-
createProxyLog({ kind: "info", message: "Proxy cache cleared" });
|
|
1040
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1041
|
-
res.end('{"ok":true}');
|
|
1042
|
-
return;
|
|
1043
|
-
}
|
|
1044
|
-
if (url.startsWith("/api/proxy")) {
|
|
1045
|
-
const proxyTarget = req.headers["x-proxy-target"];
|
|
1046
|
-
if (typeof proxyTarget !== "string") {
|
|
1047
|
-
res.writeHead(400);
|
|
1048
|
-
res.end("Missing x-proxy-target header");
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
const upstreamPath = url.slice("/api/proxy".length) || "/";
|
|
1052
|
-
const upstreamUrl = `${proxyTarget}${upstreamPath}`;
|
|
1053
|
-
const method = req.method ?? "GET";
|
|
1054
|
-
const chunks = [];
|
|
1055
|
-
for await (const chunk of req) {
|
|
1056
|
-
chunks.push(chunk);
|
|
1057
|
-
}
|
|
1058
|
-
const { host, "x-proxy-target": _drop, ...forwardHeaders } = req.headers;
|
|
1059
|
-
if (method === "GET") {
|
|
1060
|
-
const cacheKey = `GET::${upstreamUrl}`;
|
|
1061
|
-
const { response: cached, fromCache } = await proxyCache.get(
|
|
1062
|
-
cacheKey,
|
|
1063
|
-
() => fetch(upstreamUrl, {
|
|
1064
|
-
method: "GET",
|
|
1065
|
-
headers: forwardHeaders
|
|
1066
|
-
})
|
|
1067
|
-
);
|
|
1068
|
-
createProxyLog({
|
|
1069
|
-
kind: "request",
|
|
1070
|
-
method: "GET",
|
|
1071
|
-
status: cached.status,
|
|
1072
|
-
fromCache,
|
|
1073
|
-
url: upstreamPath
|
|
1074
|
-
});
|
|
1075
|
-
res.writeHead(cached.status, cached.headers);
|
|
1076
|
-
res.end(cached.body);
|
|
1077
|
-
return;
|
|
1078
|
-
}
|
|
1079
|
-
const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
|
|
1080
|
-
const resolvedBody = body && body.length > 0 ? body : void 0;
|
|
1081
|
-
const upstream = await fetch(upstreamUrl, {
|
|
1082
|
-
method,
|
|
1083
|
-
headers: forwardHeaders,
|
|
1084
|
-
...resolvedBody !== void 0 && { body: resolvedBody }
|
|
1085
|
-
});
|
|
1086
|
-
createProxyLog({
|
|
1087
|
-
kind: "request",
|
|
1088
|
-
method,
|
|
1089
|
-
status: upstream.status,
|
|
1090
|
-
fromCache: false,
|
|
1091
|
-
url: upstreamPath
|
|
1092
|
-
});
|
|
1093
|
-
const responseHeaders = Object.fromEntries(upstream.headers);
|
|
1094
|
-
delete responseHeaders["content-encoding"];
|
|
1095
|
-
delete responseHeaders["content-length"];
|
|
1096
|
-
res.writeHead(upstream.status, responseHeaders);
|
|
1097
|
-
res.end(Buffer.from(await upstream.arrayBuffer()));
|
|
1098
|
-
return;
|
|
1099
|
-
}
|
|
1100
|
-
const rawPath = url === "/" ? "/index.html" : url;
|
|
1101
|
-
const filePath = join7(viewerPath, rawPath);
|
|
1102
|
-
const resolvedPath = await fileExists(filePath) ? filePath : join7(viewerPath, "index.html");
|
|
1103
|
-
const ext = extname(resolvedPath);
|
|
1104
|
-
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
1105
|
-
res.writeHead(200, { "Content-Type": mimeType });
|
|
1106
|
-
createReadStream(resolvedPath).pipe(res);
|
|
1107
|
-
} catch (err) {
|
|
1108
|
-
if (url.startsWith("/api/proxy")) {
|
|
1109
|
-
createProxyLog({
|
|
1110
|
-
kind: "request",
|
|
1111
|
-
method: req.method ?? "GET",
|
|
1112
|
-
status: 502,
|
|
1113
|
-
fromCache: false,
|
|
1114
|
-
url: url.slice("/api/proxy".length) || "/"
|
|
1115
|
-
});
|
|
1116
|
-
} else {
|
|
1117
|
-
createProxyLog({
|
|
1118
|
-
kind: "info",
|
|
1119
|
-
message: `Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1122
|
-
if (!res.headersSent) {
|
|
1123
|
-
res.writeHead(502);
|
|
1124
|
-
res.end("Bad Gateway");
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
})();
|
|
1128
|
-
};
|
|
1129
|
-
}
|
|
1130
1200
|
var DevUI = ({
|
|
1131
1201
|
port,
|
|
1132
1202
|
pluginDir,
|
|
@@ -1137,26 +1207,30 @@ var DevUI = ({
|
|
|
1137
1207
|
}) => {
|
|
1138
1208
|
const credentialsRef = useRef(initialCredentials);
|
|
1139
1209
|
const activeProfileRef = useRef(initialActiveProfile);
|
|
1140
|
-
const [credMode, setCredMode] =
|
|
1141
|
-
const [credentialMode, setCredentialMode] =
|
|
1210
|
+
const [credMode, setCredMode] = useState5("main");
|
|
1211
|
+
const [credentialMode, setCredentialMode] = useState5(
|
|
1142
1212
|
initialCredentialMode
|
|
1143
1213
|
);
|
|
1144
|
-
const [status, setStatus] =
|
|
1145
|
-
const [errorMessage, setErrorMessage] =
|
|
1146
|
-
const [serverLogHistory,
|
|
1147
|
-
const [buildLogHistory,
|
|
1148
|
-
const [proxyLogHistory, setProxyLogHistory] =
|
|
1149
|
-
const [buildStatus, setBuildStatus] =
|
|
1150
|
-
const [buildError, setBuildError] =
|
|
1151
|
-
const [lastBuilt, setLastBuilt] =
|
|
1152
|
-
const [
|
|
1214
|
+
const [status, setStatus] = useState5("starting");
|
|
1215
|
+
const [errorMessage, setErrorMessage] = useState5(null);
|
|
1216
|
+
const [serverLogHistory, appendServerLog] = useLogHistory(LOG_LIMIT);
|
|
1217
|
+
const [buildLogHistory, appendBuildLog] = useLogHistory(LOG_LIMIT);
|
|
1218
|
+
const [proxyLogHistory, setProxyLogHistory] = useState5([]);
|
|
1219
|
+
const [buildStatus, setBuildStatus] = useState5("pending");
|
|
1220
|
+
const [buildError, setBuildError] = useState5(null);
|
|
1221
|
+
const [lastBuilt, setLastBuilt] = useState5(null);
|
|
1222
|
+
const [lastBundleSize, setLastBundleSize] = useState5(null);
|
|
1223
|
+
const [wsClientCount, setWsClientCount] = useState5(0);
|
|
1224
|
+
const [proxyCacheSize, setProxyCacheSize] = useState5(0);
|
|
1225
|
+
const [proxyCacheHits, setProxyCacheHits] = useState5(0);
|
|
1226
|
+
const [proxyCacheMisses, setProxyCacheMisses] = useState5(0);
|
|
1153
1227
|
const buildingRef = useRef(false);
|
|
1154
1228
|
const viewerLaunchedRef = useRef(false);
|
|
1155
1229
|
const chromeHandleRef = useRef(null);
|
|
1156
1230
|
const debounceTimerRef = useRef(null);
|
|
1157
1231
|
const wsClientsRef = useRef(/* @__PURE__ */ new Set());
|
|
1158
1232
|
const pendingMessagesRef = useRef([]);
|
|
1159
|
-
const broadcast =
|
|
1233
|
+
const broadcast = useCallback3((msg) => {
|
|
1160
1234
|
const json = JSON.stringify(msg);
|
|
1161
1235
|
if (wsClientsRef.current.size === 0) {
|
|
1162
1236
|
pendingMessagesRef.current = [...pendingMessagesRef.current, json].slice(-LOG_LIMIT);
|
|
@@ -1168,21 +1242,19 @@ var DevUI = ({
|
|
|
1168
1242
|
}
|
|
1169
1243
|
}
|
|
1170
1244
|
}, []);
|
|
1171
|
-
const createServerLog =
|
|
1172
|
-
|
|
1173
|
-
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
1174
|
-
);
|
|
1175
|
-
}, []);
|
|
1176
|
-
const launchChromeViewerCb = useCallback2(() => {
|
|
1245
|
+
const createServerLog = appendServerLog;
|
|
1246
|
+
const launchChromeViewerCb = useCallback3(() => {
|
|
1177
1247
|
chromeHandleRef.current?.kill();
|
|
1178
1248
|
chromeHandleRef.current = null;
|
|
1179
1249
|
void launchChromeViewer({
|
|
1180
1250
|
port,
|
|
1181
|
-
userDataDir:
|
|
1251
|
+
userDataDir: join8(outputDir, ".chrome"),
|
|
1182
1252
|
broadcast
|
|
1183
1253
|
}).then((handle) => {
|
|
1184
1254
|
chromeHandleRef.current = handle;
|
|
1185
|
-
process.on("exit", () =>
|
|
1255
|
+
process.on("exit", () => {
|
|
1256
|
+
handle.kill();
|
|
1257
|
+
});
|
|
1186
1258
|
});
|
|
1187
1259
|
}, [port, outputDir, broadcast]);
|
|
1188
1260
|
useInput2(
|
|
@@ -1199,14 +1271,14 @@ var DevUI = ({
|
|
|
1199
1271
|
},
|
|
1200
1272
|
{ isActive: credMode === "main" }
|
|
1201
1273
|
);
|
|
1202
|
-
|
|
1274
|
+
useEffect4(() => {
|
|
1203
1275
|
if (status !== "running" || viewerLaunchedRef.current) {
|
|
1204
1276
|
return;
|
|
1205
1277
|
}
|
|
1206
1278
|
viewerLaunchedRef.current = true;
|
|
1207
1279
|
launchChromeViewerCb();
|
|
1208
1280
|
}, [status, launchChromeViewerCb]);
|
|
1209
|
-
const handleCredentialsDone =
|
|
1281
|
+
const handleCredentialsDone = useCallback3(
|
|
1210
1282
|
(result) => {
|
|
1211
1283
|
credentialsRef.current = result.credentials;
|
|
1212
1284
|
activeProfileRef.current = result.profileName;
|
|
@@ -1221,27 +1293,32 @@ var DevUI = ({
|
|
|
1221
1293
|
},
|
|
1222
1294
|
[outputDir, broadcast]
|
|
1223
1295
|
);
|
|
1224
|
-
const createProxyLog =
|
|
1296
|
+
const createProxyLog = useCallback3(
|
|
1225
1297
|
(entry) => {
|
|
1226
1298
|
setProxyLogHistory(
|
|
1227
1299
|
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${proxyLogEntryToString(entry)}`].slice(
|
|
1228
1300
|
-LOG_LIMIT
|
|
1229
1301
|
)
|
|
1230
1302
|
);
|
|
1303
|
+
if (entry.kind === "request") {
|
|
1304
|
+
if (entry.fromCache) {
|
|
1305
|
+
setProxyCacheHits((n) => n + 1);
|
|
1306
|
+
} else {
|
|
1307
|
+
setProxyCacheMisses((n) => n + 1);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1231
1310
|
broadcast({ type: "proxy-log", entry });
|
|
1232
1311
|
},
|
|
1233
1312
|
[broadcast]
|
|
1234
1313
|
);
|
|
1235
|
-
const createBuildLog =
|
|
1314
|
+
const createBuildLog = useCallback3(
|
|
1236
1315
|
(message) => {
|
|
1237
|
-
|
|
1238
|
-
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
1239
|
-
);
|
|
1316
|
+
appendBuildLog(message);
|
|
1240
1317
|
broadcast({ type: "log", message });
|
|
1241
1318
|
},
|
|
1242
|
-
[broadcast]
|
|
1319
|
+
[appendBuildLog, broadcast]
|
|
1243
1320
|
);
|
|
1244
|
-
const triggerBuild =
|
|
1321
|
+
const triggerBuild = useCallback3(() => {
|
|
1245
1322
|
if (buildingRef.current) {
|
|
1246
1323
|
return;
|
|
1247
1324
|
}
|
|
@@ -1249,10 +1326,11 @@ var DevUI = ({
|
|
|
1249
1326
|
setBuildStatus("building");
|
|
1250
1327
|
setBuildError(null);
|
|
1251
1328
|
createBuildLog("Build started");
|
|
1252
|
-
void runBuild(pluginDir, outputDir).then(() => {
|
|
1253
|
-
createBuildLog(
|
|
1329
|
+
void runBuild(pluginDir, outputDir).then(({ bundleSize }) => {
|
|
1330
|
+
createBuildLog(`Build finished \u2014 bundle: ${formatBytes(bundleSize)}`);
|
|
1254
1331
|
setBuildStatus("done");
|
|
1255
1332
|
setLastBuilt(/* @__PURE__ */ new Date());
|
|
1333
|
+
setLastBundleSize(bundleSize);
|
|
1256
1334
|
createBuildLog("Notifying viewers to reload");
|
|
1257
1335
|
for (const client of wsClientsRef.current) {
|
|
1258
1336
|
if (client.readyState === 1) {
|
|
@@ -1267,7 +1345,7 @@ var DevUI = ({
|
|
|
1267
1345
|
buildingRef.current = false;
|
|
1268
1346
|
});
|
|
1269
1347
|
}, [pluginDir, outputDir, createBuildLog]);
|
|
1270
|
-
|
|
1348
|
+
useEffect4(() => {
|
|
1271
1349
|
triggerBuild();
|
|
1272
1350
|
const watcher = watch(pluginDir, { recursive: true }, (_, filename) => {
|
|
1273
1351
|
if (!filename) {
|
|
@@ -1281,7 +1359,7 @@ var DevUI = ({
|
|
|
1281
1359
|
if (debounceTimerRef.current !== null) {
|
|
1282
1360
|
clearTimeout(debounceTimerRef.current);
|
|
1283
1361
|
}
|
|
1284
|
-
debounceTimerRef.current = setTimeout(triggerBuild,
|
|
1362
|
+
debounceTimerRef.current = setTimeout(triggerBuild, FILE_WATCH_DEBOUNCE_MS);
|
|
1285
1363
|
});
|
|
1286
1364
|
return () => {
|
|
1287
1365
|
watcher.close();
|
|
@@ -1290,9 +1368,9 @@ var DevUI = ({
|
|
|
1290
1368
|
}
|
|
1291
1369
|
};
|
|
1292
1370
|
}, [pluginDir, triggerBuild, createBuildLog]);
|
|
1293
|
-
|
|
1371
|
+
useEffect4(() => {
|
|
1294
1372
|
const viewerPath = getViewerPath();
|
|
1295
|
-
void fileExists(
|
|
1373
|
+
void fileExists(join8(viewerPath, "index.html")).then((viewerBuilt) => {
|
|
1296
1374
|
if (!viewerBuilt) {
|
|
1297
1375
|
setErrorMessage("Viewer not built. Run 'pnpm build:viewer' first.");
|
|
1298
1376
|
setStatus("error");
|
|
@@ -1305,7 +1383,8 @@ var DevUI = ({
|
|
|
1305
1383
|
credentialsRef,
|
|
1306
1384
|
activeProfileRef,
|
|
1307
1385
|
outputDir,
|
|
1308
|
-
broadcast
|
|
1386
|
+
broadcast,
|
|
1387
|
+
setProxyCacheSize
|
|
1309
1388
|
);
|
|
1310
1389
|
const server = createServer(handler);
|
|
1311
1390
|
const wss = new WebSocketServer({ server });
|
|
@@ -1339,7 +1418,7 @@ var DevUI = ({
|
|
|
1339
1418
|
});
|
|
1340
1419
|
}, [port, createServerLog, createProxyLog, broadcast, outputDir]);
|
|
1341
1420
|
if (credMode === "editing") {
|
|
1342
|
-
return /* @__PURE__ */
|
|
1421
|
+
return /* @__PURE__ */ jsx6(
|
|
1343
1422
|
CredentialSetupUI,
|
|
1344
1423
|
{
|
|
1345
1424
|
...credentialMode !== void 0 && { initialMode: credentialMode },
|
|
@@ -1353,100 +1432,112 @@ var DevUI = ({
|
|
|
1353
1432
|
}
|
|
1354
1433
|
const elapsedSeconds = lastBuilt !== null ? Math.round((Date.now() - lastBuilt.getTime()) / 1e3) : null;
|
|
1355
1434
|
const elapsedLabel = elapsedSeconds === null ? "" : elapsedSeconds < 5 ? " (just now)" : ` (${String(elapsedSeconds)}s ago)`;
|
|
1356
|
-
return /* @__PURE__ */
|
|
1357
|
-
/* @__PURE__ */
|
|
1358
|
-
/* @__PURE__ */
|
|
1359
|
-
/* @__PURE__ */
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
buildStatus === "pending" && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "waiting\u2026" }),
|
|
1366
|
-
buildStatus === "building" && /* @__PURE__ */ jsxs3(Box4, { gap: 1, children: [
|
|
1367
|
-
/* @__PURE__ */ jsx4(Spinner2, {}),
|
|
1368
|
-
/* @__PURE__ */ jsx4(Text4, { children: "Building plugin package\u2026" })
|
|
1435
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", paddingY: 1, paddingX: 2, children: [
|
|
1436
|
+
/* @__PURE__ */ jsx6(AppHeader, { marginBottom: 1 }),
|
|
1437
|
+
/* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
|
|
1438
|
+
/* @__PURE__ */ jsxs4(Box5, { gap: 2, marginBottom: 0, children: [
|
|
1439
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, dimColor: true, children: "App Build" }),
|
|
1440
|
+
buildStatus === "pending" && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "waiting\u2026" }),
|
|
1441
|
+
buildStatus === "building" && /* @__PURE__ */ jsxs4(Box5, { gap: 1, children: [
|
|
1442
|
+
/* @__PURE__ */ jsx6(Spinner, {}),
|
|
1443
|
+
/* @__PURE__ */ jsx6(Text6, { children: "Building plugin package\u2026" })
|
|
1369
1444
|
] }),
|
|
1370
|
-
buildStatus === "done" && /* @__PURE__ */
|
|
1371
|
-
/* @__PURE__ */
|
|
1372
|
-
lastBuilt !== null && /* @__PURE__ */
|
|
1445
|
+
buildStatus === "done" && /* @__PURE__ */ jsxs4(Box5, { gap: 1, children: [
|
|
1446
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713 Built" }),
|
|
1447
|
+
lastBuilt !== null && /* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1373
1448
|
"at ",
|
|
1374
1449
|
lastBuilt.toLocaleTimeString(),
|
|
1375
1450
|
elapsedLabel
|
|
1451
|
+
] }),
|
|
1452
|
+
lastBundleSize !== null && /* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1453
|
+
"\xB7 bundle: ",
|
|
1454
|
+
formatBytes(lastBundleSize)
|
|
1376
1455
|
] })
|
|
1377
1456
|
] }),
|
|
1378
|
-
buildStatus === "error" && /* @__PURE__ */
|
|
1457
|
+
buildStatus === "error" && /* @__PURE__ */ jsxs4(Text6, { color: "red", children: [
|
|
1379
1458
|
"\u2717 ",
|
|
1380
1459
|
buildError ?? "unknown error"
|
|
1381
1460
|
] })
|
|
1382
1461
|
] }),
|
|
1383
|
-
/* @__PURE__ */
|
|
1384
|
-
|
|
1462
|
+
/* @__PURE__ */ jsx6(
|
|
1463
|
+
Box5,
|
|
1385
1464
|
{
|
|
1386
1465
|
flexDirection: "column",
|
|
1387
|
-
height: LOG_DISPLAY,
|
|
1466
|
+
height: LOG_DISPLAY + 2,
|
|
1388
1467
|
borderStyle: "single",
|
|
1389
1468
|
borderColor: "gray",
|
|
1390
1469
|
overflow: "hidden",
|
|
1391
|
-
children: buildLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */
|
|
1470
|
+
children: buildLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate", children: log }, index))
|
|
1392
1471
|
}
|
|
1393
1472
|
)
|
|
1394
1473
|
] }),
|
|
1395
|
-
/* @__PURE__ */
|
|
1396
|
-
/* @__PURE__ */
|
|
1397
|
-
/* @__PURE__ */
|
|
1398
|
-
status === "starting" && /* @__PURE__ */
|
|
1399
|
-
status === "running" && /* @__PURE__ */
|
|
1400
|
-
/* @__PURE__ */
|
|
1401
|
-
/* @__PURE__ */
|
|
1474
|
+
/* @__PURE__ */ jsxs4(Box5, { marginTop: 1, flexDirection: "column", children: [
|
|
1475
|
+
/* @__PURE__ */ jsxs4(Box5, { gap: 2, children: [
|
|
1476
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, dimColor: true, children: "Web Server" }),
|
|
1477
|
+
status === "starting" && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "starting\u2026" }),
|
|
1478
|
+
status === "running" && /* @__PURE__ */ jsxs4(Box5, { gap: 2, children: [
|
|
1479
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713 Running" }),
|
|
1480
|
+
/* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1402
1481
|
"\u25CF ",
|
|
1403
1482
|
wsClientCount,
|
|
1404
1483
|
" viewer",
|
|
1405
1484
|
wsClientCount !== 1 ? "s" : ""
|
|
1406
1485
|
] })
|
|
1407
1486
|
] }),
|
|
1408
|
-
status === "error" && /* @__PURE__ */
|
|
1487
|
+
status === "error" && /* @__PURE__ */ jsxs4(Text6, { color: "red", children: [
|
|
1409
1488
|
"\u2717 ",
|
|
1410
1489
|
errorMessage ?? "Server error"
|
|
1411
1490
|
] })
|
|
1412
1491
|
] }),
|
|
1413
|
-
/* @__PURE__ */
|
|
1414
|
-
|
|
1492
|
+
/* @__PURE__ */ jsx6(
|
|
1493
|
+
Box5,
|
|
1415
1494
|
{
|
|
1416
1495
|
flexDirection: "column",
|
|
1417
|
-
height: LOG_DISPLAY,
|
|
1496
|
+
height: LOG_DISPLAY + 2,
|
|
1418
1497
|
borderStyle: "single",
|
|
1419
1498
|
borderColor: "gray",
|
|
1420
1499
|
overflow: "hidden",
|
|
1421
|
-
children: serverLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */
|
|
1500
|
+
children: serverLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate", children: log }, index))
|
|
1422
1501
|
}
|
|
1423
1502
|
)
|
|
1424
1503
|
] }),
|
|
1425
|
-
/* @__PURE__ */
|
|
1426
|
-
/* @__PURE__ */
|
|
1427
|
-
/* @__PURE__ */
|
|
1428
|
-
/* @__PURE__ */
|
|
1504
|
+
/* @__PURE__ */ jsxs4(Box5, { marginTop: 1, flexDirection: "column", children: [
|
|
1505
|
+
/* @__PURE__ */ jsxs4(Box5, { gap: 2, children: [
|
|
1506
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, dimColor: true, children: "Network Proxy" }),
|
|
1507
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713 Active" }),
|
|
1508
|
+
/* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1509
|
+
"\u25CF ",
|
|
1510
|
+
proxyCacheSize,
|
|
1511
|
+
" key",
|
|
1512
|
+
proxyCacheSize !== 1 ? "s" : "",
|
|
1513
|
+
" in the network cache \xB7",
|
|
1514
|
+
" ",
|
|
1515
|
+
proxyCacheHits,
|
|
1516
|
+
" hit \xB7 ",
|
|
1517
|
+
proxyCacheMisses,
|
|
1518
|
+
" miss"
|
|
1519
|
+
] })
|
|
1429
1520
|
] }),
|
|
1430
|
-
/* @__PURE__ */
|
|
1431
|
-
|
|
1521
|
+
/* @__PURE__ */ jsx6(
|
|
1522
|
+
Box5,
|
|
1432
1523
|
{
|
|
1433
1524
|
flexDirection: "column",
|
|
1434
|
-
height: LOG_DISPLAY,
|
|
1525
|
+
height: LOG_DISPLAY + 2,
|
|
1435
1526
|
borderStyle: "single",
|
|
1436
1527
|
borderColor: "gray",
|
|
1437
1528
|
overflow: "hidden",
|
|
1438
|
-
children: proxyLogHistory.length === 0 ? /* @__PURE__ */
|
|
1529
|
+
children: proxyLogHistory.length === 0 ? /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " No requests yet." }) : proxyLogHistory.slice(-LOG_DISPLAY).map((log, i) => /* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate", children: log }, i))
|
|
1439
1530
|
}
|
|
1440
1531
|
)
|
|
1441
1532
|
] }),
|
|
1442
|
-
/* @__PURE__ */
|
|
1443
|
-
/* @__PURE__ */
|
|
1444
|
-
/* @__PURE__ */
|
|
1445
|
-
/* @__PURE__ */
|
|
1446
|
-
/* @__PURE__ */
|
|
1447
|
-
/* @__PURE__ */
|
|
1448
|
-
/* @__PURE__ */
|
|
1449
|
-
/* @__PURE__ */
|
|
1533
|
+
/* @__PURE__ */ jsxs4(Box5, { marginTop: 1, gap: 1, children: [
|
|
1534
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "[" }),
|
|
1535
|
+
/* @__PURE__ */ jsx6(Text6, { children: "q" }),
|
|
1536
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "] quit [" }),
|
|
1537
|
+
/* @__PURE__ */ jsx6(Text6, { children: "c" }),
|
|
1538
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "] credentials [" }),
|
|
1539
|
+
/* @__PURE__ */ jsx6(Text6, { children: "v" }),
|
|
1540
|
+
/* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1450
1541
|
"] ",
|
|
1451
1542
|
wsClientCount === 0 ? "open viewer" : "relaunch viewer"
|
|
1452
1543
|
] })
|