@kizenapps/cli 0.6.0 → 0.8.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/icon.png +0 -0
- package/dist/electron/main.js +42 -5
- package/dist/electron/main.js.map +1 -1
- package/dist/index.js +372 -61
- package/dist/index.js.map +1 -1
- package/dist/viewer/assets/index-B09qenTV.js +17 -0
- package/dist/viewer/assets/index-CVd4BLit.js +17 -0
- package/dist/viewer/assets/index-C_gRcfsL.js +17 -0
- package/dist/viewer/assets/index-CcvbGL5I.js +17 -0
- package/dist/viewer/assets/index-Ci5up9QD.js +17 -0
- package/dist/viewer/assets/index-DOiSISo1.css +2 -0
- package/dist/viewer/assets/index-DSJAwx9Y.js +17 -0
- package/dist/viewer/assets/index-DUgUEouL.css +2 -0
- package/dist/viewer/assets/index-WnCF0zx3.js +17 -0
- package/dist/viewer/assets/index-_K33TupM.js +17 -0
- package/dist/viewer/assets/index-dPV4go8k.js +17 -0
- package/dist/viewer/assets/index-xFuxlPJA.js +17 -0
- package/dist/viewer/icon.png +0 -0
- package/dist/viewer/index.html +2 -2
- package/package.json +1 -1
- package/dist/viewer/1024.png +0 -0
- package/dist/viewer/assets/index-B0iU58_K.css +0 -2
- package/dist/viewer/assets/index-BLljooBS.js +0 -17
- package/dist/viewer/favicon.png +0 -0
- package/dist/viewer/favicon.svg +0 -4
package/dist/index.js
CHANGED
|
@@ -238,33 +238,45 @@ import { dirname as dirname2, extname, join as join6 } from "path";
|
|
|
238
238
|
import { fileURLToPath } from "url";
|
|
239
239
|
import { WebSocketServer } from "ws";
|
|
240
240
|
|
|
241
|
-
// src/lib/
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
241
|
+
// src/lib/proxyCache.ts
|
|
242
|
+
function createProxyCache() {
|
|
243
|
+
const cache = /* @__PURE__ */ new Map();
|
|
244
|
+
return {
|
|
245
|
+
get(key, fetcher) {
|
|
246
|
+
const existing = cache.get(key);
|
|
247
|
+
if (existing !== void 0) {
|
|
248
|
+
return existing.then((response) => ({ response, fromCache: true }));
|
|
249
|
+
}
|
|
250
|
+
const pending = fetcher().then(async (response) => {
|
|
251
|
+
const headers = Object.fromEntries(response.headers);
|
|
252
|
+
delete headers["content-encoding"];
|
|
253
|
+
delete headers["content-length"];
|
|
254
|
+
return {
|
|
255
|
+
status: response.status,
|
|
256
|
+
headers,
|
|
257
|
+
body: Buffer.from(await response.arrayBuffer())
|
|
258
|
+
};
|
|
259
|
+
}).catch((error) => {
|
|
260
|
+
cache.delete(key);
|
|
261
|
+
throw error;
|
|
262
|
+
});
|
|
263
|
+
cache.set(key, pending);
|
|
264
|
+
return pending.then((response) => ({ response, fromCache: false }));
|
|
265
|
+
},
|
|
266
|
+
clear() {
|
|
267
|
+
cache.clear();
|
|
268
|
+
}
|
|
269
|
+
};
|
|
255
270
|
}
|
|
256
271
|
|
|
257
|
-
// src/ui/CredentialSetupUI.tsx
|
|
258
|
-
import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";
|
|
259
|
-
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
260
|
-
|
|
261
272
|
// src/lib/credentials.ts
|
|
262
|
-
import { mkdir as
|
|
273
|
+
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir2, writeFile as writeFile2 } from "fs/promises";
|
|
263
274
|
import { homedir } from "os";
|
|
264
|
-
import { dirname, join as
|
|
275
|
+
import { dirname, join as join4 } from "path";
|
|
265
276
|
var ENVIRONMENTS = ["go", "fmo", "staging", "integration", "test1"];
|
|
266
|
-
var GLOBAL_CREDENTIALS_DIR =
|
|
267
|
-
var GLOBAL_CREDENTIALS_PATH =
|
|
277
|
+
var GLOBAL_CREDENTIALS_DIR = join4(homedir(), ".kizenappbuilder");
|
|
278
|
+
var GLOBAL_CREDENTIALS_PATH = join4(GLOBAL_CREDENTIALS_DIR, "credentials.json");
|
|
279
|
+
var DEFAULT_PROFILE_NAME = "credentials";
|
|
268
280
|
function isValidEnvironment(value) {
|
|
269
281
|
return ENVIRONMENTS.includes(value);
|
|
270
282
|
}
|
|
@@ -282,7 +294,7 @@ function parseCredentials(raw) {
|
|
|
282
294
|
};
|
|
283
295
|
}
|
|
284
296
|
async function loadCredentialsFromFile(filePath) {
|
|
285
|
-
const content = await
|
|
297
|
+
const content = await readFile2(filePath, "utf-8");
|
|
286
298
|
return parseCredentials(JSON.parse(content));
|
|
287
299
|
}
|
|
288
300
|
async function loadGlobalCredentials() {
|
|
@@ -293,11 +305,63 @@ async function loadGlobalCredentials() {
|
|
|
293
305
|
}
|
|
294
306
|
}
|
|
295
307
|
async function saveGlobalCredentials(credentials) {
|
|
296
|
-
await
|
|
297
|
-
await
|
|
308
|
+
await mkdir2(dirname(GLOBAL_CREDENTIALS_PATH), { recursive: true });
|
|
309
|
+
await writeFile2(GLOBAL_CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), "utf-8");
|
|
310
|
+
}
|
|
311
|
+
function getProfilePath(name) {
|
|
312
|
+
return join4(GLOBAL_CREDENTIALS_DIR, `${name}.json`);
|
|
313
|
+
}
|
|
314
|
+
async function listCredentialProfiles() {
|
|
315
|
+
const profiles = [
|
|
316
|
+
{ name: DEFAULT_PROFILE_NAME, path: GLOBAL_CREDENTIALS_PATH, isDefault: true }
|
|
317
|
+
];
|
|
318
|
+
try {
|
|
319
|
+
const entries = await readdir2(GLOBAL_CREDENTIALS_DIR);
|
|
320
|
+
for (const entry of entries) {
|
|
321
|
+
if (!entry.endsWith(".json")) continue;
|
|
322
|
+
const name = entry.slice(0, -5);
|
|
323
|
+
if (name === DEFAULT_PROFILE_NAME) continue;
|
|
324
|
+
profiles.push({ name, path: join4(GLOBAL_CREDENTIALS_DIR, entry), isDefault: false });
|
|
325
|
+
}
|
|
326
|
+
} catch {
|
|
327
|
+
}
|
|
328
|
+
return profiles;
|
|
329
|
+
}
|
|
330
|
+
async function saveCredentialProfile(name, credentials) {
|
|
331
|
+
if (name === DEFAULT_PROFILE_NAME) {
|
|
332
|
+
await saveGlobalCredentials(credentials);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
await mkdir2(GLOBAL_CREDENTIALS_DIR, { recursive: true });
|
|
336
|
+
await writeFile2(getProfilePath(name), JSON.stringify(credentials, null, 2), "utf-8");
|
|
337
|
+
}
|
|
338
|
+
async function loadCredentialProfile(name) {
|
|
339
|
+
try {
|
|
340
|
+
return await loadCredentialsFromFile(getProfilePath(name));
|
|
341
|
+
} catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/lib/config.ts
|
|
347
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
348
|
+
import { join as join5 } from "path";
|
|
349
|
+
async function loadConfig(outputDir) {
|
|
350
|
+
try {
|
|
351
|
+
const content = await readFile3(join5(outputDir, "config.json"), "utf-8");
|
|
352
|
+
return JSON.parse(content);
|
|
353
|
+
} catch {
|
|
354
|
+
return {};
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
async function saveConfig(outputDir, config) {
|
|
358
|
+
await mkdir3(outputDir, { recursive: true });
|
|
359
|
+
await writeFile3(join5(outputDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
298
360
|
}
|
|
299
361
|
|
|
300
362
|
// src/ui/CredentialSetupUI.tsx
|
|
363
|
+
import { useCallback, useEffect as useEffect2, useState as useState2 } from "react";
|
|
364
|
+
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
301
365
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
302
366
|
var FIELDS = ["apiKey", "userId", "businessId"];
|
|
303
367
|
var FIELD_LABELS = {
|
|
@@ -308,32 +372,39 @@ var FIELD_LABELS = {
|
|
|
308
372
|
var Hint = ({ text }) => /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: text });
|
|
309
373
|
var CredentialSetupUI = ({
|
|
310
374
|
initialMode,
|
|
375
|
+
showProfileManager,
|
|
311
376
|
onComplete,
|
|
312
377
|
onCancel
|
|
313
378
|
}) => {
|
|
314
379
|
const [phase, setPhase] = useState2(
|
|
315
|
-
initialMode === "global" ? { type: "loading" } : { type: "mode-select", cursor: 0 }
|
|
380
|
+
initialMode === "global" && !showProfileManager ? { type: "loading" } : initialMode === "global" && showProfileManager ? { type: "profile-loading" } : { type: "mode-select", cursor: 0 }
|
|
316
381
|
);
|
|
317
382
|
const [inputBuffer, setInputBuffer] = useState2("");
|
|
318
383
|
const [error, setError] = useState2(null);
|
|
384
|
+
const [activeProfileName, setActiveProfileName] = useState2(void 0);
|
|
319
385
|
const handleModeChosen = useCallback(
|
|
320
386
|
async (mode) => {
|
|
321
387
|
if (mode === "local") {
|
|
322
388
|
onComplete({ mode: "local", credentials: null });
|
|
323
389
|
return;
|
|
324
390
|
}
|
|
325
|
-
setPhase({ type: "loading" });
|
|
326
|
-
const existing = await loadGlobalCredentials();
|
|
327
|
-
const envCursor2 = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;
|
|
328
|
-
setPhase({
|
|
329
|
-
type: "creds-entry",
|
|
330
|
-
field: 0,
|
|
331
|
-
values: existing ?? {},
|
|
332
|
-
envCursor: envCursor2
|
|
333
|
-
});
|
|
391
|
+
setPhase({ type: "profile-loading" });
|
|
334
392
|
},
|
|
335
393
|
[onComplete]
|
|
336
394
|
);
|
|
395
|
+
const handleProfileChosen = useCallback(async (profile) => {
|
|
396
|
+
if (profile === null) {
|
|
397
|
+
setPhase({ type: "profile-loading" });
|
|
398
|
+
const profiles = await listCredentialProfiles();
|
|
399
|
+
setPhase({ type: "name-entry", nameBuffer: "", existingProfiles: profiles });
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
setActiveProfileName(profile.isDefault ? void 0 : profile.name);
|
|
403
|
+
setPhase({ type: "loading" });
|
|
404
|
+
const existing = profile.isDefault ? await loadGlobalCredentials() : await loadCredentialProfile(profile.name);
|
|
405
|
+
const envCursor2 = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;
|
|
406
|
+
setPhase({ type: "creds-entry", field: 0, values: existing ?? {}, envCursor: envCursor2 });
|
|
407
|
+
}, []);
|
|
337
408
|
const handleSave = useCallback(
|
|
338
409
|
async (values2, envCursor2) => {
|
|
339
410
|
const environment = ENVIRONMENTS[envCursor2] ?? "go";
|
|
@@ -345,20 +416,32 @@ var CredentialSetupUI = ({
|
|
|
345
416
|
};
|
|
346
417
|
setPhase({ type: "saving" });
|
|
347
418
|
try {
|
|
348
|
-
|
|
349
|
-
|
|
419
|
+
const profileName = activeProfileName ?? DEFAULT_PROFILE_NAME;
|
|
420
|
+
await saveCredentialProfile(profileName, credentials);
|
|
421
|
+
onComplete({
|
|
422
|
+
mode: "global",
|
|
423
|
+
credentials,
|
|
424
|
+
...activeProfileName !== void 0 && { profileName: activeProfileName }
|
|
425
|
+
});
|
|
350
426
|
} catch (err) {
|
|
351
427
|
setError(err instanceof Error ? err.message : String(err));
|
|
352
428
|
setPhase({ type: "creds-entry", field: 0, values: values2, envCursor: envCursor2 });
|
|
353
429
|
}
|
|
354
430
|
},
|
|
355
|
-
[onComplete]
|
|
431
|
+
[onComplete, activeProfileName]
|
|
356
432
|
);
|
|
357
433
|
useInput((input, key) => {
|
|
358
434
|
if (key.ctrl && input === "c") {
|
|
359
435
|
process.exit(0);
|
|
360
436
|
}
|
|
361
437
|
if (key.escape) {
|
|
438
|
+
if (phase.type === "creds-entry" || phase.type === "name-entry") {
|
|
439
|
+
if (initialMode === "global" && showProfileManager) {
|
|
440
|
+
setPhase({ type: "profile-loading" });
|
|
441
|
+
void loadProfileList();
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
362
445
|
onCancel?.();
|
|
363
446
|
return;
|
|
364
447
|
}
|
|
@@ -373,6 +456,49 @@ var CredentialSetupUI = ({
|
|
|
373
456
|
}
|
|
374
457
|
return;
|
|
375
458
|
}
|
|
459
|
+
if (phase.type === "profile-select") {
|
|
460
|
+
const { profiles, cursor } = phase;
|
|
461
|
+
const addNewIdx = profiles.length;
|
|
462
|
+
const totalItems = profiles.length + 1;
|
|
463
|
+
if (key.upArrow) {
|
|
464
|
+
setPhase({ ...phase, cursor: (cursor - 1 + totalItems) % totalItems });
|
|
465
|
+
} else if (key.downArrow) {
|
|
466
|
+
setPhase({ ...phase, cursor: (cursor + 1) % totalItems });
|
|
467
|
+
} else if (key.return) {
|
|
468
|
+
if (cursor === addNewIdx) {
|
|
469
|
+
setPhase({ type: "name-entry", nameBuffer: "", existingProfiles: profiles });
|
|
470
|
+
} else {
|
|
471
|
+
void handleProfileChosen(profiles[cursor] ?? profiles[0]);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
if (phase.type === "name-entry") {
|
|
477
|
+
const { nameBuffer, nameError: _nameError, existingProfiles } = phase;
|
|
478
|
+
if (key.backspace || key.delete) {
|
|
479
|
+
setPhase({ type: "name-entry", nameBuffer: nameBuffer.slice(0, -1), existingProfiles });
|
|
480
|
+
} else if (key.return) {
|
|
481
|
+
const trimmed = nameBuffer.trim();
|
|
482
|
+
if (!trimmed) {
|
|
483
|
+
setPhase({ ...phase, nameError: "Name cannot be empty" });
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (trimmed === DEFAULT_PROFILE_NAME) {
|
|
487
|
+
setPhase({ ...phase, nameError: `"${DEFAULT_PROFILE_NAME}" is reserved` });
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (existingProfiles.some((p) => p.name === trimmed)) {
|
|
491
|
+
setPhase({ ...phase, nameError: `Profile "${trimmed}" already exists` });
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
setActiveProfileName(trimmed);
|
|
495
|
+
setPhase({ type: "creds-entry", field: 0, values: {}, envCursor: 0 });
|
|
496
|
+
setInputBuffer("");
|
|
497
|
+
} else if (input && !key.ctrl && !key.meta) {
|
|
498
|
+
setPhase({ type: "name-entry", nameBuffer: nameBuffer + input, existingProfiles });
|
|
499
|
+
}
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
376
502
|
if (phase.type === "creds-entry") {
|
|
377
503
|
const { field, values: values2, envCursor: envCursor2 } = phase;
|
|
378
504
|
const isEnvField2 = field === FIELDS.length;
|
|
@@ -417,9 +543,22 @@ var CredentialSetupUI = ({
|
|
|
417
543
|
}
|
|
418
544
|
}
|
|
419
545
|
});
|
|
546
|
+
const loadProfileList = useCallback(async () => {
|
|
547
|
+
const profiles = await listCredentialProfiles();
|
|
548
|
+
setPhase({ type: "profile-select", profiles, cursor: 0 });
|
|
549
|
+
}, []);
|
|
550
|
+
useEffect2(() => {
|
|
551
|
+
if (phase.type === "profile-loading") {
|
|
552
|
+
void loadProfileList();
|
|
553
|
+
}
|
|
554
|
+
}, [phase.type, loadProfileList]);
|
|
420
555
|
useEffect2(() => {
|
|
421
|
-
if (initialMode === "global") {
|
|
422
|
-
void
|
|
556
|
+
if (initialMode === "global" && !showProfileManager) {
|
|
557
|
+
void (async () => {
|
|
558
|
+
const existing = await loadGlobalCredentials();
|
|
559
|
+
const envCursor2 = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;
|
|
560
|
+
setPhase({ type: "creds-entry", field: 0, values: existing ?? {}, envCursor: envCursor2 });
|
|
561
|
+
})();
|
|
423
562
|
}
|
|
424
563
|
}, []);
|
|
425
564
|
useEffect2(() => {
|
|
@@ -427,8 +566,9 @@ var CredentialSetupUI = ({
|
|
|
427
566
|
setInputBuffer(phase.values.apiKey ?? "");
|
|
428
567
|
}
|
|
429
568
|
}, [phase.type]);
|
|
430
|
-
if (phase.type === "loading" || phase.type === "saving") {
|
|
431
|
-
|
|
569
|
+
if (phase.type === "loading" || phase.type === "saving" || phase.type === "profile-loading") {
|
|
570
|
+
const label = phase.type === "saving" ? "Saving credentials\u2026" : phase.type === "profile-loading" ? "Loading profiles\u2026" : "Loading credentials\u2026";
|
|
571
|
+
return /* @__PURE__ */ jsx3(Box3, { paddingY: 1, paddingX: 2, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: label }) });
|
|
432
572
|
}
|
|
433
573
|
if (phase.type === "done") {
|
|
434
574
|
return null;
|
|
@@ -458,8 +598,58 @@ var CredentialSetupUI = ({
|
|
|
458
598
|
/* @__PURE__ */ jsx3(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit" })
|
|
459
599
|
] });
|
|
460
600
|
}
|
|
601
|
+
if (phase.type === "profile-select") {
|
|
602
|
+
const { profiles, cursor } = phase;
|
|
603
|
+
const addNewIdx = profiles.length;
|
|
604
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
605
|
+
/* @__PURE__ */ jsx3(Logo, {}),
|
|
606
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
607
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
608
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
609
|
+
] }),
|
|
610
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
611
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Credential profiles" }),
|
|
612
|
+
profiles.map((profile, i) => {
|
|
613
|
+
const selected = cursor === i;
|
|
614
|
+
return /* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
615
|
+
/* @__PURE__ */ jsx3(Text3, { ...selected && { color: "cyan" }, children: selected ? "\u276F" : " " }),
|
|
616
|
+
/* @__PURE__ */ jsx3(Text3, { bold: selected, ...selected && { color: "cyan" }, children: profile.isDefault ? "Default" : profile.name }),
|
|
617
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: profile.path })
|
|
618
|
+
] }, profile.name);
|
|
619
|
+
}),
|
|
620
|
+
/* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
621
|
+
/* @__PURE__ */ jsx3(Text3, { ...cursor === addNewIdx && { color: "cyan" }, children: cursor === addNewIdx ? "\u276F" : " " }),
|
|
622
|
+
/* @__PURE__ */ jsx3(Text3, { bold: cursor === addNewIdx, ...cursor === addNewIdx && { color: "cyan" }, children: "+ Add new profile" })
|
|
623
|
+
] })
|
|
624
|
+
] }),
|
|
625
|
+
/* @__PURE__ */ jsx3(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel" })
|
|
626
|
+
] });
|
|
627
|
+
}
|
|
628
|
+
if (phase.type === "name-entry") {
|
|
629
|
+
const { nameBuffer, nameError } = phase;
|
|
630
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
631
|
+
/* @__PURE__ */ jsx3(Logo, {}),
|
|
632
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
633
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
634
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
635
|
+
] }),
|
|
636
|
+
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", gap: 0, children: /* @__PURE__ */ jsx3(Text3, { bold: true, children: "New credential profile" }) }),
|
|
637
|
+
nameError && /* @__PURE__ */ jsxs2(Text3, { color: "red", children: [
|
|
638
|
+
"Error: ",
|
|
639
|
+
nameError
|
|
640
|
+
] }),
|
|
641
|
+
/* @__PURE__ */ jsxs2(Box3, { gap: 2, children: [
|
|
642
|
+
/* @__PURE__ */ jsx3(Box3, { width: 12, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: "Profile name" }) }),
|
|
643
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: ">" }),
|
|
644
|
+
/* @__PURE__ */ jsx3(Text3, { children: nameBuffer }),
|
|
645
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: "\u2588" })
|
|
646
|
+
] }),
|
|
647
|
+
/* @__PURE__ */ jsx3(Hint, { text: "Type a name \xB7 Enter to confirm \xB7 Esc to go back" })
|
|
648
|
+
] });
|
|
649
|
+
}
|
|
461
650
|
const { field: activeField, values, envCursor } = phase;
|
|
462
651
|
const isEnvField = activeField === FIELDS.length;
|
|
652
|
+
const profileLabel = activeProfileName !== void 0 ? activeProfileName : DEFAULT_PROFILE_NAME;
|
|
463
653
|
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
464
654
|
/* @__PURE__ */ jsx3(Logo, {}),
|
|
465
655
|
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
@@ -467,10 +657,10 @@ var CredentialSetupUI = ({
|
|
|
467
657
|
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
468
658
|
] }),
|
|
469
659
|
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
470
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Global credentials" }),
|
|
660
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: activeProfileName !== void 0 ? `Profile: ${activeProfileName}` : "Global credentials" }),
|
|
471
661
|
/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
|
|
472
662
|
"Saved to: ",
|
|
473
|
-
GLOBAL_CREDENTIALS_PATH
|
|
663
|
+
activeProfileName !== void 0 ? `~/.kizenappbuilder/${activeProfileName}.json` : GLOBAL_CREDENTIALS_PATH
|
|
474
664
|
] })
|
|
475
665
|
] }),
|
|
476
666
|
error && /* @__PURE__ */ jsxs2(Text3, { color: "red", children: [
|
|
@@ -500,12 +690,23 @@ var CredentialSetupUI = ({
|
|
|
500
690
|
}) })
|
|
501
691
|
] })
|
|
502
692
|
] }),
|
|
503
|
-
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" })
|
|
693
|
+
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" }),
|
|
694
|
+
/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
|
|
695
|
+
"Profile: ",
|
|
696
|
+
profileLabel
|
|
697
|
+
] })
|
|
504
698
|
] });
|
|
505
699
|
};
|
|
506
700
|
|
|
507
701
|
// src/ui/DevUI.tsx
|
|
508
702
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
703
|
+
function proxyLogEntryToString(entry) {
|
|
704
|
+
if (entry.kind === "info") {
|
|
705
|
+
return entry.message;
|
|
706
|
+
}
|
|
707
|
+
const cache = entry.fromCache ? " [cache]" : "";
|
|
708
|
+
return `${entry.method} ${entry.url} \u2192 ${String(entry.status)}${cache}`;
|
|
709
|
+
}
|
|
509
710
|
var SKIP_WATCH_PREFIXES = [".kizenapp", ".git"];
|
|
510
711
|
var LOG_LIMIT = 50;
|
|
511
712
|
var LOG_DISPLAY = 8;
|
|
@@ -553,7 +754,8 @@ async function fileExists(filePath) {
|
|
|
553
754
|
return false;
|
|
554
755
|
}
|
|
555
756
|
}
|
|
556
|
-
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef) {
|
|
757
|
+
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast) {
|
|
758
|
+
const proxyCache = createProxyCache();
|
|
557
759
|
return (req, res) => {
|
|
558
760
|
void (async () => {
|
|
559
761
|
const url = req.url ?? "/";
|
|
@@ -564,6 +766,34 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
564
766
|
res.end(credentialsRef.current !== null ? JSON.stringify(credentialsRef.current) : "{}");
|
|
565
767
|
return;
|
|
566
768
|
}
|
|
769
|
+
if (url === "/api/credential-profiles" && req.method === "GET") {
|
|
770
|
+
const profiles = await listCredentialProfiles();
|
|
771
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
772
|
+
res.end(JSON.stringify({ profiles, active: activeProfileRef.current }));
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
if (url === "/api/credentials/switch" && req.method === "POST") {
|
|
776
|
+
const chunks = [];
|
|
777
|
+
for await (const chunk of req) {
|
|
778
|
+
chunks.push(chunk);
|
|
779
|
+
}
|
|
780
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}");
|
|
781
|
+
const profileName = body.profile;
|
|
782
|
+
const creds = profileName === void 0 || profileName === "" ? await loadGlobalCredentials() : await loadCredentialProfile(profileName);
|
|
783
|
+
if (creds !== null) {
|
|
784
|
+
credentialsRef.current = creds;
|
|
785
|
+
activeProfileRef.current = profileName || void 0;
|
|
786
|
+
const active = activeProfileRef.current;
|
|
787
|
+
await saveConfig(outputDir, {
|
|
788
|
+
credentialMode: "global",
|
|
789
|
+
...active !== void 0 && { activeCredentialProfile: active }
|
|
790
|
+
});
|
|
791
|
+
broadcast({ type: "credentials-updated", credentials: creds });
|
|
792
|
+
}
|
|
793
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
794
|
+
res.end(JSON.stringify({ ok: creds !== null }));
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
567
797
|
if (url === "/api/bundle") {
|
|
568
798
|
const bundlePath = join6(process.cwd(), ".kizenapp", "bundle.json");
|
|
569
799
|
try {
|
|
@@ -576,6 +806,13 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
576
806
|
}
|
|
577
807
|
return;
|
|
578
808
|
}
|
|
809
|
+
if (url === "/api/proxy-cache/clear") {
|
|
810
|
+
proxyCache.clear();
|
|
811
|
+
createProxyLog({ kind: "info", message: "Proxy cache cleared" });
|
|
812
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
813
|
+
res.end('{"ok":true}');
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
579
816
|
if (url.startsWith("/api/proxy")) {
|
|
580
817
|
const proxyTarget = req.headers["x-proxy-target"];
|
|
581
818
|
if (typeof proxyTarget !== "string") {
|
|
@@ -585,19 +822,46 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
585
822
|
}
|
|
586
823
|
const upstreamPath = url.slice("/api/proxy".length) || "/";
|
|
587
824
|
const upstreamUrl = `${proxyTarget}${upstreamPath}`;
|
|
825
|
+
const method = req.method ?? "GET";
|
|
588
826
|
const chunks = [];
|
|
589
827
|
for await (const chunk of req) {
|
|
590
828
|
chunks.push(chunk);
|
|
591
829
|
}
|
|
592
|
-
const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
|
|
593
830
|
const { host, "x-proxy-target": _drop, ...forwardHeaders } = req.headers;
|
|
831
|
+
if (method === "GET") {
|
|
832
|
+
const cacheKey = `GET::${upstreamUrl}`;
|
|
833
|
+
const { response: cached, fromCache } = await proxyCache.get(
|
|
834
|
+
cacheKey,
|
|
835
|
+
() => fetch(upstreamUrl, {
|
|
836
|
+
method: "GET",
|
|
837
|
+
headers: forwardHeaders
|
|
838
|
+
})
|
|
839
|
+
);
|
|
840
|
+
createProxyLog({
|
|
841
|
+
kind: "request",
|
|
842
|
+
method: "GET",
|
|
843
|
+
status: cached.status,
|
|
844
|
+
fromCache,
|
|
845
|
+
url: upstreamPath
|
|
846
|
+
});
|
|
847
|
+
res.writeHead(cached.status, cached.headers);
|
|
848
|
+
res.end(cached.body);
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
|
|
594
852
|
const resolvedBody = body && body.length > 0 ? body : void 0;
|
|
595
853
|
const upstream = await fetch(upstreamUrl, {
|
|
596
|
-
|
|
854
|
+
method,
|
|
597
855
|
headers: forwardHeaders,
|
|
598
856
|
...resolvedBody !== void 0 && { body: resolvedBody }
|
|
599
857
|
});
|
|
600
|
-
createProxyLog(
|
|
858
|
+
createProxyLog({
|
|
859
|
+
kind: "request",
|
|
860
|
+
method,
|
|
861
|
+
status: upstream.status,
|
|
862
|
+
fromCache: false,
|
|
863
|
+
url: upstreamPath
|
|
864
|
+
});
|
|
601
865
|
const responseHeaders = Object.fromEntries(upstream.headers);
|
|
602
866
|
delete responseHeaders["content-encoding"];
|
|
603
867
|
delete responseHeaders["content-length"];
|
|
@@ -613,9 +877,20 @@ function createRequestHandler(viewerPath, createServerLog, createProxyLog, crede
|
|
|
613
877
|
res.writeHead(200, { "Content-Type": mimeType });
|
|
614
878
|
createReadStream(resolvedPath).pipe(res);
|
|
615
879
|
} catch (err) {
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
880
|
+
if (url.startsWith("/api/proxy")) {
|
|
881
|
+
createProxyLog({
|
|
882
|
+
kind: "request",
|
|
883
|
+
method: req.method ?? "GET",
|
|
884
|
+
status: 502,
|
|
885
|
+
fromCache: false,
|
|
886
|
+
url: url.slice("/api/proxy".length) || "/"
|
|
887
|
+
});
|
|
888
|
+
} else {
|
|
889
|
+
createProxyLog({
|
|
890
|
+
kind: "info",
|
|
891
|
+
message: `Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`
|
|
892
|
+
});
|
|
893
|
+
}
|
|
619
894
|
if (!res.headersSent) {
|
|
620
895
|
res.writeHead(502);
|
|
621
896
|
res.end("Bad Gateway");
|
|
@@ -628,10 +903,16 @@ var DevUI = ({
|
|
|
628
903
|
port,
|
|
629
904
|
pluginDir,
|
|
630
905
|
outputDir,
|
|
631
|
-
credentials: initialCredentials
|
|
906
|
+
credentials: initialCredentials,
|
|
907
|
+
credentialMode: initialCredentialMode,
|
|
908
|
+
activeCredentialProfile: initialActiveProfile
|
|
632
909
|
}) => {
|
|
633
910
|
const credentialsRef = useRef(initialCredentials);
|
|
911
|
+
const activeProfileRef = useRef(initialActiveProfile);
|
|
634
912
|
const [credMode, setCredMode] = useState3("main");
|
|
913
|
+
const [credentialMode, setCredentialMode] = useState3(
|
|
914
|
+
initialCredentialMode
|
|
915
|
+
);
|
|
635
916
|
const [status, setStatus] = useState3("starting");
|
|
636
917
|
const [errorMessage, setErrorMessage] = useState3(null);
|
|
637
918
|
const [serverLogHistory, setServerLogHistory] = useState3([]);
|
|
@@ -701,18 +982,26 @@ var DevUI = ({
|
|
|
701
982
|
const handleCredentialsDone = useCallback2(
|
|
702
983
|
(result) => {
|
|
703
984
|
credentialsRef.current = result.credentials;
|
|
985
|
+
activeProfileRef.current = result.profileName;
|
|
704
986
|
setCredMode("main");
|
|
705
|
-
|
|
987
|
+
setCredentialMode(result.mode);
|
|
988
|
+
const profile = result.profileName;
|
|
989
|
+
void saveConfig(outputDir, {
|
|
990
|
+
credentialMode: result.mode,
|
|
991
|
+
...profile !== void 0 && { activeCredentialProfile: profile }
|
|
992
|
+
});
|
|
706
993
|
broadcast({ type: "credentials-updated", credentials: result.credentials });
|
|
707
994
|
},
|
|
708
995
|
[outputDir, broadcast]
|
|
709
996
|
);
|
|
710
997
|
const createProxyLog = useCallback2(
|
|
711
|
-
(
|
|
998
|
+
(entry) => {
|
|
712
999
|
setProxyLogHistory(
|
|
713
|
-
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${
|
|
1000
|
+
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${proxyLogEntryToString(entry)}`].slice(
|
|
1001
|
+
-LOG_LIMIT
|
|
1002
|
+
)
|
|
714
1003
|
);
|
|
715
|
-
broadcast({ type: "proxy-log",
|
|
1004
|
+
broadcast({ type: "proxy-log", entry });
|
|
716
1005
|
},
|
|
717
1006
|
[broadcast]
|
|
718
1007
|
);
|
|
@@ -786,7 +1075,10 @@ var DevUI = ({
|
|
|
786
1075
|
viewerPath,
|
|
787
1076
|
createServerLog,
|
|
788
1077
|
createProxyLog,
|
|
789
|
-
credentialsRef
|
|
1078
|
+
credentialsRef,
|
|
1079
|
+
activeProfileRef,
|
|
1080
|
+
outputDir,
|
|
1081
|
+
broadcast
|
|
790
1082
|
);
|
|
791
1083
|
const server = createServer(handler);
|
|
792
1084
|
const wss = new WebSocketServer({ server });
|
|
@@ -823,6 +1115,8 @@ var DevUI = ({
|
|
|
823
1115
|
return /* @__PURE__ */ jsx4(
|
|
824
1116
|
CredentialSetupUI,
|
|
825
1117
|
{
|
|
1118
|
+
...credentialMode !== void 0 && { initialMode: credentialMode },
|
|
1119
|
+
showProfileManager: credentialMode === "global",
|
|
826
1120
|
onComplete: handleCredentialsDone,
|
|
827
1121
|
onCancel: () => {
|
|
828
1122
|
setCredMode("main");
|
|
@@ -956,6 +1250,7 @@ function devCommand(program2) {
|
|
|
956
1250
|
ensureGitignore(pluginDir);
|
|
957
1251
|
let credentials = null;
|
|
958
1252
|
let credentialMode;
|
|
1253
|
+
let activeCredentialProfile;
|
|
959
1254
|
if (options.credentials) {
|
|
960
1255
|
credentials = await loadCredentialsFromFile(options.credentials);
|
|
961
1256
|
} else {
|
|
@@ -964,16 +1259,31 @@ function devCommand(program2) {
|
|
|
964
1259
|
credentialMode = "local";
|
|
965
1260
|
} else if (config.credentialMode === "global") {
|
|
966
1261
|
credentialMode = "global";
|
|
967
|
-
|
|
1262
|
+
activeCredentialProfile = config.activeCredentialProfile;
|
|
1263
|
+
if (activeCredentialProfile) {
|
|
1264
|
+
credentials = await loadCredentialProfile(activeCredentialProfile);
|
|
1265
|
+
if (!credentials) {
|
|
1266
|
+
credentials = await loadGlobalCredentials();
|
|
1267
|
+
activeCredentialProfile = void 0;
|
|
1268
|
+
}
|
|
1269
|
+
} else {
|
|
1270
|
+
credentials = await loadGlobalCredentials();
|
|
1271
|
+
}
|
|
968
1272
|
if (!credentials) {
|
|
969
1273
|
const result = await runSetupUI("global");
|
|
970
1274
|
credentials = result.credentials;
|
|
1275
|
+
activeCredentialProfile = result.profileName;
|
|
971
1276
|
}
|
|
972
1277
|
} else {
|
|
973
1278
|
const result = await runSetupUI();
|
|
974
1279
|
credentials = result.credentials;
|
|
975
1280
|
credentialMode = result.mode;
|
|
976
|
-
|
|
1281
|
+
activeCredentialProfile = result.profileName;
|
|
1282
|
+
const profile = result.profileName;
|
|
1283
|
+
await saveConfig(outputDir, {
|
|
1284
|
+
credentialMode: result.mode,
|
|
1285
|
+
...profile !== void 0 && { activeCredentialProfile: profile }
|
|
1286
|
+
});
|
|
977
1287
|
}
|
|
978
1288
|
}
|
|
979
1289
|
const { waitUntilExit } = render2(
|
|
@@ -982,7 +1292,8 @@ function devCommand(program2) {
|
|
|
982
1292
|
pluginDir,
|
|
983
1293
|
outputDir,
|
|
984
1294
|
credentials,
|
|
985
|
-
...credentialMode !== void 0 && { credentialMode }
|
|
1295
|
+
...credentialMode !== void 0 && { credentialMode },
|
|
1296
|
+
...activeCredentialProfile !== void 0 && { activeCredentialProfile }
|
|
986
1297
|
}),
|
|
987
1298
|
{ exitOnCtrlC: false }
|
|
988
1299
|
);
|