@kizenapps/cli 0.7.0 → 0.9.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/electron/main.js +9 -8
- package/dist/electron/main.js.map +1 -1
- package/dist/index.js +579 -114
- package/dist/index.js.map +1 -1
- package/dist/nwjs/shell/icon.png +0 -0
- package/dist/nwjs/shell/index.html +200 -0
- package/dist/nwjs/shell/package.json +16 -0
- package/dist/viewer/assets/fa-core-DAYjf9Yn.js +558 -0
- package/dist/viewer/assets/fa-core-Ff8SZmm_.js +558 -0
- package/dist/viewer/assets/index-47Vh9MH0.js +17 -0
- package/dist/viewer/assets/index-6uunWX8M.js +17 -0
- package/dist/viewer/assets/index-B48OpZHg.js +17 -0
- package/dist/viewer/assets/index-BFfw7eD7.js +17 -0
- package/dist/viewer/assets/index-BFyUUb06.js +17 -0
- package/dist/viewer/assets/index-BL-Yu7Bf.js +17 -0
- package/dist/viewer/assets/index-BUmv8vz7.js +17 -0
- package/dist/viewer/assets/index-BZ4HmEz8.js +17 -0
- package/dist/viewer/assets/index-BZIXccTd.js +17 -0
- package/dist/viewer/assets/index-Bk9hnfnO.js +17 -0
- package/dist/viewer/assets/index-C0SIHm9A.js +17 -0
- package/dist/viewer/assets/index-CDd-WK6Y.js +17 -0
- package/dist/viewer/assets/index-CDxQqP40.js +17 -0
- package/dist/viewer/assets/{index-C_6izRRh.js → index-CGJzvpL5.js} +7 -7
- package/dist/viewer/assets/index-CIarX3Lt.js +17 -0
- package/dist/viewer/assets/index-CIfVP45E.js +17 -0
- package/dist/viewer/assets/index-CJeb7uFu.css +2 -0
- package/dist/viewer/assets/index-CbwLb2S_.js +17 -0
- package/dist/viewer/assets/index-CsfWgoID.js +17 -0
- package/dist/viewer/assets/index-CvWmkIY5.js +17 -0
- package/dist/viewer/assets/index-Cy-weKfG.css +2 -0
- package/dist/viewer/assets/index-Cym12l2M.js +17 -0
- package/dist/viewer/assets/index-D0W0oANg.js +17 -0
- package/dist/viewer/assets/index-DCPtqd3W.js +17 -0
- package/dist/viewer/assets/index-DF_zYdLw.js +17 -0
- package/dist/viewer/assets/index-DGqxQcUx.js +17 -0
- package/dist/viewer/assets/index-DK0OVb7V.js +17 -0
- package/dist/viewer/assets/index-DKjVFdzw.js +17 -0
- package/dist/viewer/assets/index-DLhj0I_2.js +17 -0
- package/dist/viewer/assets/index-DPS_ZjbM.js +17 -0
- package/dist/viewer/assets/index-DSbHkhcS.js +17 -0
- package/dist/viewer/assets/index-DTbmNtEU.js +17 -0
- package/dist/viewer/assets/index-DUYd6RpI.js +17 -0
- package/dist/viewer/assets/index-DZwYe1wZ.css +2 -0
- package/dist/viewer/assets/index-DkRokbYc.js +17 -0
- package/dist/viewer/assets/index-DtOWzkR5.js +17 -0
- package/dist/viewer/assets/index-DuvXujkm.js +17 -0
- package/dist/viewer/assets/index-Dv0mX-oM.js +17 -0
- package/dist/viewer/assets/index-DyXisBY9.css +2 -0
- package/dist/viewer/assets/index-Nm1xKWTO.js +17 -0
- package/dist/viewer/assets/index-ZBdAq6dF.js +17 -0
- package/dist/viewer/assets/index-ZOxL_JJZ.js +17 -0
- package/dist/viewer/assets/index-kMMOwjlY.js +17 -0
- package/dist/viewer/assets/{index--m1PKX6N.js → index-ov2oU6RI.js} +7 -7
- package/dist/viewer/assets/index-uF6u0kT8.js +17 -0
- package/dist/viewer/assets/index-xbDHMSaa.css +2 -0
- package/dist/viewer/assets/react-D7PmSb6e.js +9 -0
- package/dist/viewer/assets/react-DIjeYlvh.js +9 -0
- package/dist/viewer/index.html +4 -4
- package/package.json +4 -4
- package/dist/viewer/assets/index-2OcBnmZB.js +0 -17
- package/dist/viewer/assets/index-7ah1RuPy.js +0 -17
- package/dist/viewer/assets/index-B3gNsKTt.js +0 -17
- package/dist/viewer/assets/index-B40AtXqk.js +0 -17
- package/dist/viewer/assets/index-B4ikC-wc.js +0 -17
- package/dist/viewer/assets/index-BKOfPpLS.js +0 -17
- package/dist/viewer/assets/index-BM3JrC-1.js +0 -17
- package/dist/viewer/assets/index-BUnK11-F.js +0 -17
- package/dist/viewer/assets/index-Bc7IZVr6.js +0 -17
- package/dist/viewer/assets/index-C1KzcpVj.js +0 -17
- package/dist/viewer/assets/index-CBBwr2o_.js +0 -17
- package/dist/viewer/assets/index-CHtXWYIY.js +0 -17
- package/dist/viewer/assets/index-CN9NvJkQ.js +0 -17
- package/dist/viewer/assets/index-CNKPBxhv.js +0 -17
- package/dist/viewer/assets/index-CgzK6zig.js +0 -17
- package/dist/viewer/assets/index-Cw2cxYy2.js +0 -17
- package/dist/viewer/assets/index-D06uhGtQ.js +0 -17
- package/dist/viewer/assets/index-DAHWT-g0.js +0 -17
- package/dist/viewer/assets/index-DAxJgHat.js +0 -17
- package/dist/viewer/assets/index-DF_geUaW.js +0 -17
- package/dist/viewer/assets/index-DUgUEouL.css +0 -2
- package/dist/viewer/assets/index-DcGGXuA3.js +0 -17
- package/dist/viewer/assets/index-DlVmY-nR.js +0 -17
- package/dist/viewer/assets/index-FZw9Ev_R.js +0 -17
- package/dist/viewer/assets/index-M1Obm_99.js +0 -17
- package/dist/viewer/assets/index-_kM1Ri7v.js +0 -17
- package/dist/viewer/assets/index-aTt_sTlu.js +0 -17
- package/dist/viewer/assets/index-vYFGGFc2.js +0 -17
package/dist/index.js
CHANGED
|
@@ -229,14 +229,231 @@ 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") return Number(prop.value);
|
|
263
|
+
if (prop.type === "boolean") return prop.value === "true";
|
|
264
|
+
if (prop.type === "undefined") return void 0;
|
|
265
|
+
if (prop.type === "object" && prop.value === "null") return null;
|
|
266
|
+
if (prop.type === "object" && prop.valuePreview) {
|
|
267
|
+
const { valuePreview } = prop;
|
|
268
|
+
if (valuePreview.subtype === "array") {
|
|
269
|
+
return valuePreview.properties.filter((p) => /^\d+$/.test(p.name)).sort((a, b) => parseInt(a.name) - parseInt(b.name)).map(parseProp);
|
|
270
|
+
}
|
|
271
|
+
const obj = {};
|
|
272
|
+
for (const p of valuePreview.properties) obj[p.name] = parseProp(p);
|
|
273
|
+
return obj;
|
|
274
|
+
}
|
|
275
|
+
return prop.value ?? `[${prop.type}]`;
|
|
276
|
+
}
|
|
277
|
+
function serializeArg(arg) {
|
|
278
|
+
if (arg.value !== void 0) return arg.value;
|
|
279
|
+
if (arg.preview) {
|
|
280
|
+
const { preview } = arg;
|
|
281
|
+
if (preview.subtype === "array") {
|
|
282
|
+
return preview.properties.filter((p) => /^\d+$/.test(p.name)).sort((a, b) => parseInt(a.name) - parseInt(b.name)).map(parseProp);
|
|
283
|
+
}
|
|
284
|
+
const obj = {};
|
|
285
|
+
for (const prop of preview.properties) obj[prop.name] = parseProp(prop);
|
|
286
|
+
return obj;
|
|
287
|
+
}
|
|
288
|
+
return arg.description ?? `[${arg.type}]`;
|
|
289
|
+
}
|
|
290
|
+
async function serializeArgAsync(client, arg) {
|
|
291
|
+
if (arg.type === "object" && arg.objectId) {
|
|
292
|
+
try {
|
|
293
|
+
const result = await client.Runtime.callFunctionOn({
|
|
294
|
+
objectId: arg.objectId,
|
|
295
|
+
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; }); }',
|
|
296
|
+
returnByValue: true
|
|
297
|
+
});
|
|
298
|
+
const val = result.result.value;
|
|
299
|
+
if (typeof val === "string") return JSON.parse(val);
|
|
300
|
+
} catch {
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return serializeArg(arg);
|
|
304
|
+
}
|
|
305
|
+
async function installDockIcon(client) {
|
|
306
|
+
try {
|
|
307
|
+
const iconPath = join4(dirname(fileURLToPath(import.meta.url)), "viewer", "icon.png");
|
|
308
|
+
const icon = await readFile2(iconPath);
|
|
309
|
+
await client.Browser.setDockTile({ image: icon.toString("base64") });
|
|
310
|
+
} catch {
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
async function launchChromeViewer(opts) {
|
|
314
|
+
mkdirSync(opts.userDataDir, { recursive: true });
|
|
315
|
+
const chrome = await launch({
|
|
316
|
+
startingUrl: `http://localhost:${opts.port}`,
|
|
317
|
+
chromeFlags: [
|
|
318
|
+
`--app=http://localhost:${opts.port}`,
|
|
319
|
+
"--no-first-run",
|
|
320
|
+
"--no-default-browser-check",
|
|
321
|
+
"--disable-extensions"
|
|
322
|
+
],
|
|
323
|
+
userDataDir: opts.userDataDir,
|
|
324
|
+
handleSIGINT: false,
|
|
325
|
+
logLevel: "silent"
|
|
326
|
+
});
|
|
327
|
+
let client = null;
|
|
328
|
+
let cookieTimer = null;
|
|
329
|
+
let cdpPort = chrome.port;
|
|
330
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
331
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
332
|
+
try {
|
|
333
|
+
client = await CDP({ port: cdpPort });
|
|
334
|
+
break;
|
|
335
|
+
} catch {
|
|
336
|
+
if (attempt === 9) {
|
|
337
|
+
return {
|
|
338
|
+
kill: () => chrome.kill()
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (!client) {
|
|
344
|
+
return {
|
|
345
|
+
kill: () => chrome.kill()
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const c = client;
|
|
349
|
+
await installDockIcon(c);
|
|
350
|
+
await c.Fetch.enable({
|
|
351
|
+
patterns: KIZEN_DOMAINS.flatMap((d) => [
|
|
352
|
+
{ urlPattern: `*://${d}/*`, requestStage: "Response" },
|
|
353
|
+
{ urlPattern: `*://*.${d}/*`, requestStage: "Response" }
|
|
354
|
+
])
|
|
355
|
+
});
|
|
356
|
+
c.on("Fetch.requestPaused", (rawParams) => {
|
|
357
|
+
void (async () => {
|
|
358
|
+
const params = rawParams;
|
|
359
|
+
const { requestId, request, responseHeaders, responseStatusCode } = params;
|
|
360
|
+
const url = request?.url ?? "";
|
|
361
|
+
const filtered = [];
|
|
362
|
+
for (const h of responseHeaders ?? []) {
|
|
363
|
+
if (CSP_HEADERS.has(h.name.toLowerCase())) continue;
|
|
364
|
+
if (h.name.toLowerCase() === "set-cookie" && isKizenUrl(url)) {
|
|
365
|
+
const patched = h.value.split("\n").map((cookie) => {
|
|
366
|
+
if (!/SameSite=/i.test(cookie)) return cookie + "; SameSite=None; Secure";
|
|
367
|
+
return cookie.replace(/SameSite=\w+/i, "SameSite=None");
|
|
368
|
+
}).join("\n");
|
|
369
|
+
filtered.push({ name: h.name, value: patched });
|
|
370
|
+
} else {
|
|
371
|
+
filtered.push(h);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
const { body, base64Encoded } = await c.Fetch.getResponseBody({ requestId });
|
|
376
|
+
await c.Fetch.fulfillRequest({
|
|
377
|
+
requestId,
|
|
378
|
+
responseCode: responseStatusCode ?? 200,
|
|
379
|
+
responseHeaders: filtered,
|
|
380
|
+
body,
|
|
381
|
+
...base64Encoded && { base64Encoded: true }
|
|
382
|
+
});
|
|
383
|
+
} catch {
|
|
384
|
+
try {
|
|
385
|
+
await c.Fetch.continueRequest({ requestId });
|
|
386
|
+
} catch {
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
})();
|
|
390
|
+
});
|
|
391
|
+
cookieTimer = setInterval(() => {
|
|
392
|
+
void (async () => {
|
|
393
|
+
try {
|
|
394
|
+
const { cookies } = await c.Network.getAllCookies();
|
|
395
|
+
for (const cookie of cookies) {
|
|
396
|
+
if (!isKizenUrl(`https://${cookie.domain ?? ""}`)) continue;
|
|
397
|
+
if (cookie.sameSite === "None") continue;
|
|
398
|
+
const raw = cookie.domain ?? "";
|
|
399
|
+
const bare = raw.startsWith(".") ? raw.slice(1) : raw;
|
|
400
|
+
await c.Network.setCookie({
|
|
401
|
+
url: `https://${bare}`,
|
|
402
|
+
name: cookie.name,
|
|
403
|
+
value: cookie.value,
|
|
404
|
+
domain: raw,
|
|
405
|
+
path: cookie.path ?? "/",
|
|
406
|
+
secure: true,
|
|
407
|
+
...cookie.httpOnly !== void 0 && { httpOnly: cookie.httpOnly },
|
|
408
|
+
...cookie.expirationDate !== void 0 && {
|
|
409
|
+
expires: cookie.expirationDate
|
|
410
|
+
},
|
|
411
|
+
sameSite: "None"
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
} catch {
|
|
415
|
+
}
|
|
416
|
+
})();
|
|
417
|
+
}, 2e3);
|
|
418
|
+
await c.send("Runtime.enable", { generatePreview: true });
|
|
419
|
+
c.on("Target.attachedToTarget", (rawParams) => {
|
|
420
|
+
const { sessionId } = rawParams;
|
|
421
|
+
void c.send("Runtime.enable", { generatePreview: true }, sessionId).catch(() => {
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
await c.Target.setAutoAttach({
|
|
425
|
+
autoAttach: true,
|
|
426
|
+
waitForDebuggerOnStart: false,
|
|
427
|
+
flatten: true
|
|
428
|
+
});
|
|
429
|
+
await c.Target.setDiscoverTargets({ discover: true });
|
|
430
|
+
c.on("Target.targetCreated", (rawParams) => {
|
|
431
|
+
const { targetInfo } = rawParams;
|
|
432
|
+
if (targetInfo.type === "page" && targetInfo.url === "chrome://newtab/") {
|
|
433
|
+
void c.Target.closeTarget({ targetId: targetInfo.targetId }).catch(() => {
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
c.on("Runtime.consoleAPICalled", (rawParams) => {
|
|
438
|
+
void (async () => {
|
|
439
|
+
const { type, args } = rawParams;
|
|
440
|
+
if (args[0]?.type === "string" && String(args[0].value).includes("Chrome Security")) return;
|
|
441
|
+
const level = type === "warning" ? "warn" : ["log", "warn", "error", "info"].includes(type) ? type : "log";
|
|
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
|
+
}
|
|
240
457
|
|
|
241
458
|
// src/lib/proxyCache.ts
|
|
242
459
|
function createProxyCache() {
|
|
@@ -269,33 +486,14 @@ function createProxyCache() {
|
|
|
269
486
|
};
|
|
270
487
|
}
|
|
271
488
|
|
|
272
|
-
// src/lib/config.ts
|
|
273
|
-
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
274
|
-
import { join as join4 } from "path";
|
|
275
|
-
async function loadConfig(outputDir) {
|
|
276
|
-
try {
|
|
277
|
-
const content = await readFile2(join4(outputDir, "config.json"), "utf-8");
|
|
278
|
-
return JSON.parse(content);
|
|
279
|
-
} catch {
|
|
280
|
-
return {};
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
async function saveConfig(outputDir, config) {
|
|
284
|
-
await mkdir2(outputDir, { recursive: true });
|
|
285
|
-
await writeFile2(join4(outputDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// src/ui/CredentialSetupUI.tsx
|
|
289
|
-
import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";
|
|
290
|
-
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
291
|
-
|
|
292
489
|
// src/lib/credentials.ts
|
|
293
|
-
import { mkdir as
|
|
490
|
+
import { mkdir as mkdir2, readFile as readFile3, readdir as readdir2, writeFile as writeFile2 } from "fs/promises";
|
|
294
491
|
import { homedir } from "os";
|
|
295
|
-
import { dirname, join as join5 } from "path";
|
|
492
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
296
493
|
var ENVIRONMENTS = ["go", "fmo", "staging", "integration", "test1"];
|
|
297
494
|
var GLOBAL_CREDENTIALS_DIR = join5(homedir(), ".kizenappbuilder");
|
|
298
495
|
var GLOBAL_CREDENTIALS_PATH = join5(GLOBAL_CREDENTIALS_DIR, "credentials.json");
|
|
496
|
+
var DEFAULT_PROFILE_NAME = "credentials";
|
|
299
497
|
function isValidEnvironment(value) {
|
|
300
498
|
return ENVIRONMENTS.includes(value);
|
|
301
499
|
}
|
|
@@ -324,11 +522,67 @@ async function loadGlobalCredentials() {
|
|
|
324
522
|
}
|
|
325
523
|
}
|
|
326
524
|
async function saveGlobalCredentials(credentials) {
|
|
327
|
-
await
|
|
328
|
-
await
|
|
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;
|
|
544
|
+
}
|
|
545
|
+
profiles.push({ name, path: join5(GLOBAL_CREDENTIALS_DIR, entry), isDefault: false });
|
|
546
|
+
}
|
|
547
|
+
} catch {
|
|
548
|
+
}
|
|
549
|
+
return profiles;
|
|
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
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// src/lib/config.ts
|
|
568
|
+
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
569
|
+
import { join as join6 } from "path";
|
|
570
|
+
async function loadConfig(outputDir) {
|
|
571
|
+
try {
|
|
572
|
+
const content = await readFile4(join6(outputDir, "config.json"), "utf-8");
|
|
573
|
+
return JSON.parse(content);
|
|
574
|
+
} catch {
|
|
575
|
+
return {};
|
|
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");
|
|
329
581
|
}
|
|
330
582
|
|
|
331
583
|
// src/ui/CredentialSetupUI.tsx
|
|
584
|
+
import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";
|
|
585
|
+
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
332
586
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
333
587
|
var FIELDS = ["apiKey", "userId", "businessId"];
|
|
334
588
|
var FIELD_LABELS = {
|
|
@@ -339,32 +593,39 @@ var FIELD_LABELS = {
|
|
|
339
593
|
var Hint = ({ text }) => /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: text });
|
|
340
594
|
var CredentialSetupUI = ({
|
|
341
595
|
initialMode,
|
|
596
|
+
showProfileManager,
|
|
342
597
|
onComplete,
|
|
343
598
|
onCancel
|
|
344
599
|
}) => {
|
|
345
600
|
const [phase, setPhase] = useState2(
|
|
346
|
-
initialMode === "global" ? { type: "loading" } : { type: "mode-select", cursor: 0 }
|
|
601
|
+
initialMode === "global" && !showProfileManager ? { type: "loading" } : initialMode === "global" && showProfileManager ? { type: "profile-loading" } : { type: "mode-select", cursor: 0 }
|
|
347
602
|
);
|
|
348
603
|
const [inputBuffer, setInputBuffer] = useState2("");
|
|
349
604
|
const [error, setError] = useState2(null);
|
|
605
|
+
const [activeProfileName, setActiveProfileName] = useState2(void 0);
|
|
350
606
|
const handleModeChosen = useCallback(
|
|
351
|
-
|
|
607
|
+
(mode) => {
|
|
352
608
|
if (mode === "local") {
|
|
353
609
|
onComplete({ mode: "local", credentials: null });
|
|
354
610
|
return;
|
|
355
611
|
}
|
|
356
|
-
setPhase({ type: "loading" });
|
|
357
|
-
const existing = await loadGlobalCredentials();
|
|
358
|
-
const envCursor2 = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;
|
|
359
|
-
setPhase({
|
|
360
|
-
type: "creds-entry",
|
|
361
|
-
field: 0,
|
|
362
|
-
values: existing ?? {},
|
|
363
|
-
envCursor: envCursor2
|
|
364
|
-
});
|
|
612
|
+
setPhase({ type: "profile-loading" });
|
|
365
613
|
},
|
|
366
614
|
[onComplete]
|
|
367
615
|
);
|
|
616
|
+
const handleProfileChosen = useCallback(async (profile) => {
|
|
617
|
+
if (profile === null) {
|
|
618
|
+
setPhase({ type: "profile-loading" });
|
|
619
|
+
const profiles = await listCredentialProfiles();
|
|
620
|
+
setPhase({ type: "name-entry", nameBuffer: "", existingProfiles: profiles });
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
setActiveProfileName(profile.isDefault ? void 0 : profile.name);
|
|
624
|
+
setPhase({ type: "loading" });
|
|
625
|
+
const existing = profile.isDefault ? await loadGlobalCredentials() : await loadCredentialProfile(profile.name);
|
|
626
|
+
const envCursor2 = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;
|
|
627
|
+
setPhase({ type: "creds-entry", field: 0, values: existing ?? {}, envCursor: envCursor2 });
|
|
628
|
+
}, []);
|
|
368
629
|
const handleSave = useCallback(
|
|
369
630
|
async (values2, envCursor2) => {
|
|
370
631
|
const environment = ENVIRONMENTS[envCursor2] ?? "go";
|
|
@@ -376,20 +637,32 @@ var CredentialSetupUI = ({
|
|
|
376
637
|
};
|
|
377
638
|
setPhase({ type: "saving" });
|
|
378
639
|
try {
|
|
379
|
-
|
|
380
|
-
|
|
640
|
+
const profileName = activeProfileName ?? DEFAULT_PROFILE_NAME;
|
|
641
|
+
await saveCredentialProfile(profileName, credentials);
|
|
642
|
+
onComplete({
|
|
643
|
+
mode: "global",
|
|
644
|
+
credentials,
|
|
645
|
+
...activeProfileName !== void 0 && { profileName: activeProfileName }
|
|
646
|
+
});
|
|
381
647
|
} catch (err) {
|
|
382
648
|
setError(err instanceof Error ? err.message : String(err));
|
|
383
649
|
setPhase({ type: "creds-entry", field: 0, values: values2, envCursor: envCursor2 });
|
|
384
650
|
}
|
|
385
651
|
},
|
|
386
|
-
[onComplete]
|
|
652
|
+
[onComplete, activeProfileName]
|
|
387
653
|
);
|
|
388
654
|
useInput((input, key) => {
|
|
389
655
|
if (key.ctrl && input === "c") {
|
|
390
656
|
process.exit(0);
|
|
391
657
|
}
|
|
392
658
|
if (key.escape) {
|
|
659
|
+
if (phase.type === "creds-entry" || phase.type === "name-entry") {
|
|
660
|
+
if (initialMode === "global" && showProfileManager) {
|
|
661
|
+
setPhase({ type: "profile-loading" });
|
|
662
|
+
void loadProfileList();
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
393
666
|
onCancel?.();
|
|
394
667
|
return;
|
|
395
668
|
}
|
|
@@ -400,7 +673,53 @@ var CredentialSetupUI = ({
|
|
|
400
673
|
setPhase({ type: "mode-select", cursor: 1 });
|
|
401
674
|
} else if (key.return) {
|
|
402
675
|
const mode = phase.cursor === 0 ? "global" : "local";
|
|
403
|
-
|
|
676
|
+
handleModeChosen(mode);
|
|
677
|
+
}
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
if (phase.type === "profile-select") {
|
|
681
|
+
const { profiles, cursor } = phase;
|
|
682
|
+
const addNewIdx = profiles.length;
|
|
683
|
+
const totalItems = profiles.length + 1;
|
|
684
|
+
if (key.upArrow) {
|
|
685
|
+
setPhase({ ...phase, cursor: (cursor - 1 + totalItems) % totalItems });
|
|
686
|
+
} else if (key.downArrow) {
|
|
687
|
+
setPhase({ ...phase, cursor: (cursor + 1) % totalItems });
|
|
688
|
+
} else if (key.return) {
|
|
689
|
+
if (cursor === addNewIdx) {
|
|
690
|
+
setPhase({ type: "name-entry", nameBuffer: "", existingProfiles: profiles });
|
|
691
|
+
} else {
|
|
692
|
+
const selected = profiles[cursor] ?? profiles[0];
|
|
693
|
+
if (selected) {
|
|
694
|
+
void handleProfileChosen(selected);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
if (phase.type === "name-entry") {
|
|
701
|
+
const { nameBuffer, existingProfiles } = phase;
|
|
702
|
+
if (key.backspace || key.delete) {
|
|
703
|
+
setPhase({ type: "name-entry", nameBuffer: nameBuffer.slice(0, -1), existingProfiles });
|
|
704
|
+
} else if (key.return) {
|
|
705
|
+
const trimmed = nameBuffer.trim();
|
|
706
|
+
if (!trimmed) {
|
|
707
|
+
setPhase({ ...phase, nameError: "Name cannot be empty" });
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
if (trimmed === DEFAULT_PROFILE_NAME) {
|
|
711
|
+
setPhase({ ...phase, nameError: `"${DEFAULT_PROFILE_NAME}" is reserved` });
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
if (existingProfiles.some((p) => p.name === trimmed)) {
|
|
715
|
+
setPhase({ ...phase, nameError: `Profile "${trimmed}" already exists` });
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
setActiveProfileName(trimmed);
|
|
719
|
+
setPhase({ type: "creds-entry", field: 0, values: {}, envCursor: 0 });
|
|
720
|
+
setInputBuffer("");
|
|
721
|
+
} else if (input && !key.ctrl && !key.meta) {
|
|
722
|
+
setPhase({ type: "name-entry", nameBuffer: nameBuffer + input, existingProfiles });
|
|
404
723
|
}
|
|
405
724
|
return;
|
|
406
725
|
}
|
|
@@ -448,9 +767,22 @@ var CredentialSetupUI = ({
|
|
|
448
767
|
}
|
|
449
768
|
}
|
|
450
769
|
});
|
|
770
|
+
const loadProfileList = useCallback(async () => {
|
|
771
|
+
const profiles = await listCredentialProfiles();
|
|
772
|
+
setPhase({ type: "profile-select", profiles, cursor: 0 });
|
|
773
|
+
}, []);
|
|
451
774
|
useEffect2(() => {
|
|
452
|
-
if (
|
|
453
|
-
void
|
|
775
|
+
if (phase.type === "profile-loading") {
|
|
776
|
+
void loadProfileList();
|
|
777
|
+
}
|
|
778
|
+
}, [phase.type, loadProfileList]);
|
|
779
|
+
useEffect2(() => {
|
|
780
|
+
if (initialMode === "global" && !showProfileManager) {
|
|
781
|
+
void (async () => {
|
|
782
|
+
const existing = await loadGlobalCredentials();
|
|
783
|
+
const envCursor2 = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;
|
|
784
|
+
setPhase({ type: "creds-entry", field: 0, values: existing ?? {}, envCursor: envCursor2 });
|
|
785
|
+
})();
|
|
454
786
|
}
|
|
455
787
|
}, []);
|
|
456
788
|
useEffect2(() => {
|
|
@@ -458,8 +790,9 @@ var CredentialSetupUI = ({
|
|
|
458
790
|
setInputBuffer(phase.values.apiKey ?? "");
|
|
459
791
|
}
|
|
460
792
|
}, [phase.type]);
|
|
461
|
-
if (phase.type === "loading" || phase.type === "saving") {
|
|
462
|
-
|
|
793
|
+
if (phase.type === "loading" || phase.type === "saving" || phase.type === "profile-loading") {
|
|
794
|
+
const label = phase.type === "saving" ? "Saving credentials\u2026" : phase.type === "profile-loading" ? "Loading profiles\u2026" : "Loading credentials\u2026";
|
|
795
|
+
return /* @__PURE__ */ jsx3(Box3, { paddingY: 1, paddingX: 2, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: label }) });
|
|
463
796
|
}
|
|
464
797
|
if (phase.type === "done") {
|
|
465
798
|
return null;
|
|
@@ -489,8 +822,65 @@ var CredentialSetupUI = ({
|
|
|
489
822
|
/* @__PURE__ */ jsx3(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit" })
|
|
490
823
|
] });
|
|
491
824
|
}
|
|
825
|
+
if (phase.type === "profile-select") {
|
|
826
|
+
const { profiles, cursor } = phase;
|
|
827
|
+
const addNewIdx = profiles.length;
|
|
828
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
829
|
+
/* @__PURE__ */ jsx3(Logo, {}),
|
|
830
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
831
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
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" }),
|
|
836
|
+
profiles.map((profile, i) => {
|
|
837
|
+
const selected = cursor === i;
|
|
838
|
+
return /* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
839
|
+
/* @__PURE__ */ jsx3(Text3, { ...selected && { color: "cyan" }, children: selected ? "\u276F" : " " }),
|
|
840
|
+
/* @__PURE__ */ jsx3(Text3, { bold: selected, ...selected && { color: "cyan" }, children: profile.isDefault ? "Default" : profile.name }),
|
|
841
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: profile.path })
|
|
842
|
+
] }, profile.name);
|
|
843
|
+
}),
|
|
844
|
+
/* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
845
|
+
/* @__PURE__ */ jsx3(Text3, { ...cursor === addNewIdx && { color: "cyan" }, children: cursor === addNewIdx ? "\u276F" : " " }),
|
|
846
|
+
/* @__PURE__ */ jsx3(
|
|
847
|
+
Text3,
|
|
848
|
+
{
|
|
849
|
+
bold: cursor === addNewIdx,
|
|
850
|
+
...cursor === addNewIdx && { color: "cyan" },
|
|
851
|
+
children: "+ Add new profile"
|
|
852
|
+
}
|
|
853
|
+
)
|
|
854
|
+
] })
|
|
855
|
+
] }),
|
|
856
|
+
/* @__PURE__ */ jsx3(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel" })
|
|
857
|
+
] });
|
|
858
|
+
}
|
|
859
|
+
if (phase.type === "name-entry") {
|
|
860
|
+
const { nameBuffer, nameError } = phase;
|
|
861
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
862
|
+
/* @__PURE__ */ jsx3(Logo, {}),
|
|
863
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
864
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
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: [
|
|
869
|
+
"Error: ",
|
|
870
|
+
nameError
|
|
871
|
+
] }),
|
|
872
|
+
/* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
873
|
+
/* @__PURE__ */ jsx3(Box3, { width: 12, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "Profile name" }) }),
|
|
874
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: ">" }),
|
|
875
|
+
/* @__PURE__ */ jsx3(Text3, { children: nameBuffer }),
|
|
876
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "\u2588" })
|
|
877
|
+
] }),
|
|
878
|
+
/* @__PURE__ */ jsx3(Hint, { text: "Type a name \xB7 Enter to confirm \xB7 Esc to go back" })
|
|
879
|
+
] });
|
|
880
|
+
}
|
|
492
881
|
const { field: activeField, values, envCursor } = phase;
|
|
493
882
|
const isEnvField = activeField === FIELDS.length;
|
|
883
|
+
const profileLabel = activeProfileName ?? DEFAULT_PROFILE_NAME;
|
|
494
884
|
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
495
885
|
/* @__PURE__ */ jsx3(Logo, {}),
|
|
496
886
|
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
@@ -498,10 +888,11 @@ var CredentialSetupUI = ({
|
|
|
498
888
|
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
499
889
|
] }),
|
|
500
890
|
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
501
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Global credentials" }),
|
|
891
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: activeProfileName !== void 0 ? `Profile: ${activeProfileName}` : "Global credentials" }),
|
|
502
892
|
/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
|
|
503
|
-
"Saved to:
|
|
504
|
-
|
|
893
|
+
"Saved to:",
|
|
894
|
+
" ",
|
|
895
|
+
activeProfileName !== void 0 ? `~/.kizenappbuilder/${activeProfileName}.json` : GLOBAL_CREDENTIALS_PATH
|
|
505
896
|
] })
|
|
506
897
|
] }),
|
|
507
898
|
error && /* @__PURE__ */ jsxs2(Text3, { color: "red", children: [
|
|
@@ -531,7 +922,11 @@ var CredentialSetupUI = ({
|
|
|
531
922
|
}) })
|
|
532
923
|
] })
|
|
533
924
|
] }),
|
|
534
|
-
isEnvField ? /* @__PURE__ */ jsx3(Hint, { text: "\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel" }) : /* @__PURE__ */ jsx3(Hint, { text: "\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel" })
|
|
925
|
+
isEnvField ? /* @__PURE__ */ jsx3(Hint, { text: "\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel" }) : /* @__PURE__ */ jsx3(Hint, { text: "\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel" }),
|
|
926
|
+
/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
|
|
927
|
+
"Profile: ",
|
|
928
|
+
profileLabel
|
|
929
|
+
] })
|
|
535
930
|
] });
|
|
536
931
|
};
|
|
537
932
|
|
|
@@ -576,12 +971,8 @@ var Spinner2 = () => {
|
|
|
576
971
|
return /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: SPINNER_FRAMES2[frame] ?? "\u280B" });
|
|
577
972
|
};
|
|
578
973
|
function getViewerPath() {
|
|
579
|
-
const filename =
|
|
580
|
-
return
|
|
581
|
-
}
|
|
582
|
-
function getElectronMainPath() {
|
|
583
|
-
const filename = fileURLToPath(import.meta.url);
|
|
584
|
-
return join6(dirname2(filename), "electron", "main.js");
|
|
974
|
+
const filename = fileURLToPath2(import.meta.url);
|
|
975
|
+
return join7(dirname3(filename), "viewer");
|
|
585
976
|
}
|
|
586
977
|
async function fileExists(filePath) {
|
|
587
978
|
try {
|
|
@@ -591,7 +982,7 @@ async function fileExists(filePath) {
|
|
|
591
982
|
return false;
|
|
592
983
|
}
|
|
593
984
|
}
|
|
594
|
-
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef) {
|
|
985
|
+
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast) {
|
|
595
986
|
const proxyCache = createProxyCache();
|
|
596
987
|
return (req, res) => {
|
|
597
988
|
void (async () => {
|
|
@@ -603,10 +994,38 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
603
994
|
res.end(credentialsRef.current !== null ? JSON.stringify(credentialsRef.current) : "{}");
|
|
604
995
|
return;
|
|
605
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
|
+
}
|
|
606
1025
|
if (url === "/api/bundle") {
|
|
607
|
-
const bundlePath =
|
|
1026
|
+
const bundlePath = join7(process.cwd(), ".kizenapp", "bundle.json");
|
|
608
1027
|
try {
|
|
609
|
-
const content = await
|
|
1028
|
+
const content = await readFile5(bundlePath, "utf-8");
|
|
610
1029
|
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
611
1030
|
res.end(content);
|
|
612
1031
|
} catch {
|
|
@@ -679,17 +1098,27 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
679
1098
|
return;
|
|
680
1099
|
}
|
|
681
1100
|
const rawPath = url === "/" ? "/index.html" : url;
|
|
682
|
-
const filePath =
|
|
683
|
-
const resolvedPath = await fileExists(filePath) ? filePath :
|
|
1101
|
+
const filePath = join7(viewerPath, rawPath);
|
|
1102
|
+
const resolvedPath = await fileExists(filePath) ? filePath : join7(viewerPath, "index.html");
|
|
684
1103
|
const ext = extname(resolvedPath);
|
|
685
1104
|
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
686
1105
|
res.writeHead(200, { "Content-Type": mimeType });
|
|
687
1106
|
createReadStream(resolvedPath).pipe(res);
|
|
688
1107
|
} catch (err) {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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
|
+
}
|
|
693
1122
|
if (!res.headersSent) {
|
|
694
1123
|
res.writeHead(502);
|
|
695
1124
|
res.end("Bad Gateway");
|
|
@@ -702,10 +1131,16 @@ var DevUI = ({
|
|
|
702
1131
|
port,
|
|
703
1132
|
pluginDir,
|
|
704
1133
|
outputDir,
|
|
705
|
-
credentials: initialCredentials
|
|
1134
|
+
credentials: initialCredentials,
|
|
1135
|
+
credentialMode: initialCredentialMode,
|
|
1136
|
+
activeCredentialProfile: initialActiveProfile
|
|
706
1137
|
}) => {
|
|
707
1138
|
const credentialsRef = useRef(initialCredentials);
|
|
1139
|
+
const activeProfileRef = useRef(initialActiveProfile);
|
|
708
1140
|
const [credMode, setCredMode] = useState3("main");
|
|
1141
|
+
const [credentialMode, setCredentialMode] = useState3(
|
|
1142
|
+
initialCredentialMode
|
|
1143
|
+
);
|
|
709
1144
|
const [status, setStatus] = useState3("starting");
|
|
710
1145
|
const [errorMessage, setErrorMessage] = useState3(null);
|
|
711
1146
|
const [serverLogHistory, setServerLogHistory] = useState3([]);
|
|
@@ -716,10 +1151,40 @@ var DevUI = ({
|
|
|
716
1151
|
const [lastBuilt, setLastBuilt] = useState3(null);
|
|
717
1152
|
const [wsClientCount, setWsClientCount] = useState3(0);
|
|
718
1153
|
const buildingRef = useRef(false);
|
|
719
|
-
const
|
|
1154
|
+
const viewerLaunchedRef = useRef(false);
|
|
1155
|
+
const chromeHandleRef = useRef(null);
|
|
720
1156
|
const debounceTimerRef = useRef(null);
|
|
721
1157
|
const wsClientsRef = useRef(/* @__PURE__ */ new Set());
|
|
722
1158
|
const pendingMessagesRef = useRef([]);
|
|
1159
|
+
const broadcast = useCallback2((msg) => {
|
|
1160
|
+
const json = JSON.stringify(msg);
|
|
1161
|
+
if (wsClientsRef.current.size === 0) {
|
|
1162
|
+
pendingMessagesRef.current = [...pendingMessagesRef.current, json].slice(-LOG_LIMIT);
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
for (const client of wsClientsRef.current) {
|
|
1166
|
+
if (client.readyState === 1) {
|
|
1167
|
+
client.send(json);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}, []);
|
|
1171
|
+
const createServerLog = useCallback2((message) => {
|
|
1172
|
+
setServerLogHistory(
|
|
1173
|
+
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
1174
|
+
);
|
|
1175
|
+
}, []);
|
|
1176
|
+
const launchChromeViewerCb = useCallback2(() => {
|
|
1177
|
+
chromeHandleRef.current?.kill();
|
|
1178
|
+
chromeHandleRef.current = null;
|
|
1179
|
+
void launchChromeViewer({
|
|
1180
|
+
port,
|
|
1181
|
+
userDataDir: join7(outputDir, ".chrome"),
|
|
1182
|
+
broadcast
|
|
1183
|
+
}).then((handle) => {
|
|
1184
|
+
chromeHandleRef.current = handle;
|
|
1185
|
+
process.on("exit", () => handle.kill());
|
|
1186
|
+
});
|
|
1187
|
+
}, [port, outputDir, broadcast]);
|
|
723
1188
|
useInput2(
|
|
724
1189
|
(input, key) => {
|
|
725
1190
|
if (input === "q" || key.ctrl && input === "c") {
|
|
@@ -728,55 +1193,30 @@ var DevUI = ({
|
|
|
728
1193
|
if (input === "c") {
|
|
729
1194
|
setCredMode("editing");
|
|
730
1195
|
}
|
|
731
|
-
if (input === "
|
|
732
|
-
|
|
1196
|
+
if (input === "v") {
|
|
1197
|
+
launchChromeViewerCb();
|
|
733
1198
|
}
|
|
734
1199
|
},
|
|
735
1200
|
{ isActive: credMode === "main" }
|
|
736
1201
|
);
|
|
737
1202
|
useEffect3(() => {
|
|
738
|
-
if (status !== "running" ||
|
|
1203
|
+
if (status !== "running" || viewerLaunchedRef.current) {
|
|
739
1204
|
return;
|
|
740
1205
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
const electronMain = getElectronMainPath();
|
|
745
|
-
const userDataDir = join6(outputDir, ".electron");
|
|
746
|
-
const proc = spawn(
|
|
747
|
-
electronBin,
|
|
748
|
-
[electronMain, `--port=${String(port)}`, `--user-data-dir=${userDataDir}`],
|
|
749
|
-
{
|
|
750
|
-
stdio: "ignore"
|
|
751
|
-
}
|
|
752
|
-
);
|
|
753
|
-
proc.unref();
|
|
754
|
-
process.on("exit", () => {
|
|
755
|
-
proc.kill();
|
|
756
|
-
});
|
|
757
|
-
}, [status, port, outputDir]);
|
|
758
|
-
const createServerLog = useCallback2((message) => {
|
|
759
|
-
setServerLogHistory(
|
|
760
|
-
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
761
|
-
);
|
|
762
|
-
}, []);
|
|
763
|
-
const broadcast = useCallback2((msg) => {
|
|
764
|
-
const json = JSON.stringify(msg);
|
|
765
|
-
if (wsClientsRef.current.size === 0) {
|
|
766
|
-
pendingMessagesRef.current = [...pendingMessagesRef.current, json].slice(-LOG_LIMIT);
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
for (const client of wsClientsRef.current) {
|
|
770
|
-
if (client.readyState === 1) {
|
|
771
|
-
client.send(json);
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
}, []);
|
|
1206
|
+
viewerLaunchedRef.current = true;
|
|
1207
|
+
launchChromeViewerCb();
|
|
1208
|
+
}, [status, launchChromeViewerCb]);
|
|
775
1209
|
const handleCredentialsDone = useCallback2(
|
|
776
1210
|
(result) => {
|
|
777
1211
|
credentialsRef.current = result.credentials;
|
|
1212
|
+
activeProfileRef.current = result.profileName;
|
|
778
1213
|
setCredMode("main");
|
|
779
|
-
|
|
1214
|
+
setCredentialMode(result.mode);
|
|
1215
|
+
const profile = result.profileName;
|
|
1216
|
+
void saveConfig(outputDir, {
|
|
1217
|
+
credentialMode: result.mode,
|
|
1218
|
+
...profile !== void 0 && { activeCredentialProfile: profile }
|
|
1219
|
+
});
|
|
780
1220
|
broadcast({ type: "credentials-updated", credentials: result.credentials });
|
|
781
1221
|
},
|
|
782
1222
|
[outputDir, broadcast]
|
|
@@ -852,7 +1292,7 @@ var DevUI = ({
|
|
|
852
1292
|
}, [pluginDir, triggerBuild, createBuildLog]);
|
|
853
1293
|
useEffect3(() => {
|
|
854
1294
|
const viewerPath = getViewerPath();
|
|
855
|
-
void fileExists(
|
|
1295
|
+
void fileExists(join7(viewerPath, "index.html")).then((viewerBuilt) => {
|
|
856
1296
|
if (!viewerBuilt) {
|
|
857
1297
|
setErrorMessage("Viewer not built. Run 'pnpm build:viewer' first.");
|
|
858
1298
|
setStatus("error");
|
|
@@ -862,7 +1302,10 @@ var DevUI = ({
|
|
|
862
1302
|
viewerPath,
|
|
863
1303
|
createServerLog,
|
|
864
1304
|
createProxyLog,
|
|
865
|
-
credentialsRef
|
|
1305
|
+
credentialsRef,
|
|
1306
|
+
activeProfileRef,
|
|
1307
|
+
outputDir,
|
|
1308
|
+
broadcast
|
|
866
1309
|
);
|
|
867
1310
|
const server = createServer(handler);
|
|
868
1311
|
const wss = new WebSocketServer({ server });
|
|
@@ -894,11 +1337,13 @@ var DevUI = ({
|
|
|
894
1337
|
server.close();
|
|
895
1338
|
};
|
|
896
1339
|
});
|
|
897
|
-
}, [port, createServerLog, createProxyLog]);
|
|
1340
|
+
}, [port, createServerLog, createProxyLog, broadcast, outputDir]);
|
|
898
1341
|
if (credMode === "editing") {
|
|
899
1342
|
return /* @__PURE__ */ jsx4(
|
|
900
1343
|
CredentialSetupUI,
|
|
901
1344
|
{
|
|
1345
|
+
...credentialMode !== void 0 && { initialMode: credentialMode },
|
|
1346
|
+
showProfileManager: credentialMode === "global",
|
|
902
1347
|
onComplete: handleCredentialsDone,
|
|
903
1348
|
onCancel: () => {
|
|
904
1349
|
setCredMode("main");
|
|
@@ -1000,8 +1445,11 @@ var DevUI = ({
|
|
|
1000
1445
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "] quit [" }),
|
|
1001
1446
|
/* @__PURE__ */ jsx4(Text4, { children: "c" }),
|
|
1002
1447
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "] credentials [" }),
|
|
1003
|
-
/* @__PURE__ */ jsx4(Text4, { children: "
|
|
1004
|
-
/* @__PURE__ */
|
|
1448
|
+
/* @__PURE__ */ jsx4(Text4, { children: "v" }),
|
|
1449
|
+
/* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
|
|
1450
|
+
"] ",
|
|
1451
|
+
wsClientCount === 0 ? "open viewer" : "relaunch viewer"
|
|
1452
|
+
] })
|
|
1005
1453
|
] })
|
|
1006
1454
|
] });
|
|
1007
1455
|
};
|
|
@@ -1032,6 +1480,7 @@ function devCommand(program2) {
|
|
|
1032
1480
|
ensureGitignore(pluginDir);
|
|
1033
1481
|
let credentials = null;
|
|
1034
1482
|
let credentialMode;
|
|
1483
|
+
let activeCredentialProfile;
|
|
1035
1484
|
if (options.credentials) {
|
|
1036
1485
|
credentials = await loadCredentialsFromFile(options.credentials);
|
|
1037
1486
|
} else {
|
|
@@ -1040,16 +1489,31 @@ function devCommand(program2) {
|
|
|
1040
1489
|
credentialMode = "local";
|
|
1041
1490
|
} else if (config.credentialMode === "global") {
|
|
1042
1491
|
credentialMode = "global";
|
|
1043
|
-
|
|
1492
|
+
activeCredentialProfile = config.activeCredentialProfile;
|
|
1493
|
+
if (activeCredentialProfile) {
|
|
1494
|
+
credentials = await loadCredentialProfile(activeCredentialProfile);
|
|
1495
|
+
if (!credentials) {
|
|
1496
|
+
credentials = await loadGlobalCredentials();
|
|
1497
|
+
activeCredentialProfile = void 0;
|
|
1498
|
+
}
|
|
1499
|
+
} else {
|
|
1500
|
+
credentials = await loadGlobalCredentials();
|
|
1501
|
+
}
|
|
1044
1502
|
if (!credentials) {
|
|
1045
1503
|
const result = await runSetupUI("global");
|
|
1046
1504
|
credentials = result.credentials;
|
|
1505
|
+
activeCredentialProfile = result.profileName;
|
|
1047
1506
|
}
|
|
1048
1507
|
} else {
|
|
1049
1508
|
const result = await runSetupUI();
|
|
1050
1509
|
credentials = result.credentials;
|
|
1051
1510
|
credentialMode = result.mode;
|
|
1052
|
-
|
|
1511
|
+
activeCredentialProfile = result.profileName;
|
|
1512
|
+
const profile = result.profileName;
|
|
1513
|
+
await saveConfig(outputDir, {
|
|
1514
|
+
credentialMode: result.mode,
|
|
1515
|
+
...profile !== void 0 && { activeCredentialProfile: profile }
|
|
1516
|
+
});
|
|
1053
1517
|
}
|
|
1054
1518
|
}
|
|
1055
1519
|
const { waitUntilExit } = render2(
|
|
@@ -1058,7 +1522,8 @@ function devCommand(program2) {
|
|
|
1058
1522
|
pluginDir,
|
|
1059
1523
|
outputDir,
|
|
1060
1524
|
credentials,
|
|
1061
|
-
...credentialMode !== void 0 && { credentialMode }
|
|
1525
|
+
...credentialMode !== void 0 && { credentialMode },
|
|
1526
|
+
...activeCredentialProfile !== void 0 && { activeCredentialProfile }
|
|
1062
1527
|
}),
|
|
1063
1528
|
{ exitOnCtrlC: false }
|
|
1064
1529
|
);
|