@kizenapps/cli 0.8.0 → 0.10.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/index.js +388 -90
- package/dist/index.js.map +1 -1
- package/dist/viewer/assets/AppDetailPage-ObugMPkn.js +1 -0
- package/dist/viewer/assets/BootstrapContext-CEWgv2oI.js +1 -0
- package/dist/viewer/assets/Card-BSwG5koM.js +1 -0
- package/dist/viewer/assets/ConfigurationPage-SnFNzZgJ.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-BFVVe-i3.js +1 -0
- package/dist/viewer/assets/SidebarContext-Byo6PYOF.js +1 -0
- package/dist/viewer/assets/VersionsPage-DOd2Hv8M.js +1 -0
- package/dist/viewer/assets/configStorage-Bb-A9Nvj.js +14 -0
- package/dist/viewer/assets/{fa-core-BU3ZZt7W.js → fa-core-mHW_3JUd.js} +1 -1
- package/dist/viewer/assets/index-B-4D4w_w.js +5 -0
- package/dist/viewer/assets/index-D6Un_G7k.css +2 -0
- package/dist/viewer/assets/{react-C90crogl.js → react-D_K8ni3_.js} +1 -1
- package/dist/viewer/assets/validIcons-TcFXfn-E.js +1 -0
- package/dist/viewer/index.html +8 -5
- package/package.json +8 -4
- 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-4Z6S6LWP.js +0 -6134
- package/dist/chunk-4Z6S6LWP.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-HJPLDI45.js +0 -6134
- package/dist/chunk-HJPLDI45.js.map +0 -1
- package/dist/chunk-KMKDY2I6.js +0 -46
- package/dist/chunk-KMKDY2I6.js.map +0 -1
- package/dist/chunk-LSHHXCC6.js +0 -3639
- package/dist/chunk-LSHHXCC6.js.map +0 -1
- package/dist/chunk-NNDSADQG.js +0 -3641
- package/dist/chunk-NNDSADQG.js.map +0 -1
- package/dist/chunk-SEGVTWSK.js +0 -44
- package/dist/chunk-SEGVTWSK.js.map +0 -1
- package/dist/chunk-ZWE3DS7E.js +0 -39
- package/dist/chunk-ZWE3DS7E.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 +0 -67
- 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/dist-C3F6UOWF.js +0 -8472
- package/dist/dist-C3F6UOWF.js.map +0 -1
- package/dist/dist-NUJOSN7W.js +0 -8472
- package/dist/dist-NUJOSN7W.js.map +0 -1
- package/dist/dist-QHDMIBVE.js +0 -135
- package/dist/dist-QHDMIBVE.js.map +0 -1
- package/dist/dist-ZIZQOSY3.js +0 -135
- package/dist/dist-ZIZQOSY3.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-K37OQCQ2.js +0 -137
- package/dist/gzip-size-K37OQCQ2.js.map +0 -1
- package/dist/gzip-size-QRGIYYEQ.js +0 -137
- package/dist/gzip-size-QRGIYYEQ.js.map +0 -1
- package/dist/gzip-size-SHZBT5GU.js +0 -139
- package/dist/gzip-size-SHZBT5GU.js.map +0 -1
- package/dist/viewer/assets/index-B09qenTV.js +0 -17
- package/dist/viewer/assets/index-CVd4BLit.js +0 -17
- package/dist/viewer/assets/index-C_gRcfsL.js +0 -17
- package/dist/viewer/assets/index-CcvbGL5I.js +0 -17
- package/dist/viewer/assets/index-Ci5up9QD.js +0 -17
- package/dist/viewer/assets/index-DOiSISo1.css +0 -2
- package/dist/viewer/assets/index-DSJAwx9Y.js +0 -17
- package/dist/viewer/assets/index-DUgUEouL.css +0 -2
- package/dist/viewer/assets/index-WnCF0zx3.js +0 -17
- package/dist/viewer/assets/index-_K33TupM.js +0 -17
- package/dist/viewer/assets/index-dPV4go8k.js +0 -17
- package/dist/viewer/assets/index-xFuxlPJA.js +0 -17
- /package/dist/viewer/assets/{fa-pro-icons-D4afj0tU.js → fa-pro-icons-CIQGXozY.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -229,18 +229,269 @@ import { render as render2 } from "ink";
|
|
|
229
229
|
// src/ui/DevUI.tsx
|
|
230
230
|
import { useCallback as useCallback2, useEffect as useEffect3, useRef, useState as useState3 } from "react";
|
|
231
231
|
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
232
|
-
import { spawn } from "child_process";
|
|
233
232
|
import { createReadStream, watch } from "fs";
|
|
234
|
-
import { access, readFile as
|
|
233
|
+
import { access, readFile as readFile5 } from "fs/promises";
|
|
235
234
|
import { createServer } from "http";
|
|
235
|
+
import { dirname as dirname3, extname, join as join7 } from "path";
|
|
236
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
237
|
+
import { WebSocketServer } from "ws";
|
|
238
|
+
|
|
239
|
+
// src/chrome/launcher.ts
|
|
240
|
+
import { launch } from "chrome-launcher";
|
|
236
241
|
import { createRequire } from "module";
|
|
237
|
-
import {
|
|
242
|
+
import { mkdirSync } from "fs";
|
|
243
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
244
|
+
import { dirname, join as join4 } from "path";
|
|
238
245
|
import { fileURLToPath } from "url";
|
|
239
|
-
|
|
246
|
+
var CDP = createRequire(import.meta.url)("chrome-remote-interface");
|
|
247
|
+
var CSP_HEADERS = /* @__PURE__ */ new Set([
|
|
248
|
+
"content-security-policy",
|
|
249
|
+
"content-security-policy-report-only",
|
|
250
|
+
"x-frame-options"
|
|
251
|
+
]);
|
|
252
|
+
var KIZEN_DOMAINS = ["kizen.dev", "kizen.com"];
|
|
253
|
+
function isKizenUrl(url) {
|
|
254
|
+
try {
|
|
255
|
+
const { hostname } = new URL(url);
|
|
256
|
+
return KIZEN_DOMAINS.some((d) => hostname === d || hostname.endsWith("." + d));
|
|
257
|
+
} catch {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function parseProp(prop) {
|
|
262
|
+
if (prop.type === "number") {
|
|
263
|
+
return Number(prop.value);
|
|
264
|
+
}
|
|
265
|
+
if (prop.type === "boolean") {
|
|
266
|
+
return prop.value === "true";
|
|
267
|
+
}
|
|
268
|
+
if (prop.type === "undefined") {
|
|
269
|
+
return void 0;
|
|
270
|
+
}
|
|
271
|
+
if (prop.type === "object" && prop.value === "null") {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
if (prop.type === "object" && prop.valuePreview) {
|
|
275
|
+
const { valuePreview } = prop;
|
|
276
|
+
if (valuePreview.subtype === "array") {
|
|
277
|
+
return valuePreview.properties.filter((p) => /^\d+$/.test(p.name)).sort((a, b) => parseInt(a.name) - parseInt(b.name)).map(parseProp);
|
|
278
|
+
}
|
|
279
|
+
const obj = {};
|
|
280
|
+
for (const p of valuePreview.properties) {
|
|
281
|
+
obj[p.name] = parseProp(p);
|
|
282
|
+
}
|
|
283
|
+
return obj;
|
|
284
|
+
}
|
|
285
|
+
return prop.value ?? `[${prop.type}]`;
|
|
286
|
+
}
|
|
287
|
+
function serializeArg(arg) {
|
|
288
|
+
if (arg.value !== void 0) {
|
|
289
|
+
return arg.value;
|
|
290
|
+
}
|
|
291
|
+
if (arg.preview) {
|
|
292
|
+
const { preview } = arg;
|
|
293
|
+
if (preview.subtype === "array") {
|
|
294
|
+
return preview.properties.filter((p) => /^\d+$/.test(p.name)).sort((a, b) => parseInt(a.name) - parseInt(b.name)).map(parseProp);
|
|
295
|
+
}
|
|
296
|
+
const obj = {};
|
|
297
|
+
for (const prop of preview.properties) {
|
|
298
|
+
obj[prop.name] = parseProp(prop);
|
|
299
|
+
}
|
|
300
|
+
return obj;
|
|
301
|
+
}
|
|
302
|
+
return arg.description ?? `[${arg.type}]`;
|
|
303
|
+
}
|
|
304
|
+
async function serializeArgAsync(client, arg) {
|
|
305
|
+
if (arg.type === "object" && arg.objectId) {
|
|
306
|
+
try {
|
|
307
|
+
const result = await client.Runtime.callFunctionOn({
|
|
308
|
+
objectId: arg.objectId,
|
|
309
|
+
functionDeclaration: 'function() { const seen = new WeakSet(); return JSON.stringify(this, function(k,v) { if (typeof v === "object" && v !== null) { if (seen.has(v)) return "[Circular]"; seen.add(v); } return v; }); }',
|
|
310
|
+
returnByValue: true
|
|
311
|
+
});
|
|
312
|
+
const val = result.result.value;
|
|
313
|
+
if (typeof val === "string") {
|
|
314
|
+
return JSON.parse(val);
|
|
315
|
+
}
|
|
316
|
+
} catch {
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return serializeArg(arg);
|
|
320
|
+
}
|
|
321
|
+
async function installDockIcon(client) {
|
|
322
|
+
try {
|
|
323
|
+
const iconPath = join4(dirname(fileURLToPath(import.meta.url)), "viewer", "icon.png");
|
|
324
|
+
const icon = await readFile2(iconPath);
|
|
325
|
+
await client.Browser.setDockTile({ image: icon.toString("base64") });
|
|
326
|
+
} catch {
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
async function launchChromeViewer(opts) {
|
|
330
|
+
mkdirSync(opts.userDataDir, { recursive: true });
|
|
331
|
+
const chrome = await launch({
|
|
332
|
+
startingUrl: `http://localhost:${String(opts.port)}`,
|
|
333
|
+
chromeFlags: [
|
|
334
|
+
`--app=http://localhost:${String(opts.port)}`,
|
|
335
|
+
"--no-first-run",
|
|
336
|
+
"--no-default-browser-check",
|
|
337
|
+
"--disable-extensions"
|
|
338
|
+
],
|
|
339
|
+
userDataDir: opts.userDataDir,
|
|
340
|
+
handleSIGINT: false,
|
|
341
|
+
logLevel: "silent"
|
|
342
|
+
});
|
|
343
|
+
let client = null;
|
|
344
|
+
let cookieTimer = null;
|
|
345
|
+
const cdpPort = chrome.port;
|
|
346
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
347
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
348
|
+
try {
|
|
349
|
+
client = await CDP({ port: cdpPort });
|
|
350
|
+
break;
|
|
351
|
+
} catch {
|
|
352
|
+
if (attempt === 9) {
|
|
353
|
+
return {
|
|
354
|
+
kill: () => {
|
|
355
|
+
chrome.kill();
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (!client) {
|
|
362
|
+
return {
|
|
363
|
+
kill: () => {
|
|
364
|
+
chrome.kill();
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
const c = client;
|
|
369
|
+
await installDockIcon(c);
|
|
370
|
+
await c.Fetch.enable({
|
|
371
|
+
patterns: KIZEN_DOMAINS.flatMap((d) => [
|
|
372
|
+
{ urlPattern: `*://${d}/*`, requestStage: "Response" },
|
|
373
|
+
{ urlPattern: `*://*.${d}/*`, requestStage: "Response" }
|
|
374
|
+
])
|
|
375
|
+
});
|
|
376
|
+
c.on("Fetch.requestPaused", (rawParams) => {
|
|
377
|
+
void (async () => {
|
|
378
|
+
const params = rawParams;
|
|
379
|
+
const { requestId, request, responseHeaders, responseStatusCode } = params;
|
|
380
|
+
const url = request.url;
|
|
381
|
+
const filtered = [];
|
|
382
|
+
for (const h of responseHeaders ?? []) {
|
|
383
|
+
if (CSP_HEADERS.has(h.name.toLowerCase())) {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if (h.name.toLowerCase() === "set-cookie" && isKizenUrl(url)) {
|
|
387
|
+
const patched = h.value.split("\n").map((cookie) => {
|
|
388
|
+
if (!/SameSite=/i.test(cookie)) {
|
|
389
|
+
return cookie + "; SameSite=None; Secure";
|
|
390
|
+
}
|
|
391
|
+
return cookie.replace(/SameSite=\w+/i, "SameSite=None");
|
|
392
|
+
}).join("\n");
|
|
393
|
+
filtered.push({ name: h.name, value: patched });
|
|
394
|
+
} else {
|
|
395
|
+
filtered.push(h);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
const { body, base64Encoded } = await c.Fetch.getResponseBody({ requestId });
|
|
400
|
+
await c.Fetch.fulfillRequest({
|
|
401
|
+
requestId,
|
|
402
|
+
responseCode: responseStatusCode ?? 200,
|
|
403
|
+
responseHeaders: filtered,
|
|
404
|
+
body,
|
|
405
|
+
...base64Encoded && { base64Encoded: true }
|
|
406
|
+
});
|
|
407
|
+
} catch {
|
|
408
|
+
try {
|
|
409
|
+
await c.Fetch.continueRequest({ requestId });
|
|
410
|
+
} catch {
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
})();
|
|
414
|
+
});
|
|
415
|
+
cookieTimer = setInterval(() => {
|
|
416
|
+
void (async () => {
|
|
417
|
+
try {
|
|
418
|
+
const { cookies } = await c.Network.getAllCookies();
|
|
419
|
+
for (const cookie of cookies) {
|
|
420
|
+
if (!isKizenUrl(`https://${cookie.domain ?? ""}`)) {
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (cookie.sameSite === "None") {
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
const raw = cookie.domain ?? "";
|
|
427
|
+
const bare = raw.startsWith(".") ? raw.slice(1) : raw;
|
|
428
|
+
await c.Network.setCookie({
|
|
429
|
+
url: `https://${bare}`,
|
|
430
|
+
name: cookie.name,
|
|
431
|
+
value: cookie.value,
|
|
432
|
+
domain: raw,
|
|
433
|
+
path: cookie.path ?? "/",
|
|
434
|
+
secure: true,
|
|
435
|
+
...cookie.httpOnly !== void 0 && { httpOnly: cookie.httpOnly },
|
|
436
|
+
...cookie.expirationDate !== void 0 && {
|
|
437
|
+
expires: cookie.expirationDate
|
|
438
|
+
},
|
|
439
|
+
sameSite: "None"
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
} catch {
|
|
443
|
+
}
|
|
444
|
+
})();
|
|
445
|
+
}, 2e3);
|
|
446
|
+
await c.send("Runtime.enable", { generatePreview: true });
|
|
447
|
+
c.on("Target.attachedToTarget", (rawParams) => {
|
|
448
|
+
const { sessionId } = rawParams;
|
|
449
|
+
void c.send("Runtime.enable", { generatePreview: true }, sessionId).catch(() => {
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
await c.Target.setAutoAttach({
|
|
453
|
+
autoAttach: true,
|
|
454
|
+
waitForDebuggerOnStart: false,
|
|
455
|
+
flatten: true
|
|
456
|
+
});
|
|
457
|
+
await c.Target.setDiscoverTargets({ discover: true });
|
|
458
|
+
c.on("Target.targetCreated", (rawParams) => {
|
|
459
|
+
const { targetInfo } = rawParams;
|
|
460
|
+
if (targetInfo.type === "page" && targetInfo.url === "chrome://newtab/") {
|
|
461
|
+
void c.Target.closeTarget({ targetId: targetInfo.targetId }).catch(() => {
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
c.on("Runtime.consoleAPICalled", (rawParams) => {
|
|
466
|
+
void (async () => {
|
|
467
|
+
const { type, args } = rawParams;
|
|
468
|
+
if (args[0]?.type === "string" && String(args[0].value).includes("Chrome Security")) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
const level = type === "warning" ? "warn" : ["log", "warn", "error", "info"].includes(type) ? type : "log";
|
|
472
|
+
const serialized = await Promise.all(args.map((arg) => serializeArgAsync(c, arg)));
|
|
473
|
+
opts.broadcast({ type: "console-message", level, args: serialized });
|
|
474
|
+
})().catch(() => {
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
const kill = () => {
|
|
478
|
+
clearInterval(cookieTimer);
|
|
479
|
+
try {
|
|
480
|
+
void c.close();
|
|
481
|
+
} catch {
|
|
482
|
+
}
|
|
483
|
+
chrome.kill();
|
|
484
|
+
};
|
|
485
|
+
return { kill };
|
|
486
|
+
}
|
|
240
487
|
|
|
241
488
|
// src/lib/proxyCache.ts
|
|
242
|
-
function createProxyCache() {
|
|
489
|
+
function createProxyCache(options = {}) {
|
|
243
490
|
const cache = /* @__PURE__ */ new Map();
|
|
491
|
+
const { onChange } = options;
|
|
492
|
+
const emitChange = () => {
|
|
493
|
+
onChange?.(cache.size);
|
|
494
|
+
};
|
|
244
495
|
return {
|
|
245
496
|
get(key, fetcher) {
|
|
246
497
|
const existing = cache.get(key);
|
|
@@ -258,24 +509,33 @@ function createProxyCache() {
|
|
|
258
509
|
};
|
|
259
510
|
}).catch((error) => {
|
|
260
511
|
cache.delete(key);
|
|
512
|
+
emitChange();
|
|
261
513
|
throw error;
|
|
262
514
|
});
|
|
263
515
|
cache.set(key, pending);
|
|
264
|
-
|
|
516
|
+
emitChange();
|
|
517
|
+
return pending.then((response) => {
|
|
518
|
+
if (response.status >= 400) {
|
|
519
|
+
cache.delete(key);
|
|
520
|
+
emitChange();
|
|
521
|
+
}
|
|
522
|
+
return { response, fromCache: false };
|
|
523
|
+
});
|
|
265
524
|
},
|
|
266
525
|
clear() {
|
|
267
526
|
cache.clear();
|
|
527
|
+
emitChange();
|
|
268
528
|
}
|
|
269
529
|
};
|
|
270
530
|
}
|
|
271
531
|
|
|
272
532
|
// src/lib/credentials.ts
|
|
273
|
-
import { mkdir as mkdir2, readFile as
|
|
533
|
+
import { mkdir as mkdir2, readFile as readFile3, readdir as readdir2, writeFile as writeFile2 } from "fs/promises";
|
|
274
534
|
import { homedir } from "os";
|
|
275
|
-
import { dirname, join as
|
|
535
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
276
536
|
var ENVIRONMENTS = ["go", "fmo", "staging", "integration", "test1"];
|
|
277
|
-
var GLOBAL_CREDENTIALS_DIR =
|
|
278
|
-
var GLOBAL_CREDENTIALS_PATH =
|
|
537
|
+
var GLOBAL_CREDENTIALS_DIR = join5(homedir(), ".kizenappbuilder");
|
|
538
|
+
var GLOBAL_CREDENTIALS_PATH = join5(GLOBAL_CREDENTIALS_DIR, "credentials.json");
|
|
279
539
|
var DEFAULT_PROFILE_NAME = "credentials";
|
|
280
540
|
function isValidEnvironment(value) {
|
|
281
541
|
return ENVIRONMENTS.includes(value);
|
|
@@ -294,7 +554,7 @@ function parseCredentials(raw) {
|
|
|
294
554
|
};
|
|
295
555
|
}
|
|
296
556
|
async function loadCredentialsFromFile(filePath) {
|
|
297
|
-
const content = await
|
|
557
|
+
const content = await readFile3(filePath, "utf-8");
|
|
298
558
|
return parseCredentials(JSON.parse(content));
|
|
299
559
|
}
|
|
300
560
|
async function loadGlobalCredentials() {
|
|
@@ -305,11 +565,11 @@ async function loadGlobalCredentials() {
|
|
|
305
565
|
}
|
|
306
566
|
}
|
|
307
567
|
async function saveGlobalCredentials(credentials) {
|
|
308
|
-
await mkdir2(
|
|
568
|
+
await mkdir2(dirname2(GLOBAL_CREDENTIALS_PATH), { recursive: true });
|
|
309
569
|
await writeFile2(GLOBAL_CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), "utf-8");
|
|
310
570
|
}
|
|
311
571
|
function getProfilePath(name) {
|
|
312
|
-
return
|
|
572
|
+
return join5(GLOBAL_CREDENTIALS_DIR, `${name}.json`);
|
|
313
573
|
}
|
|
314
574
|
async function listCredentialProfiles() {
|
|
315
575
|
const profiles = [
|
|
@@ -318,10 +578,14 @@ async function listCredentialProfiles() {
|
|
|
318
578
|
try {
|
|
319
579
|
const entries = await readdir2(GLOBAL_CREDENTIALS_DIR);
|
|
320
580
|
for (const entry of entries) {
|
|
321
|
-
if (!entry.endsWith(".json"))
|
|
581
|
+
if (!entry.endsWith(".json")) {
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
322
584
|
const name = entry.slice(0, -5);
|
|
323
|
-
if (name === DEFAULT_PROFILE_NAME)
|
|
324
|
-
|
|
585
|
+
if (name === DEFAULT_PROFILE_NAME) {
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
profiles.push({ name, path: join5(GLOBAL_CREDENTIALS_DIR, entry), isDefault: false });
|
|
325
589
|
}
|
|
326
590
|
} catch {
|
|
327
591
|
}
|
|
@@ -344,11 +608,11 @@ async function loadCredentialProfile(name) {
|
|
|
344
608
|
}
|
|
345
609
|
|
|
346
610
|
// src/lib/config.ts
|
|
347
|
-
import { mkdir as mkdir3, readFile as
|
|
348
|
-
import { join as
|
|
611
|
+
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
612
|
+
import { join as join6 } from "path";
|
|
349
613
|
async function loadConfig(outputDir) {
|
|
350
614
|
try {
|
|
351
|
-
const content = await
|
|
615
|
+
const content = await readFile4(join6(outputDir, "config.json"), "utf-8");
|
|
352
616
|
return JSON.parse(content);
|
|
353
617
|
} catch {
|
|
354
618
|
return {};
|
|
@@ -356,7 +620,7 @@ async function loadConfig(outputDir) {
|
|
|
356
620
|
}
|
|
357
621
|
async function saveConfig(outputDir, config) {
|
|
358
622
|
await mkdir3(outputDir, { recursive: true });
|
|
359
|
-
await writeFile3(
|
|
623
|
+
await writeFile3(join6(outputDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
360
624
|
}
|
|
361
625
|
|
|
362
626
|
// src/ui/CredentialSetupUI.tsx
|
|
@@ -383,7 +647,7 @@ var CredentialSetupUI = ({
|
|
|
383
647
|
const [error, setError] = useState2(null);
|
|
384
648
|
const [activeProfileName, setActiveProfileName] = useState2(void 0);
|
|
385
649
|
const handleModeChosen = useCallback(
|
|
386
|
-
|
|
650
|
+
(mode) => {
|
|
387
651
|
if (mode === "local") {
|
|
388
652
|
onComplete({ mode: "local", credentials: null });
|
|
389
653
|
return;
|
|
@@ -452,7 +716,7 @@ var CredentialSetupUI = ({
|
|
|
452
716
|
setPhase({ type: "mode-select", cursor: 1 });
|
|
453
717
|
} else if (key.return) {
|
|
454
718
|
const mode = phase.cursor === 0 ? "global" : "local";
|
|
455
|
-
|
|
719
|
+
handleModeChosen(mode);
|
|
456
720
|
}
|
|
457
721
|
return;
|
|
458
722
|
}
|
|
@@ -468,13 +732,16 @@ var CredentialSetupUI = ({
|
|
|
468
732
|
if (cursor === addNewIdx) {
|
|
469
733
|
setPhase({ type: "name-entry", nameBuffer: "", existingProfiles: profiles });
|
|
470
734
|
} else {
|
|
471
|
-
|
|
735
|
+
const selected = profiles[cursor] ?? profiles[0];
|
|
736
|
+
if (selected) {
|
|
737
|
+
void handleProfileChosen(selected);
|
|
738
|
+
}
|
|
472
739
|
}
|
|
473
740
|
}
|
|
474
741
|
return;
|
|
475
742
|
}
|
|
476
743
|
if (phase.type === "name-entry") {
|
|
477
|
-
const { nameBuffer,
|
|
744
|
+
const { nameBuffer, existingProfiles } = phase;
|
|
478
745
|
if (key.backspace || key.delete) {
|
|
479
746
|
setPhase({ type: "name-entry", nameBuffer: nameBuffer.slice(0, -1), existingProfiles });
|
|
480
747
|
} else if (key.return) {
|
|
@@ -619,7 +886,14 @@ var CredentialSetupUI = ({
|
|
|
619
886
|
}),
|
|
620
887
|
/* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
621
888
|
/* @__PURE__ */ jsx3(Text3, { ...cursor === addNewIdx && { color: "cyan" }, children: cursor === addNewIdx ? "\u276F" : " " }),
|
|
622
|
-
/* @__PURE__ */ jsx3(
|
|
889
|
+
/* @__PURE__ */ jsx3(
|
|
890
|
+
Text3,
|
|
891
|
+
{
|
|
892
|
+
bold: cursor === addNewIdx,
|
|
893
|
+
...cursor === addNewIdx && { color: "cyan" },
|
|
894
|
+
children: "+ Add new profile"
|
|
895
|
+
}
|
|
896
|
+
)
|
|
623
897
|
] })
|
|
624
898
|
] }),
|
|
625
899
|
/* @__PURE__ */ jsx3(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel" })
|
|
@@ -649,7 +923,7 @@ var CredentialSetupUI = ({
|
|
|
649
923
|
}
|
|
650
924
|
const { field: activeField, values, envCursor } = phase;
|
|
651
925
|
const isEnvField = activeField === FIELDS.length;
|
|
652
|
-
const profileLabel = activeProfileName
|
|
926
|
+
const profileLabel = activeProfileName ?? DEFAULT_PROFILE_NAME;
|
|
653
927
|
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
654
928
|
/* @__PURE__ */ jsx3(Logo, {}),
|
|
655
929
|
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
@@ -659,7 +933,8 @@ var CredentialSetupUI = ({
|
|
|
659
933
|
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
660
934
|
/* @__PURE__ */ jsx3(Text3, { bold: true, children: activeProfileName !== void 0 ? `Profile: ${activeProfileName}` : "Global credentials" }),
|
|
661
935
|
/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
|
|
662
|
-
"Saved to:
|
|
936
|
+
"Saved to:",
|
|
937
|
+
" ",
|
|
663
938
|
activeProfileName !== void 0 ? `~/.kizenappbuilder/${activeProfileName}.json` : GLOBAL_CREDENTIALS_PATH
|
|
664
939
|
] })
|
|
665
940
|
] }),
|
|
@@ -739,12 +1014,8 @@ var Spinner2 = () => {
|
|
|
739
1014
|
return /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: SPINNER_FRAMES2[frame] ?? "\u280B" });
|
|
740
1015
|
};
|
|
741
1016
|
function getViewerPath() {
|
|
742
|
-
const filename =
|
|
743
|
-
return
|
|
744
|
-
}
|
|
745
|
-
function getElectronMainPath() {
|
|
746
|
-
const filename = fileURLToPath(import.meta.url);
|
|
747
|
-
return join6(dirname2(filename), "electron", "main.js");
|
|
1017
|
+
const filename = fileURLToPath2(import.meta.url);
|
|
1018
|
+
return join7(dirname3(filename), "viewer");
|
|
748
1019
|
}
|
|
749
1020
|
async function fileExists(filePath) {
|
|
750
1021
|
try {
|
|
@@ -754,8 +1025,8 @@ async function fileExists(filePath) {
|
|
|
754
1025
|
return false;
|
|
755
1026
|
}
|
|
756
1027
|
}
|
|
757
|
-
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast) {
|
|
758
|
-
const proxyCache = createProxyCache();
|
|
1028
|
+
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast, onProxyCacheChange) {
|
|
1029
|
+
const proxyCache = createProxyCache({ onChange: onProxyCacheChange });
|
|
759
1030
|
return (req, res) => {
|
|
760
1031
|
void (async () => {
|
|
761
1032
|
const url = req.url ?? "/";
|
|
@@ -782,7 +1053,7 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
782
1053
|
const creds = profileName === void 0 || profileName === "" ? await loadGlobalCredentials() : await loadCredentialProfile(profileName);
|
|
783
1054
|
if (creds !== null) {
|
|
784
1055
|
credentialsRef.current = creds;
|
|
785
|
-
activeProfileRef.current = profileName
|
|
1056
|
+
activeProfileRef.current = profileName ?? void 0;
|
|
786
1057
|
const active = activeProfileRef.current;
|
|
787
1058
|
await saveConfig(outputDir, {
|
|
788
1059
|
credentialMode: "global",
|
|
@@ -795,9 +1066,9 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
795
1066
|
return;
|
|
796
1067
|
}
|
|
797
1068
|
if (url === "/api/bundle") {
|
|
798
|
-
const bundlePath =
|
|
1069
|
+
const bundlePath = join7(process.cwd(), ".kizenapp", "bundle.json");
|
|
799
1070
|
try {
|
|
800
|
-
const content = await
|
|
1071
|
+
const content = await readFile5(bundlePath, "utf-8");
|
|
801
1072
|
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
802
1073
|
res.end(content);
|
|
803
1074
|
} catch {
|
|
@@ -870,8 +1141,8 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
870
1141
|
return;
|
|
871
1142
|
}
|
|
872
1143
|
const rawPath = url === "/" ? "/index.html" : url;
|
|
873
|
-
const filePath =
|
|
874
|
-
const resolvedPath = await fileExists(filePath) ? filePath :
|
|
1144
|
+
const filePath = join7(viewerPath, rawPath);
|
|
1145
|
+
const resolvedPath = await fileExists(filePath) ? filePath : join7(viewerPath, "index.html");
|
|
875
1146
|
const ext = extname(resolvedPath);
|
|
876
1147
|
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
877
1148
|
res.writeHead(200, { "Content-Type": mimeType });
|
|
@@ -922,11 +1193,46 @@ var DevUI = ({
|
|
|
922
1193
|
const [buildError, setBuildError] = useState3(null);
|
|
923
1194
|
const [lastBuilt, setLastBuilt] = useState3(null);
|
|
924
1195
|
const [wsClientCount, setWsClientCount] = useState3(0);
|
|
1196
|
+
const [proxyCacheSize, setProxyCacheSize] = useState3(0);
|
|
1197
|
+
const [proxyCacheHits, setProxyCacheHits] = useState3(0);
|
|
1198
|
+
const [proxyCacheMisses, setProxyCacheMisses] = useState3(0);
|
|
925
1199
|
const buildingRef = useRef(false);
|
|
926
|
-
const
|
|
1200
|
+
const viewerLaunchedRef = useRef(false);
|
|
1201
|
+
const chromeHandleRef = useRef(null);
|
|
927
1202
|
const debounceTimerRef = useRef(null);
|
|
928
1203
|
const wsClientsRef = useRef(/* @__PURE__ */ new Set());
|
|
929
1204
|
const pendingMessagesRef = useRef([]);
|
|
1205
|
+
const broadcast = useCallback2((msg) => {
|
|
1206
|
+
const json = JSON.stringify(msg);
|
|
1207
|
+
if (wsClientsRef.current.size === 0) {
|
|
1208
|
+
pendingMessagesRef.current = [...pendingMessagesRef.current, json].slice(-LOG_LIMIT);
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
for (const client of wsClientsRef.current) {
|
|
1212
|
+
if (client.readyState === 1) {
|
|
1213
|
+
client.send(json);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
}, []);
|
|
1217
|
+
const createServerLog = useCallback2((message) => {
|
|
1218
|
+
setServerLogHistory(
|
|
1219
|
+
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
1220
|
+
);
|
|
1221
|
+
}, []);
|
|
1222
|
+
const launchChromeViewerCb = useCallback2(() => {
|
|
1223
|
+
chromeHandleRef.current?.kill();
|
|
1224
|
+
chromeHandleRef.current = null;
|
|
1225
|
+
void launchChromeViewer({
|
|
1226
|
+
port,
|
|
1227
|
+
userDataDir: join7(outputDir, ".chrome"),
|
|
1228
|
+
broadcast
|
|
1229
|
+
}).then((handle) => {
|
|
1230
|
+
chromeHandleRef.current = handle;
|
|
1231
|
+
process.on("exit", () => {
|
|
1232
|
+
handle.kill();
|
|
1233
|
+
});
|
|
1234
|
+
});
|
|
1235
|
+
}, [port, outputDir, broadcast]);
|
|
930
1236
|
useInput2(
|
|
931
1237
|
(input, key) => {
|
|
932
1238
|
if (input === "q" || key.ctrl && input === "c") {
|
|
@@ -935,50 +1241,19 @@ var DevUI = ({
|
|
|
935
1241
|
if (input === "c") {
|
|
936
1242
|
setCredMode("editing");
|
|
937
1243
|
}
|
|
938
|
-
if (input === "
|
|
939
|
-
|
|
1244
|
+
if (input === "v") {
|
|
1245
|
+
launchChromeViewerCb();
|
|
940
1246
|
}
|
|
941
1247
|
},
|
|
942
1248
|
{ isActive: credMode === "main" }
|
|
943
1249
|
);
|
|
944
1250
|
useEffect3(() => {
|
|
945
|
-
if (status !== "running" ||
|
|
1251
|
+
if (status !== "running" || viewerLaunchedRef.current) {
|
|
946
1252
|
return;
|
|
947
1253
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
const electronMain = getElectronMainPath();
|
|
952
|
-
const userDataDir = join6(outputDir, ".electron");
|
|
953
|
-
const proc = spawn(
|
|
954
|
-
electronBin,
|
|
955
|
-
[electronMain, `--port=${String(port)}`, `--user-data-dir=${userDataDir}`],
|
|
956
|
-
{
|
|
957
|
-
stdio: "ignore"
|
|
958
|
-
}
|
|
959
|
-
);
|
|
960
|
-
proc.unref();
|
|
961
|
-
process.on("exit", () => {
|
|
962
|
-
proc.kill();
|
|
963
|
-
});
|
|
964
|
-
}, [status, port, outputDir]);
|
|
965
|
-
const createServerLog = useCallback2((message) => {
|
|
966
|
-
setServerLogHistory(
|
|
967
|
-
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
968
|
-
);
|
|
969
|
-
}, []);
|
|
970
|
-
const broadcast = useCallback2((msg) => {
|
|
971
|
-
const json = JSON.stringify(msg);
|
|
972
|
-
if (wsClientsRef.current.size === 0) {
|
|
973
|
-
pendingMessagesRef.current = [...pendingMessagesRef.current, json].slice(-LOG_LIMIT);
|
|
974
|
-
return;
|
|
975
|
-
}
|
|
976
|
-
for (const client of wsClientsRef.current) {
|
|
977
|
-
if (client.readyState === 1) {
|
|
978
|
-
client.send(json);
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
}, []);
|
|
1254
|
+
viewerLaunchedRef.current = true;
|
|
1255
|
+
launchChromeViewerCb();
|
|
1256
|
+
}, [status, launchChromeViewerCb]);
|
|
982
1257
|
const handleCredentialsDone = useCallback2(
|
|
983
1258
|
(result) => {
|
|
984
1259
|
credentialsRef.current = result.credentials;
|
|
@@ -1001,6 +1276,13 @@ var DevUI = ({
|
|
|
1001
1276
|
-LOG_LIMIT
|
|
1002
1277
|
)
|
|
1003
1278
|
);
|
|
1279
|
+
if (entry.kind === "request") {
|
|
1280
|
+
if (entry.fromCache) {
|
|
1281
|
+
setProxyCacheHits((n) => n + 1);
|
|
1282
|
+
} else {
|
|
1283
|
+
setProxyCacheMisses((n) => n + 1);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1004
1286
|
broadcast({ type: "proxy-log", entry });
|
|
1005
1287
|
},
|
|
1006
1288
|
[broadcast]
|
|
@@ -1065,7 +1347,7 @@ var DevUI = ({
|
|
|
1065
1347
|
}, [pluginDir, triggerBuild, createBuildLog]);
|
|
1066
1348
|
useEffect3(() => {
|
|
1067
1349
|
const viewerPath = getViewerPath();
|
|
1068
|
-
void fileExists(
|
|
1350
|
+
void fileExists(join7(viewerPath, "index.html")).then((viewerBuilt) => {
|
|
1069
1351
|
if (!viewerBuilt) {
|
|
1070
1352
|
setErrorMessage("Viewer not built. Run 'pnpm build:viewer' first.");
|
|
1071
1353
|
setStatus("error");
|
|
@@ -1078,7 +1360,8 @@ var DevUI = ({
|
|
|
1078
1360
|
credentialsRef,
|
|
1079
1361
|
activeProfileRef,
|
|
1080
1362
|
outputDir,
|
|
1081
|
-
broadcast
|
|
1363
|
+
broadcast,
|
|
1364
|
+
setProxyCacheSize
|
|
1082
1365
|
);
|
|
1083
1366
|
const server = createServer(handler);
|
|
1084
1367
|
const wss = new WebSocketServer({ server });
|
|
@@ -1110,7 +1393,7 @@ var DevUI = ({
|
|
|
1110
1393
|
server.close();
|
|
1111
1394
|
};
|
|
1112
1395
|
});
|
|
1113
|
-
}, [port, createServerLog, createProxyLog]);
|
|
1396
|
+
}, [port, createServerLog, createProxyLog, broadcast, outputDir]);
|
|
1114
1397
|
if (credMode === "editing") {
|
|
1115
1398
|
return /* @__PURE__ */ jsx4(
|
|
1116
1399
|
CredentialSetupUI,
|
|
@@ -1134,7 +1417,7 @@ var DevUI = ({
|
|
|
1134
1417
|
] }),
|
|
1135
1418
|
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
|
|
1136
1419
|
/* @__PURE__ */ jsxs3(Box4, { gap: 2, marginBottom: 0, children: [
|
|
1137
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, dimColor: true, children: "Build" }),
|
|
1420
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, dimColor: true, children: "App Build" }),
|
|
1138
1421
|
buildStatus === "pending" && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "waiting\u2026" }),
|
|
1139
1422
|
buildStatus === "building" && /* @__PURE__ */ jsxs3(Box4, { gap: 1, children: [
|
|
1140
1423
|
/* @__PURE__ */ jsx4(Spinner2, {}),
|
|
@@ -1157,7 +1440,7 @@ var DevUI = ({
|
|
|
1157
1440
|
Box4,
|
|
1158
1441
|
{
|
|
1159
1442
|
flexDirection: "column",
|
|
1160
|
-
height: LOG_DISPLAY,
|
|
1443
|
+
height: LOG_DISPLAY + 2,
|
|
1161
1444
|
borderStyle: "single",
|
|
1162
1445
|
borderColor: "gray",
|
|
1163
1446
|
overflow: "hidden",
|
|
@@ -1167,7 +1450,7 @@ var DevUI = ({
|
|
|
1167
1450
|
] }),
|
|
1168
1451
|
/* @__PURE__ */ jsxs3(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
1169
1452
|
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1170
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, dimColor: true, children: "Server" }),
|
|
1453
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, dimColor: true, children: "Web Server" }),
|
|
1171
1454
|
status === "starting" && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "starting\u2026" }),
|
|
1172
1455
|
status === "running" && /* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1173
1456
|
/* @__PURE__ */ jsx4(Text4, { color: "green", children: "\u2713 Running" }),
|
|
@@ -1187,7 +1470,7 @@ var DevUI = ({
|
|
|
1187
1470
|
Box4,
|
|
1188
1471
|
{
|
|
1189
1472
|
flexDirection: "column",
|
|
1190
|
-
height: LOG_DISPLAY,
|
|
1473
|
+
height: LOG_DISPLAY + 2,
|
|
1191
1474
|
borderStyle: "single",
|
|
1192
1475
|
borderColor: "gray",
|
|
1193
1476
|
overflow: "hidden",
|
|
@@ -1197,14 +1480,26 @@ var DevUI = ({
|
|
|
1197
1480
|
] }),
|
|
1198
1481
|
/* @__PURE__ */ jsxs3(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
1199
1482
|
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1200
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, dimColor: true, children: "Proxy" }),
|
|
1201
|
-
/* @__PURE__ */ jsx4(Text4, { color: "green", children: "\u2713 Active" })
|
|
1483
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, dimColor: true, children: "Network Proxy" }),
|
|
1484
|
+
/* @__PURE__ */ jsx4(Text4, { color: "green", children: "\u2713 Active" }),
|
|
1485
|
+
/* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
|
|
1486
|
+
"\u25CF ",
|
|
1487
|
+
proxyCacheSize,
|
|
1488
|
+
" key",
|
|
1489
|
+
proxyCacheSize !== 1 ? "s" : "",
|
|
1490
|
+
" in the network cache \xB7",
|
|
1491
|
+
" ",
|
|
1492
|
+
proxyCacheHits,
|
|
1493
|
+
" hit \xB7 ",
|
|
1494
|
+
proxyCacheMisses,
|
|
1495
|
+
" miss"
|
|
1496
|
+
] })
|
|
1202
1497
|
] }),
|
|
1203
1498
|
/* @__PURE__ */ jsx4(
|
|
1204
1499
|
Box4,
|
|
1205
1500
|
{
|
|
1206
1501
|
flexDirection: "column",
|
|
1207
|
-
height: LOG_DISPLAY,
|
|
1502
|
+
height: LOG_DISPLAY + 2,
|
|
1208
1503
|
borderStyle: "single",
|
|
1209
1504
|
borderColor: "gray",
|
|
1210
1505
|
overflow: "hidden",
|
|
@@ -1218,8 +1513,11 @@ var DevUI = ({
|
|
|
1218
1513
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "] quit [" }),
|
|
1219
1514
|
/* @__PURE__ */ jsx4(Text4, { children: "c" }),
|
|
1220
1515
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "] credentials [" }),
|
|
1221
|
-
/* @__PURE__ */ jsx4(Text4, { children: "
|
|
1222
|
-
/* @__PURE__ */
|
|
1516
|
+
/* @__PURE__ */ jsx4(Text4, { children: "v" }),
|
|
1517
|
+
/* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
|
|
1518
|
+
"] ",
|
|
1519
|
+
wsClientCount === 0 ? "open viewer" : "relaunch viewer"
|
|
1520
|
+
] })
|
|
1223
1521
|
] })
|
|
1224
1522
|
] });
|
|
1225
1523
|
};
|