@kizenapps/cli 0.10.0 → 0.12.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/chunk-4Z6S6LWP.js +6134 -0
- package/dist/chunk-4Z6S6LWP.js.map +1 -0
- package/dist/chunk-HJPLDI45.js +6134 -0
- package/dist/chunk-HJPLDI45.js.map +1 -0
- package/dist/chunk-LSHHXCC6.js +3639 -0
- package/dist/chunk-LSHHXCC6.js.map +1 -0
- package/dist/chunk-SEGVTWSK.js +44 -0
- package/dist/chunk-SEGVTWSK.js.map +1 -0
- package/dist/chunk-ZWE3DS7E.js +39 -0
- package/dist/chunk-ZWE3DS7E.js.map +1 -0
- package/dist/devtools-LZRAH4XS.js +90 -0
- package/dist/devtools-LZRAH4XS.js.map +1 -0
- package/dist/dist-C3F6UOWF.js +8472 -0
- package/dist/dist-C3F6UOWF.js.map +1 -0
- package/dist/dist-NUJOSN7W.js +8472 -0
- package/dist/dist-NUJOSN7W.js.map +1 -0
- package/dist/dist-QHDMIBVE.js +135 -0
- package/dist/dist-QHDMIBVE.js.map +1 -0
- package/dist/dist-ZIZQOSY3.js +135 -0
- package/dist/dist-ZIZQOSY3.js.map +1 -0
- package/dist/gzip-size-K37OQCQ2.js +137 -0
- package/dist/gzip-size-K37OQCQ2.js.map +1 -0
- package/dist/gzip-size-QRGIYYEQ.js +137 -0
- package/dist/gzip-size-QRGIYYEQ.js.map +1 -0
- package/dist/index.js +1046 -582
- package/dist/index.js.map +1 -1
- package/dist/viewer/assets/AppDetailPage-BPvWscWJ.js +1 -0
- package/dist/viewer/assets/AppDetailPage-DIuYKCTQ.js +1 -0
- package/dist/viewer/assets/AppDetailPage-r3jzO9Kf.js +1 -0
- package/dist/viewer/assets/BootstrapContext-CExPp3R2.js +1 -0
- package/dist/viewer/assets/BootstrapContext-CTQMWXf-.js +1 -0
- package/dist/viewer/assets/BootstrapContext-DbnbWmQT.js +1 -0
- package/dist/viewer/assets/Card-Bmn1HMWl.js +1 -0
- package/dist/viewer/assets/Card-DMz6T3VL.js +1 -0
- package/dist/viewer/assets/Card-DsqKctyM.js +1 -0
- package/dist/viewer/assets/CodeStepsPage-BHqLfCdV.js +4 -0
- package/dist/viewer/assets/CodeStepsPage-BymhEfzO.js +4 -0
- package/dist/viewer/assets/CodeStepsPage-CD_MhDwY.js +4 -0
- package/dist/viewer/assets/CodeStepsPage-CgI-LqEx.js +4 -0
- package/dist/viewer/assets/CodeStepsPage-Dak3saZE.js +5 -0
- package/dist/viewer/assets/CodeStepsPage-DdKuH37F.css +1 -0
- package/dist/viewer/assets/CodeStepsPage-Zj6DscGd.js +4 -0
- package/dist/viewer/assets/ConfigurationPage-Cjy9TH3N.js +1 -0
- package/dist/viewer/assets/ConfigurationPage-DmX-6MM-.js +1 -0
- package/dist/viewer/assets/ConfigurationPage-J56kCD_e.js +1 -0
- package/dist/viewer/assets/CredentialsContext-Xbse1T0q.js +1 -0
- package/dist/viewer/assets/CredentialsContext-zl2e9kpM.js +1 -0
- package/dist/viewer/assets/DevSidebar-B30mgxSn.js +1 -0
- package/dist/viewer/assets/{DevSidebar-BiROAoKF.js → DevSidebar-BhTD2bBO.js} +1 -1
- package/dist/viewer/assets/DevSidebar-CsEdCTej.js +1 -0
- package/dist/viewer/assets/IconReferencePage-B6j9wlte.js +1 -0
- package/dist/viewer/assets/IconReferencePage-CJa9yg9Z.js +1 -0
- package/dist/viewer/assets/IconReferencePage-Q5I-lMFQ.js +1 -0
- package/dist/viewer/assets/SandboxPage-C0h7GUkw.js +1 -0
- package/dist/viewer/assets/SandboxPage-GDcydJnJ.js +1 -0
- package/dist/viewer/assets/SandboxPage-JREBQ4id.js +1 -0
- package/dist/viewer/assets/SidebarContext-BPkYyxET.js +1 -0
- package/dist/viewer/assets/SidebarContext-DVDXFWJI.js +1 -0
- package/dist/viewer/assets/SidebarContext-HucmR353.js +1 -0
- package/dist/viewer/assets/VersionsPage-B76eugMm.js +1 -0
- package/dist/viewer/assets/VersionsPage-BIpB0iBz.js +1 -0
- package/dist/viewer/assets/VersionsPage-D0qenxK5.js +1 -0
- package/dist/viewer/assets/api-BOqcXygX.js +1 -0
- package/dist/viewer/assets/api-DqAiw0w9.js +1 -0
- package/dist/viewer/assets/bundleQuery-206rQR6g.js +1 -0
- package/dist/viewer/assets/bundleQuery-L4H4wq5q.js +1 -0
- package/dist/viewer/assets/{fa-core-mHW_3JUd.js → fa-core-DaD7O-yO.js} +1 -1
- package/dist/viewer/assets/fa-core-wsCxaNB7.js +558 -0
- package/dist/viewer/assets/fa-pro-icons-Dzkwxnip.js +1 -0
- package/dist/viewer/assets/index-BPiwld5D.js +5 -0
- package/dist/viewer/assets/index-BiyeMU_r.css +2 -0
- package/dist/viewer/assets/index-BlJv_543.js +5 -0
- package/dist/viewer/assets/index-CAYNux5J.js +5 -0
- package/dist/viewer/assets/index-D4AnoAXz.js +5 -0
- package/dist/viewer/assets/index-D8Koqlb-.js +5 -0
- package/dist/viewer/assets/index-DKrC0qkC.js +5 -0
- package/dist/viewer/assets/{react-D_K8ni3_.js → react-CkuOm_dq.js} +1 -1
- package/dist/viewer/assets/react-CyWK9rg5.js +9 -0
- package/dist/viewer/assets/useLocalStorage-BWwvt0nG.js +1 -0
- package/dist/viewer/assets/useLocalStorage-BlZWItfY.js +1 -0
- package/dist/viewer/assets/useLocalStorage-CQO0VGQ6.js +1 -0
- package/dist/viewer/assets/useNavigate-9J1ZzN1J.js +1 -0
- package/dist/viewer/assets/useNavigate-V8wjv5GQ.js +1 -0
- package/dist/viewer/assets/useObjectLookups-BAqe9wvu.js +14 -0
- package/dist/viewer/assets/useObjectLookups-C65zm-bM.js +14 -0
- package/dist/viewer/assets/useObjectLookups-CslM2vSA.js +14 -0
- package/dist/viewer/assets/{validIcons-TcFXfn-E.js → validIcons-Dqgxgpv-.js} +1 -1
- package/dist/viewer/assets/validIcons-UmfwFGTT.js +1 -0
- package/dist/viewer/index.html +10 -8
- package/dist/viewer/mark.svg +17 -0
- package/package.json +11 -10
- package/dist/viewer/assets/AppDetailPage-ObugMPkn.js +0 -1
- package/dist/viewer/assets/BootstrapContext-CEWgv2oI.js +0 -1
- package/dist/viewer/assets/Card-BSwG5koM.js +0 -1
- package/dist/viewer/assets/ConfigurationPage-SnFNzZgJ.js +0 -1
- package/dist/viewer/assets/CredentialsContext-BLZX6RwF.js +0 -1
- package/dist/viewer/assets/SandboxPage-BFVVe-i3.js +0 -1
- package/dist/viewer/assets/SidebarContext-Byo6PYOF.js +0 -1
- package/dist/viewer/assets/VersionsPage-DOd2Hv8M.js +0 -1
- package/dist/viewer/assets/configStorage-Bb-A9Nvj.js +0 -14
- package/dist/viewer/assets/index-B-4D4w_w.js +0 -5
- package/dist/viewer/assets/index-D6Un_G7k.css +0 -2
- /package/dist/viewer/assets/{fa-pro-icons-CIQGXozY.js → fa-pro-icons-CiTC899m.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -8,8 +8,8 @@ import { createElement } from "react";
|
|
|
8
8
|
import { render } from "ink";
|
|
9
9
|
|
|
10
10
|
// src/ui/BuildUI.tsx
|
|
11
|
-
import { useEffect, useState } from "react";
|
|
12
|
-
import { Box as
|
|
11
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
12
|
+
import { Box as Box3, Text as Text4, useApp } from "ink";
|
|
13
13
|
|
|
14
14
|
// src/lib/runBuild.ts
|
|
15
15
|
import { mkdir, writeFile } from "fs/promises";
|
|
@@ -88,36 +88,66 @@ async function runBuild(pluginDir, outputDir, onStep) {
|
|
|
88
88
|
})).sort((a, b) => b.version.localeCompare(a.version, void 0, { numeric: true })) : [];
|
|
89
89
|
return serializePlugin(plugin, allReleaseNotes);
|
|
90
90
|
});
|
|
91
|
-
|
|
91
|
+
const jsonStr = JSON.stringify(bundle, null, 2);
|
|
92
|
+
const bundleSize = Buffer.byteLength(jsonStr, "utf-8");
|
|
93
|
+
await writeFile(join2(outputDir, "bundle.json"), jsonStr, "utf-8");
|
|
94
|
+
return { bundleSize };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/lib/formatBytes.ts
|
|
98
|
+
function formatBytes(n) {
|
|
99
|
+
if (n < 1024) {
|
|
100
|
+
return `${String(n)} B`;
|
|
101
|
+
}
|
|
102
|
+
if (n < 1024 * 1024) {
|
|
103
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
104
|
+
}
|
|
105
|
+
return `${(n / (1024 * 1024)).toFixed(2)} MB`;
|
|
92
106
|
}
|
|
93
107
|
|
|
108
|
+
// src/ui/AppHeader.tsx
|
|
109
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
110
|
+
|
|
94
111
|
// src/ui/Logo.tsx
|
|
95
112
|
import { Box, Text } from "ink";
|
|
96
113
|
import { jsx } from "react/jsx-runtime";
|
|
97
114
|
var LOGO_LINES = [
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
115
|
+
" :::::::: ",
|
|
116
|
+
" :::::: ::::::::::: ",
|
|
117
|
+
" :::::: :::::::::: ",
|
|
118
|
+
" :::::: :::::: ::::::: ",
|
|
119
|
+
" ::::: :::::: ::::::::::::::::: ",
|
|
120
|
+
" ::::: ::::: ::::::::::::::::::: ",
|
|
121
|
+
" ::::: ::::: :::::: ::::: ",
|
|
122
|
+
":::: ::::: ::: ::::: :: ",
|
|
123
|
+
"::::: :::::: :::::::::: ",
|
|
124
|
+
"::::: :::::: ::::::::::: ",
|
|
125
|
+
" ::::: ::: ::::::: ",
|
|
126
|
+
" ::::::: ::: ::::: ",
|
|
127
|
+
" ::::::::::: :::::: :::::",
|
|
128
|
+
" :::::::::: :::::: :::::",
|
|
129
|
+
" :: ::::: ::: ::::: ::::",
|
|
130
|
+
" ::::: :::::: ::::: ::::: ::: ",
|
|
131
|
+
" ::::::::::::::::::: ::::: ::::: ",
|
|
132
|
+
" ::::::::::::::::: ::::: ::::: ",
|
|
133
|
+
" ::::::::: :::::: :::::: ",
|
|
134
|
+
" :::::::::: :::::: ",
|
|
135
|
+
" ::::::::::: :::::: ",
|
|
136
|
+
" :::::::: "
|
|
116
137
|
];
|
|
117
138
|
var Logo = () => /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: LOGO_LINES.map((line, i) => /* @__PURE__ */ jsx(Text, { color: "cyan", children: line }, i)) });
|
|
118
139
|
|
|
119
|
-
// src/ui/
|
|
140
|
+
// src/ui/AppHeader.tsx
|
|
120
141
|
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
142
|
+
var AppHeader = ({ marginBottom = 0 }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
143
|
+
/* @__PURE__ */ jsx2(Logo, {}),
|
|
144
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, marginBottom, children: /* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "Kizen App Development Toolkit" }) })
|
|
145
|
+
] });
|
|
146
|
+
|
|
147
|
+
// src/ui/Spinner.tsx
|
|
148
|
+
import { useEffect, useState } from "react";
|
|
149
|
+
import { Text as Text3 } from "ink";
|
|
150
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
121
151
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
122
152
|
var Spinner = () => {
|
|
123
153
|
const [frame, setFrame] = useState(0);
|
|
@@ -129,8 +159,11 @@ var Spinner = () => {
|
|
|
129
159
|
clearInterval(id);
|
|
130
160
|
};
|
|
131
161
|
}, []);
|
|
132
|
-
return /* @__PURE__ */
|
|
162
|
+
return /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: SPINNER_FRAMES[frame] ?? "\u280B" });
|
|
133
163
|
};
|
|
164
|
+
|
|
165
|
+
// src/ui/BuildUI.tsx
|
|
166
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
134
167
|
var STEPS = [
|
|
135
168
|
"creating-dir",
|
|
136
169
|
"reading-files",
|
|
@@ -147,10 +180,12 @@ var STEP_LABELS = {
|
|
|
147
180
|
};
|
|
148
181
|
var BuildUI = ({ outputDir, pluginDir }) => {
|
|
149
182
|
const app = useApp();
|
|
150
|
-
const [step, setStep] =
|
|
151
|
-
const [errorMessage, setErrorMessage] =
|
|
152
|
-
|
|
153
|
-
|
|
183
|
+
const [step, setStep] = useState2("creating-dir");
|
|
184
|
+
const [errorMessage, setErrorMessage] = useState2(null);
|
|
185
|
+
const [bundleSize, setBundleSize] = useState2(null);
|
|
186
|
+
useEffect2(() => {
|
|
187
|
+
void runBuild(pluginDir, outputDir, setStep).then(({ bundleSize: size }) => {
|
|
188
|
+
setBundleSize(size);
|
|
154
189
|
setStep("done");
|
|
155
190
|
app.exit();
|
|
156
191
|
}).catch((err) => {
|
|
@@ -163,32 +198,32 @@ var BuildUI = ({ outputDir, pluginDir }) => {
|
|
|
163
198
|
const currentIndex = STEPS.indexOf(step);
|
|
164
199
|
const isError = step === "error";
|
|
165
200
|
const isDone = step === "done";
|
|
166
|
-
return /* @__PURE__ */
|
|
167
|
-
/* @__PURE__ */
|
|
168
|
-
/* @__PURE__ */
|
|
169
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: "cyan", children: "Kizen App Builder" }),
|
|
170
|
-
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2500".repeat(24) })
|
|
171
|
-
] }),
|
|
172
|
-
/* @__PURE__ */ jsxs(Box2, { flexDirection: "column", gap: 0, children: [
|
|
201
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", paddingY: 1, paddingX: 2, children: [
|
|
202
|
+
/* @__PURE__ */ jsx4(AppHeader, { marginBottom: 1 }),
|
|
203
|
+
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
173
204
|
STEPS.map((s, i) => {
|
|
174
205
|
const isActive = step === s;
|
|
175
206
|
const isStepDone = isDone || currentIndex > i;
|
|
176
207
|
const isFailed = isError && i === currentIndex;
|
|
177
|
-
return /* @__PURE__ */
|
|
208
|
+
return /* @__PURE__ */ jsx4(Box3, { gap: 1, children: isFailed ? /* @__PURE__ */ jsxs2(Text4, { color: "red", children: [
|
|
178
209
|
"\u2717 ",
|
|
179
210
|
STEP_LABELS[s]
|
|
180
|
-
] }) : isStepDone ? /* @__PURE__ */
|
|
211
|
+
] }) : isStepDone ? /* @__PURE__ */ jsxs2(Text4, { color: "green", children: [
|
|
181
212
|
"\u2713 ",
|
|
182
213
|
STEP_LABELS[s]
|
|
183
|
-
] }) : isActive ? /* @__PURE__ */
|
|
184
|
-
/* @__PURE__ */
|
|
185
|
-
/* @__PURE__ */
|
|
186
|
-
] }) : /* @__PURE__ */
|
|
214
|
+
] }) : isActive ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
215
|
+
/* @__PURE__ */ jsx4(Spinner, {}),
|
|
216
|
+
/* @__PURE__ */ jsx4(Text4, { children: STEP_LABELS[s] })
|
|
217
|
+
] }) : /* @__PURE__ */ jsxs2(Text4, { dimColor: true, children: [
|
|
187
218
|
" ",
|
|
188
219
|
STEP_LABELS[s]
|
|
189
220
|
] }) }, s);
|
|
190
221
|
}),
|
|
191
|
-
|
|
222
|
+
isDone && bundleSize !== null && /* @__PURE__ */ jsx4(Box3, { marginTop: 1, gap: 1, children: /* @__PURE__ */ jsxs2(Text4, { color: "green", children: [
|
|
223
|
+
"\u2713 bundle.json \u2014 ",
|
|
224
|
+
formatBytes(bundleSize)
|
|
225
|
+
] }) }),
|
|
226
|
+
errorMessage !== null && /* @__PURE__ */ jsx4(Box3, { marginTop: 1, borderStyle: "single", borderColor: "red", paddingX: 1, children: /* @__PURE__ */ jsx4(Text4, { color: "red", children: errorMessage }) })
|
|
192
227
|
] })
|
|
193
228
|
] });
|
|
194
229
|
};
|
|
@@ -222,27 +257,785 @@ function buildCommand(program2) {
|
|
|
222
257
|
});
|
|
223
258
|
}
|
|
224
259
|
|
|
225
|
-
// src/commands/dev.ts
|
|
226
|
-
import { createElement as createElement2 } from "react";
|
|
227
|
-
import { render as render2 } from "ink";
|
|
228
|
-
|
|
229
|
-
// src/ui/DevUI.tsx
|
|
230
|
-
import { useCallback as
|
|
231
|
-
import { Box as
|
|
232
|
-
import {
|
|
233
|
-
import {
|
|
234
|
-
import {
|
|
235
|
-
import {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
260
|
+
// src/commands/dev.ts
|
|
261
|
+
import { createElement as createElement2 } from "react";
|
|
262
|
+
import { render as render2 } from "ink";
|
|
263
|
+
|
|
264
|
+
// src/ui/DevUI.tsx
|
|
265
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useRef, useState as useState5 } from "react";
|
|
266
|
+
import { Box as Box5, Text as Text6, useInput as useInput2 } from "ink";
|
|
267
|
+
import { watch } from "fs";
|
|
268
|
+
import { createServer } from "http";
|
|
269
|
+
import { join as join9 } from "path";
|
|
270
|
+
import { WebSocketServer } from "ws";
|
|
271
|
+
|
|
272
|
+
// src/server/requestHandler.ts
|
|
273
|
+
import { createReadStream } from "fs";
|
|
274
|
+
import { access as access2, readFile as readFile4 } from "fs/promises";
|
|
275
|
+
import { dirname as dirname2, extname, join as join7 } from "path";
|
|
276
|
+
import { fileURLToPath } from "url";
|
|
277
|
+
|
|
278
|
+
// src/lib/proxyCache.ts
|
|
279
|
+
function createProxyCache(options = {}) {
|
|
280
|
+
const cache = /* @__PURE__ */ new Map();
|
|
281
|
+
const { onChange } = options;
|
|
282
|
+
const emitChange = () => {
|
|
283
|
+
onChange?.(cache.size);
|
|
284
|
+
};
|
|
285
|
+
return {
|
|
286
|
+
get(key, fetcher) {
|
|
287
|
+
const existing = cache.get(key);
|
|
288
|
+
if (existing !== void 0) {
|
|
289
|
+
return existing.then((response) => ({ response, fromCache: true }));
|
|
290
|
+
}
|
|
291
|
+
const pending = fetcher().then(async (response) => {
|
|
292
|
+
const headers = Object.fromEntries(response.headers);
|
|
293
|
+
delete headers["content-encoding"];
|
|
294
|
+
delete headers["content-length"];
|
|
295
|
+
return {
|
|
296
|
+
status: response.status,
|
|
297
|
+
headers,
|
|
298
|
+
body: Buffer.from(await response.arrayBuffer())
|
|
299
|
+
};
|
|
300
|
+
}).catch((error) => {
|
|
301
|
+
cache.delete(key);
|
|
302
|
+
emitChange();
|
|
303
|
+
throw error;
|
|
304
|
+
});
|
|
305
|
+
cache.set(key, pending);
|
|
306
|
+
emitChange();
|
|
307
|
+
return pending.then((response) => {
|
|
308
|
+
if (response.status >= 400) {
|
|
309
|
+
cache.delete(key);
|
|
310
|
+
emitChange();
|
|
311
|
+
}
|
|
312
|
+
return { response, fromCache: false };
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
clear() {
|
|
316
|
+
cache.clear();
|
|
317
|
+
emitChange();
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/lib/constants.ts
|
|
323
|
+
var LOG_LIMIT = 50;
|
|
324
|
+
var LOG_DISPLAY = 8;
|
|
325
|
+
var FILE_WATCH_DEBOUNCE_MS = 150;
|
|
326
|
+
var MIME_TYPES = {
|
|
327
|
+
".html": "text/html; charset=utf-8",
|
|
328
|
+
".js": "application/javascript; charset=utf-8",
|
|
329
|
+
".mjs": "application/javascript; charset=utf-8",
|
|
330
|
+
".css": "text/css; charset=utf-8",
|
|
331
|
+
".png": "image/png",
|
|
332
|
+
".jpg": "image/jpeg",
|
|
333
|
+
".svg": "image/svg+xml",
|
|
334
|
+
".ico": "image/x-icon",
|
|
335
|
+
".json": "application/json; charset=utf-8",
|
|
336
|
+
".woff": "font/woff",
|
|
337
|
+
".woff2": "font/woff2",
|
|
338
|
+
".ttf": "font/ttf",
|
|
339
|
+
".map": "application/json"
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// src/lib/credentials.ts
|
|
343
|
+
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir2, writeFile as writeFile2 } from "fs/promises";
|
|
344
|
+
import { homedir } from "os";
|
|
345
|
+
import { dirname, join as join4 } from "path";
|
|
346
|
+
var ENVIRONMENTS = ["go", "fmo", "staging", "integration", "test1"];
|
|
347
|
+
var GLOBAL_CREDENTIALS_DIR = join4(homedir(), ".kizenappbuilder");
|
|
348
|
+
var GLOBAL_CREDENTIALS_PATH = join4(GLOBAL_CREDENTIALS_DIR, "credentials.json");
|
|
349
|
+
var DEFAULT_PROFILE_NAME = "credentials";
|
|
350
|
+
function isValidEnvironment(value) {
|
|
351
|
+
return ENVIRONMENTS.includes(value);
|
|
352
|
+
}
|
|
353
|
+
function parseCredentials(raw) {
|
|
354
|
+
if (typeof raw !== "object" || raw === null) {
|
|
355
|
+
throw new Error("Credentials must be a JSON object");
|
|
356
|
+
}
|
|
357
|
+
const obj = raw;
|
|
358
|
+
const env = obj.environment;
|
|
359
|
+
return {
|
|
360
|
+
apiKey: typeof obj.apiKey === "string" ? obj.apiKey : "",
|
|
361
|
+
userId: typeof obj.userId === "string" ? obj.userId : "",
|
|
362
|
+
businessId: typeof obj.businessId === "string" ? obj.businessId : "",
|
|
363
|
+
environment: isValidEnvironment(env) ? env : "go"
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
async function loadCredentialsFromFile(filePath) {
|
|
367
|
+
const content = await readFile2(filePath, "utf-8");
|
|
368
|
+
return parseCredentials(JSON.parse(content));
|
|
369
|
+
}
|
|
370
|
+
async function loadGlobalCredentials() {
|
|
371
|
+
try {
|
|
372
|
+
return await loadCredentialsFromFile(GLOBAL_CREDENTIALS_PATH);
|
|
373
|
+
} catch {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
async function saveGlobalCredentials(credentials) {
|
|
378
|
+
await mkdir2(dirname(GLOBAL_CREDENTIALS_PATH), { recursive: true });
|
|
379
|
+
await writeFile2(GLOBAL_CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), "utf-8");
|
|
380
|
+
}
|
|
381
|
+
function getProfilePath(name) {
|
|
382
|
+
return join4(GLOBAL_CREDENTIALS_DIR, `${name}.json`);
|
|
383
|
+
}
|
|
384
|
+
async function listCredentialProfiles() {
|
|
385
|
+
const profiles = [
|
|
386
|
+
{ name: DEFAULT_PROFILE_NAME, path: GLOBAL_CREDENTIALS_PATH, isDefault: true }
|
|
387
|
+
];
|
|
388
|
+
try {
|
|
389
|
+
const entries = await readdir2(GLOBAL_CREDENTIALS_DIR);
|
|
390
|
+
for (const entry of entries) {
|
|
391
|
+
if (!entry.endsWith(".json")) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
const name = entry.slice(0, -5);
|
|
395
|
+
if (name === DEFAULT_PROFILE_NAME) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
profiles.push({ name, path: join4(GLOBAL_CREDENTIALS_DIR, entry), isDefault: false });
|
|
399
|
+
}
|
|
400
|
+
} catch {
|
|
401
|
+
}
|
|
402
|
+
return profiles;
|
|
403
|
+
}
|
|
404
|
+
async function saveCredentialProfile(name, credentials) {
|
|
405
|
+
if (name === DEFAULT_PROFILE_NAME) {
|
|
406
|
+
await saveGlobalCredentials(credentials);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
await mkdir2(GLOBAL_CREDENTIALS_DIR, { recursive: true });
|
|
410
|
+
await writeFile2(getProfilePath(name), JSON.stringify(credentials, null, 2), "utf-8");
|
|
411
|
+
}
|
|
412
|
+
async function loadCredentialProfile(name) {
|
|
413
|
+
try {
|
|
414
|
+
return await loadCredentialsFromFile(getProfilePath(name));
|
|
415
|
+
} catch {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// src/lib/config.ts
|
|
421
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
422
|
+
import { join as join5 } from "path";
|
|
423
|
+
async function loadConfig(outputDir) {
|
|
424
|
+
try {
|
|
425
|
+
const content = await readFile3(join5(outputDir, "config.json"), "utf-8");
|
|
426
|
+
return JSON.parse(content);
|
|
427
|
+
} catch {
|
|
428
|
+
return {};
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
async function saveConfig(outputDir, config) {
|
|
432
|
+
await mkdir3(outputDir, { recursive: true });
|
|
433
|
+
await writeFile3(join5(outputDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/server/pythonExecutor.ts
|
|
437
|
+
import { spawn, execFileSync } from "child_process";
|
|
438
|
+
import { writeFile as writeFile4, rm, mkdtemp, access } from "fs/promises";
|
|
439
|
+
import { join as join6 } from "path";
|
|
440
|
+
import { tmpdir } from "os";
|
|
441
|
+
var WRAPPER_SCRIPT = `
|
|
442
|
+
import sys, json, os, traceback
|
|
443
|
+
|
|
444
|
+
# --- Inputs proxy (attribute access) ---
|
|
445
|
+
class _InputsProxy:
|
|
446
|
+
def __init__(self, data):
|
|
447
|
+
object.__setattr__(self, '_data', data)
|
|
448
|
+
|
|
449
|
+
def __getattr__(self, name):
|
|
450
|
+
if name.startswith('_'):
|
|
451
|
+
raise AttributeError(name)
|
|
452
|
+
return self._data.get(name)
|
|
453
|
+
|
|
454
|
+
def __repr__(self):
|
|
455
|
+
return repr(self._data)
|
|
456
|
+
|
|
457
|
+
def __str__(self):
|
|
458
|
+
return str(self._data)
|
|
459
|
+
|
|
460
|
+
def __bool__(self):
|
|
461
|
+
return bool(self._data)
|
|
462
|
+
|
|
463
|
+
inputs = _InputsProxy(json.loads(os.environ.get('__KIZEN_INPUTS__', '{}')))
|
|
464
|
+
|
|
465
|
+
# --- Secrets ---
|
|
466
|
+
secrets = json.loads(os.environ.get('__KIZEN_SECRETS__', '{}'))
|
|
467
|
+
|
|
468
|
+
# --- Outputs proxy ---
|
|
469
|
+
class _OutputsProxy:
|
|
470
|
+
def __init__(self):
|
|
471
|
+
object.__setattr__(self, '_values', {})
|
|
472
|
+
object.__setattr__(self, '_logs', [])
|
|
473
|
+
|
|
474
|
+
def __setattr__(self, name, value):
|
|
475
|
+
if name.startswith('_'):
|
|
476
|
+
object.__setattr__(self, name, value)
|
|
477
|
+
else:
|
|
478
|
+
self._values[name] = value
|
|
479
|
+
|
|
480
|
+
def __getattr__(self, name):
|
|
481
|
+
if name.startswith('_'):
|
|
482
|
+
raise AttributeError(name)
|
|
483
|
+
return self._values.get(name)
|
|
484
|
+
|
|
485
|
+
def log(self, message):
|
|
486
|
+
self._logs.append(str(message))
|
|
487
|
+
|
|
488
|
+
outputs = _OutputsProxy()
|
|
489
|
+
|
|
490
|
+
# --- Execute user script ---
|
|
491
|
+
try:
|
|
492
|
+
exec(open(os.environ['__KIZEN_SCRIPT_PATH__'], encoding='utf-8').read())
|
|
493
|
+
result = {
|
|
494
|
+
'success': True,
|
|
495
|
+
'outputValues': outputs._values,
|
|
496
|
+
'logs': outputs._logs,
|
|
497
|
+
'error': None,
|
|
498
|
+
}
|
|
499
|
+
except Exception:
|
|
500
|
+
# Build a clean traceback that hides the wrapper internals.
|
|
501
|
+
# Keep only frames from the user script (shown as File "<string>")
|
|
502
|
+
# and re-label them with "script.py" for clarity.
|
|
503
|
+
exc_type, exc_value, exc_tb = sys.exc_info()
|
|
504
|
+
entries = traceback.extract_tb(exc_tb)
|
|
505
|
+
user_entries = [e for e in entries if e.filename != __file__]
|
|
506
|
+
for e in user_entries:
|
|
507
|
+
if e.filename == '<string>':
|
|
508
|
+
e.filename = 'script.py'
|
|
509
|
+
lines = ['Traceback (most recent call last):\\n']
|
|
510
|
+
lines += traceback.format_list(user_entries)
|
|
511
|
+
lines += traceback.format_exception_only(exc_type, exc_value)
|
|
512
|
+
result = {
|
|
513
|
+
'success': False,
|
|
514
|
+
'outputValues': outputs._values,
|
|
515
|
+
'logs': outputs._logs,
|
|
516
|
+
'error': ''.join(lines),
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
# Write results between markers so we can extract them reliably
|
|
520
|
+
# even if the user script wrote to stdout
|
|
521
|
+
sys.stdout.write('\\n__KIZEN_RESULT_START__\\n')
|
|
522
|
+
sys.stdout.write(json.dumps(result, ensure_ascii=False))
|
|
523
|
+
sys.stdout.write('\\n__KIZEN_RESULT_END__\\n')
|
|
524
|
+
sys.stdout.flush()
|
|
525
|
+
`.trim();
|
|
526
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
527
|
+
var VENV_DIR = join6(process.cwd(), ".kizenapp", "venv");
|
|
528
|
+
var VENV_PACKAGES = ["requests"];
|
|
529
|
+
var venvReady = null;
|
|
530
|
+
function resolvePythonBinary(runtime) {
|
|
531
|
+
const match = /^python-(\d+\.\d+)$/.exec(runtime);
|
|
532
|
+
if (match?.[1]) {
|
|
533
|
+
return `python${match[1]}`;
|
|
534
|
+
}
|
|
535
|
+
return "python3";
|
|
536
|
+
}
|
|
537
|
+
function ensureVenv(runtime) {
|
|
538
|
+
if (!venvReady) {
|
|
539
|
+
venvReady = (async () => {
|
|
540
|
+
const venvPython = join6(VENV_DIR, "bin", "python");
|
|
541
|
+
try {
|
|
542
|
+
await access(venvPython);
|
|
543
|
+
} catch {
|
|
544
|
+
const systemPython = resolvePythonBinary(runtime);
|
|
545
|
+
execFileSync(systemPython, ["-m", "venv", VENV_DIR], { stdio: "ignore" });
|
|
546
|
+
}
|
|
547
|
+
execFileSync(venvPython, ["-m", "pip", "install", "-q", ...VENV_PACKAGES], {
|
|
548
|
+
stdio: "ignore"
|
|
549
|
+
});
|
|
550
|
+
return venvPython;
|
|
551
|
+
})();
|
|
552
|
+
}
|
|
553
|
+
return venvReady;
|
|
554
|
+
}
|
|
555
|
+
function parseResult(stdout) {
|
|
556
|
+
const startMarker = "__KIZEN_RESULT_START__";
|
|
557
|
+
const endMarker = "__KIZEN_RESULT_END__";
|
|
558
|
+
const startIdx = stdout.indexOf(startMarker);
|
|
559
|
+
const endIdx = stdout.indexOf(endMarker);
|
|
560
|
+
if (startIdx === -1 || endIdx === -1) {
|
|
561
|
+
return { userStdout: stdout, result: null };
|
|
562
|
+
}
|
|
563
|
+
const userStdout = stdout.slice(0, startIdx).trimEnd();
|
|
564
|
+
const jsonStr = stdout.slice(startIdx + startMarker.length, endIdx).trim();
|
|
565
|
+
try {
|
|
566
|
+
const result = JSON.parse(jsonStr);
|
|
567
|
+
return { userStdout, result };
|
|
568
|
+
} catch {
|
|
569
|
+
return { userStdout: stdout, result: null };
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
async function executePythonStep(params) {
|
|
573
|
+
const timeout = params.timeout ?? DEFAULT_TIMEOUT;
|
|
574
|
+
const pythonBin = await ensureVenv(params.scriptRuntime);
|
|
575
|
+
const start = Date.now();
|
|
576
|
+
let tmpDir;
|
|
577
|
+
try {
|
|
578
|
+
tmpDir = await mkdtemp(join6(tmpdir(), "kizen-step-"));
|
|
579
|
+
const wrapperPath = join6(tmpDir, "wrapper.py");
|
|
580
|
+
const scriptPath = join6(tmpDir, "script.py");
|
|
581
|
+
await Promise.all([
|
|
582
|
+
writeFile4(wrapperPath, WRAPPER_SCRIPT, "utf-8"),
|
|
583
|
+
writeFile4(scriptPath, params.script, "utf-8")
|
|
584
|
+
]);
|
|
585
|
+
const env = {
|
|
586
|
+
...process.env,
|
|
587
|
+
__KIZEN_INPUTS__: JSON.stringify(params.inputs),
|
|
588
|
+
__KIZEN_SECRETS__: JSON.stringify(params.secrets),
|
|
589
|
+
__KIZEN_SCRIPT_PATH__: scriptPath
|
|
590
|
+
};
|
|
591
|
+
const { exitCode, stdout, stderr } = await new Promise((resolve) => {
|
|
592
|
+
const stdoutChunks = [];
|
|
593
|
+
const stderrChunks = [];
|
|
594
|
+
let settled = false;
|
|
595
|
+
const proc = spawn(pythonBin, [wrapperPath], {
|
|
596
|
+
env,
|
|
597
|
+
cwd: tmpDir,
|
|
598
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
599
|
+
});
|
|
600
|
+
const timer = setTimeout(() => {
|
|
601
|
+
proc.kill("SIGKILL");
|
|
602
|
+
}, timeout);
|
|
603
|
+
proc.stdout.on("data", (chunk) => {
|
|
604
|
+
stdoutChunks.push(chunk);
|
|
605
|
+
});
|
|
606
|
+
proc.stderr.on("data", (chunk) => {
|
|
607
|
+
stderrChunks.push(chunk);
|
|
608
|
+
});
|
|
609
|
+
const finish = (code) => {
|
|
610
|
+
if (settled) {
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
settled = true;
|
|
614
|
+
clearTimeout(timer);
|
|
615
|
+
resolve({
|
|
616
|
+
exitCode: code ?? 1,
|
|
617
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
618
|
+
stderr: Buffer.concat(stderrChunks).toString("utf-8")
|
|
619
|
+
});
|
|
620
|
+
};
|
|
621
|
+
proc.on("close", finish);
|
|
622
|
+
proc.on("error", (err) => {
|
|
623
|
+
if (settled) {
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
settled = true;
|
|
627
|
+
clearTimeout(timer);
|
|
628
|
+
resolve({
|
|
629
|
+
exitCode: 1,
|
|
630
|
+
stdout: "",
|
|
631
|
+
stderr: err.message
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
const durationMs = Date.now() - start;
|
|
636
|
+
const { userStdout, result } = parseResult(stdout);
|
|
637
|
+
if (result) {
|
|
638
|
+
const base2 = {
|
|
639
|
+
success: result.success,
|
|
640
|
+
outputValues: result.outputValues,
|
|
641
|
+
logs: result.logs,
|
|
642
|
+
stdout: userStdout,
|
|
643
|
+
stderr,
|
|
644
|
+
exitCode,
|
|
645
|
+
durationMs
|
|
646
|
+
};
|
|
647
|
+
if (result.error !== null) {
|
|
648
|
+
base2.error = result.error;
|
|
649
|
+
}
|
|
650
|
+
return base2;
|
|
651
|
+
}
|
|
652
|
+
const base = {
|
|
653
|
+
success: false,
|
|
654
|
+
outputValues: {},
|
|
655
|
+
logs: [],
|
|
656
|
+
stdout: userStdout,
|
|
657
|
+
stderr,
|
|
658
|
+
exitCode,
|
|
659
|
+
durationMs
|
|
660
|
+
};
|
|
661
|
+
if (exitCode !== 0) {
|
|
662
|
+
base.error = `Process exited with code ${String(exitCode)}`;
|
|
663
|
+
}
|
|
664
|
+
return base;
|
|
665
|
+
} finally {
|
|
666
|
+
if (tmpDir) {
|
|
667
|
+
void rm(tmpDir, { recursive: true, force: true });
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/server/remoteCodeRunner.ts
|
|
673
|
+
var BASE_URLS = {
|
|
674
|
+
go: "https://app.go.kizen.com/api",
|
|
675
|
+
fmo: "https://app.fmo.kizen.com/api",
|
|
676
|
+
staging: "https://staging.kizen.dev/api",
|
|
677
|
+
integration: "https://integration.kizen.dev/api",
|
|
678
|
+
test1: "https://test1.kizen.dev/api"
|
|
679
|
+
};
|
|
680
|
+
var SUPPORTED_RUNTIMES = ["python-3-13", "python-3-12"];
|
|
681
|
+
var DEFAULT_RUNTIME = "python-3-12";
|
|
682
|
+
var DATA_TYPE_TO_KIZEN = {
|
|
683
|
+
text: "s",
|
|
684
|
+
string: "s",
|
|
685
|
+
number: "n",
|
|
686
|
+
integer: "n",
|
|
687
|
+
boolean: "b",
|
|
688
|
+
date: "d",
|
|
689
|
+
datetime: "dt",
|
|
690
|
+
phone: "p",
|
|
691
|
+
phonenumber: "p",
|
|
692
|
+
uuid: "u",
|
|
693
|
+
file: "f",
|
|
694
|
+
list: "l"
|
|
695
|
+
};
|
|
696
|
+
function toKizenType(dataType) {
|
|
697
|
+
return DATA_TYPE_TO_KIZEN[dataType.toLowerCase()] ?? "s";
|
|
698
|
+
}
|
|
699
|
+
function resolveRuntime(runtime) {
|
|
700
|
+
if (SUPPORTED_RUNTIMES.includes(runtime)) {
|
|
701
|
+
return runtime;
|
|
702
|
+
}
|
|
703
|
+
return DEFAULT_RUNTIME;
|
|
704
|
+
}
|
|
705
|
+
function encodeInputs(inputs, inputTypes) {
|
|
706
|
+
const keys = Object.keys(inputs);
|
|
707
|
+
if (keys.length === 0) {
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
const encoded = {};
|
|
711
|
+
for (const key of keys) {
|
|
712
|
+
encoded[key] = {
|
|
713
|
+
t: toKizenType(inputTypes[key] ?? "string"),
|
|
714
|
+
v: inputs[key]
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
return encoded;
|
|
718
|
+
}
|
|
719
|
+
function encodeOutputTypes(outputTypes) {
|
|
720
|
+
const keys = Object.keys(outputTypes);
|
|
721
|
+
if (keys.length === 0) {
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
const encoded = {};
|
|
725
|
+
for (const key of keys) {
|
|
726
|
+
encoded[key] = toKizenType(outputTypes[key] ?? "string");
|
|
727
|
+
}
|
|
728
|
+
return encoded;
|
|
729
|
+
}
|
|
730
|
+
function decodeOutputValues(values) {
|
|
731
|
+
if (!values) {
|
|
732
|
+
return {};
|
|
733
|
+
}
|
|
734
|
+
const decoded = {};
|
|
735
|
+
for (const [key, encoded] of Object.entries(values)) {
|
|
736
|
+
decoded[key] = encoded.v;
|
|
737
|
+
}
|
|
738
|
+
return decoded;
|
|
739
|
+
}
|
|
740
|
+
async function executeRemoteStep(params, credentials) {
|
|
741
|
+
const baseUrl = BASE_URLS[credentials.environment];
|
|
742
|
+
const url = `${baseUrl}/coderunner/run`;
|
|
743
|
+
const start = Date.now();
|
|
744
|
+
const body = {
|
|
745
|
+
user_script: params.script,
|
|
746
|
+
runtime: resolveRuntime(params.scriptRuntime),
|
|
747
|
+
secrets: params.secretNames.length > 0 ? params.secretNames : void 0,
|
|
748
|
+
inputs: encodeInputs(params.inputs, params.inputTypes),
|
|
749
|
+
output_types: encodeOutputTypes(params.outputTypes)
|
|
750
|
+
};
|
|
751
|
+
try {
|
|
752
|
+
const response = await fetch(url, {
|
|
753
|
+
method: "POST",
|
|
754
|
+
headers: {
|
|
755
|
+
"Content-Type": "application/json",
|
|
756
|
+
"X-API-KEY": credentials.apiKey,
|
|
757
|
+
"X-USER-ID": credentials.userId,
|
|
758
|
+
"X-BUSINESS-ID": credentials.businessId
|
|
759
|
+
},
|
|
760
|
+
body: JSON.stringify(body)
|
|
761
|
+
});
|
|
762
|
+
const durationMs = Date.now() - start;
|
|
763
|
+
if (!response.ok) {
|
|
764
|
+
const text = await response.text();
|
|
765
|
+
return {
|
|
766
|
+
success: false,
|
|
767
|
+
outputValues: {},
|
|
768
|
+
logs: [],
|
|
769
|
+
stdout: "",
|
|
770
|
+
stderr: "",
|
|
771
|
+
error: `Remote runner returned ${String(response.status)}: ${text}`,
|
|
772
|
+
exitCode: 1,
|
|
773
|
+
durationMs
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
const data = await response.json();
|
|
777
|
+
const hasError = data.error !== null;
|
|
778
|
+
const result = {
|
|
779
|
+
success: !hasError,
|
|
780
|
+
outputValues: decodeOutputValues(data.values),
|
|
781
|
+
logs: data.logs ?? [],
|
|
782
|
+
stdout: "",
|
|
783
|
+
stderr: "",
|
|
784
|
+
exitCode: hasError ? 1 : 0,
|
|
785
|
+
durationMs: data.duration_ms ?? durationMs
|
|
786
|
+
};
|
|
787
|
+
if (hasError && data.error) {
|
|
788
|
+
result.error = data.error.detail ? `${data.error.error}
|
|
789
|
+
${data.error.detail}` : data.error.error;
|
|
790
|
+
}
|
|
791
|
+
return result;
|
|
792
|
+
} catch (err) {
|
|
793
|
+
return {
|
|
794
|
+
success: false,
|
|
795
|
+
outputValues: {},
|
|
796
|
+
logs: [],
|
|
797
|
+
stdout: "",
|
|
798
|
+
stderr: "",
|
|
799
|
+
error: `Remote execution failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
800
|
+
exitCode: 1,
|
|
801
|
+
durationMs: Date.now() - start
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// src/server/requestHandler.ts
|
|
807
|
+
function proxyLogEntryToString(entry) {
|
|
808
|
+
if (entry.kind === "info") {
|
|
809
|
+
return entry.message;
|
|
810
|
+
}
|
|
811
|
+
const cache = entry.fromCache ? " [cache]" : "";
|
|
812
|
+
return `${entry.method} ${entry.url} \u2192 ${String(entry.status)}${cache}`;
|
|
813
|
+
}
|
|
814
|
+
function getViewerPath() {
|
|
815
|
+
const filename = fileURLToPath(import.meta.url);
|
|
816
|
+
return join7(dirname2(filename), "viewer");
|
|
817
|
+
}
|
|
818
|
+
async function fileExists(filePath) {
|
|
819
|
+
try {
|
|
820
|
+
await access2(filePath);
|
|
821
|
+
return true;
|
|
822
|
+
} catch {
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast, onProxyCacheChange, lastPathRef) {
|
|
827
|
+
const proxyCache = createProxyCache({ onChange: onProxyCacheChange });
|
|
828
|
+
return (req, res) => {
|
|
829
|
+
void (async () => {
|
|
830
|
+
const url = req.url ?? "/";
|
|
831
|
+
try {
|
|
832
|
+
createServerLog(`Received request: ${url}`);
|
|
833
|
+
if (url === "/api/credentials") {
|
|
834
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
835
|
+
res.end(credentialsRef.current !== null ? JSON.stringify(credentialsRef.current) : "{}");
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
if (url === "/api/credential-profiles" && req.method === "GET") {
|
|
839
|
+
const profiles = await listCredentialProfiles();
|
|
840
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
841
|
+
res.end(JSON.stringify({ profiles, active: activeProfileRef.current }));
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
if (url === "/api/credentials/switch" && req.method === "POST") {
|
|
845
|
+
const chunks = [];
|
|
846
|
+
for await (const chunk of req) {
|
|
847
|
+
chunks.push(chunk);
|
|
848
|
+
}
|
|
849
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}");
|
|
850
|
+
const profileName = body.profile;
|
|
851
|
+
const creds = profileName === void 0 || profileName === "" ? await loadGlobalCredentials() : await loadCredentialProfile(profileName);
|
|
852
|
+
if (creds !== null) {
|
|
853
|
+
credentialsRef.current = creds;
|
|
854
|
+
activeProfileRef.current = profileName ?? void 0;
|
|
855
|
+
const active = activeProfileRef.current;
|
|
856
|
+
await saveConfig(outputDir, {
|
|
857
|
+
credentialMode: "global",
|
|
858
|
+
...active !== void 0 && { activeCredentialProfile: active }
|
|
859
|
+
});
|
|
860
|
+
broadcast({ type: "credentials-updated", credentials: creds });
|
|
861
|
+
}
|
|
862
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
863
|
+
res.end(JSON.stringify({ ok: creds !== null }));
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
if (url === "/api/bundle") {
|
|
867
|
+
const bundlePath = join7(process.cwd(), ".kizenapp", "bundle.json");
|
|
868
|
+
try {
|
|
869
|
+
const content = await readFile4(bundlePath, "utf-8");
|
|
870
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
871
|
+
res.end(content);
|
|
872
|
+
} catch {
|
|
873
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
874
|
+
res.end("{}");
|
|
875
|
+
}
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
if (url === "/api/last-path" && req.method === "POST") {
|
|
879
|
+
const chunks = [];
|
|
880
|
+
for await (const chunk of req) {
|
|
881
|
+
chunks.push(chunk);
|
|
882
|
+
}
|
|
883
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}");
|
|
884
|
+
if (typeof body.path === "string") {
|
|
885
|
+
lastPathRef.current = body.path;
|
|
886
|
+
const currentConfig = await loadConfig(outputDir);
|
|
887
|
+
await saveConfig(outputDir, { ...currentConfig, lastPath: body.path });
|
|
888
|
+
}
|
|
889
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
890
|
+
res.end('{"ok":true}');
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
if (url === "/api/execute-step" && req.method === "POST") {
|
|
894
|
+
const chunks = [];
|
|
895
|
+
for await (const chunk of req) {
|
|
896
|
+
chunks.push(chunk);
|
|
897
|
+
}
|
|
898
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}");
|
|
899
|
+
if (typeof body.script !== "string") {
|
|
900
|
+
res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
|
|
901
|
+
res.end(JSON.stringify({ error: "Missing required field: script" }));
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
let result;
|
|
905
|
+
if (body.mode === "remote") {
|
|
906
|
+
if (!credentialsRef.current) {
|
|
907
|
+
res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
|
|
908
|
+
res.end(JSON.stringify({ error: "Credentials are required for remote execution" }));
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
result = await executeRemoteStep(
|
|
912
|
+
{
|
|
913
|
+
script: body.script,
|
|
914
|
+
scriptRuntime: body.scriptRuntime ?? "python-3-12",
|
|
915
|
+
inputs: body.inputs ?? {},
|
|
916
|
+
inputTypes: body.inputTypes ?? {},
|
|
917
|
+
outputTypes: body.outputTypes ?? {},
|
|
918
|
+
secretNames: body.secretNames ?? []
|
|
919
|
+
},
|
|
920
|
+
credentialsRef.current
|
|
921
|
+
);
|
|
922
|
+
} else {
|
|
923
|
+
const stepParams = {
|
|
924
|
+
script: body.script,
|
|
925
|
+
scriptRuntime: body.scriptRuntime ?? "python-3.9",
|
|
926
|
+
inputs: body.inputs ?? {},
|
|
927
|
+
secrets: body.secrets ?? {}
|
|
928
|
+
};
|
|
929
|
+
if (typeof body.timeout === "number") {
|
|
930
|
+
stepParams.timeout = body.timeout;
|
|
931
|
+
}
|
|
932
|
+
result = await executePythonStep(stepParams);
|
|
933
|
+
}
|
|
934
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
935
|
+
res.end(JSON.stringify(result));
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
if (url === "/api/proxy-cache/clear") {
|
|
939
|
+
proxyCache.clear();
|
|
940
|
+
createProxyLog({ kind: "info", message: "Proxy cache cleared" });
|
|
941
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
942
|
+
res.end('{"ok":true}');
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
if (url.startsWith("/api/proxy")) {
|
|
946
|
+
const proxyTarget = req.headers["x-proxy-target"];
|
|
947
|
+
if (typeof proxyTarget !== "string") {
|
|
948
|
+
res.writeHead(400);
|
|
949
|
+
res.end("Missing x-proxy-target header");
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
const upstreamPath = url.slice("/api/proxy".length) || "/";
|
|
953
|
+
const upstreamUrl = `${proxyTarget}${upstreamPath}`;
|
|
954
|
+
const method = req.method ?? "GET";
|
|
955
|
+
const chunks = [];
|
|
956
|
+
for await (const chunk of req) {
|
|
957
|
+
chunks.push(chunk);
|
|
958
|
+
}
|
|
959
|
+
const { host, "x-proxy-target": _drop, ...forwardHeaders } = req.headers;
|
|
960
|
+
if (method === "GET") {
|
|
961
|
+
const cacheKey = `GET::${upstreamUrl}`;
|
|
962
|
+
const { response: cached, fromCache } = await proxyCache.get(
|
|
963
|
+
cacheKey,
|
|
964
|
+
() => fetch(upstreamUrl, {
|
|
965
|
+
method: "GET",
|
|
966
|
+
headers: forwardHeaders
|
|
967
|
+
})
|
|
968
|
+
);
|
|
969
|
+
createProxyLog({
|
|
970
|
+
kind: "request",
|
|
971
|
+
method: "GET",
|
|
972
|
+
status: cached.status,
|
|
973
|
+
fromCache,
|
|
974
|
+
url: upstreamPath
|
|
975
|
+
});
|
|
976
|
+
res.writeHead(cached.status, cached.headers);
|
|
977
|
+
res.end(cached.body);
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
|
|
981
|
+
const resolvedBody = body && body.length > 0 ? body : void 0;
|
|
982
|
+
const upstream = await fetch(upstreamUrl, {
|
|
983
|
+
method,
|
|
984
|
+
headers: forwardHeaders,
|
|
985
|
+
...resolvedBody !== void 0 && { body: resolvedBody }
|
|
986
|
+
});
|
|
987
|
+
createProxyLog({
|
|
988
|
+
kind: "request",
|
|
989
|
+
method,
|
|
990
|
+
status: upstream.status,
|
|
991
|
+
fromCache: false,
|
|
992
|
+
url: upstreamPath
|
|
993
|
+
});
|
|
994
|
+
const responseHeaders = Object.fromEntries(upstream.headers);
|
|
995
|
+
delete responseHeaders["content-encoding"];
|
|
996
|
+
delete responseHeaders["content-length"];
|
|
997
|
+
res.writeHead(upstream.status, responseHeaders);
|
|
998
|
+
res.end(Buffer.from(await upstream.arrayBuffer()));
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
const rawPath = url === "/" ? "/index.html" : url;
|
|
1002
|
+
const filePath = join7(viewerPath, rawPath);
|
|
1003
|
+
const resolvedPath = await fileExists(filePath) ? filePath : join7(viewerPath, "index.html");
|
|
1004
|
+
const ext = extname(resolvedPath);
|
|
1005
|
+
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
1006
|
+
res.writeHead(200, { "Content-Type": mimeType });
|
|
1007
|
+
createReadStream(resolvedPath).pipe(res);
|
|
1008
|
+
} catch (err) {
|
|
1009
|
+
if (url.startsWith("/api/proxy")) {
|
|
1010
|
+
createProxyLog({
|
|
1011
|
+
kind: "request",
|
|
1012
|
+
method: req.method ?? "GET",
|
|
1013
|
+
status: 502,
|
|
1014
|
+
fromCache: false,
|
|
1015
|
+
url: url.slice("/api/proxy".length) || "/"
|
|
1016
|
+
});
|
|
1017
|
+
} else {
|
|
1018
|
+
createProxyLog({
|
|
1019
|
+
kind: "info",
|
|
1020
|
+
message: `Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
if (!res.headersSent) {
|
|
1024
|
+
res.writeHead(502);
|
|
1025
|
+
res.end("Bad Gateway");
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
})();
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
|
|
239
1032
|
// src/chrome/launcher.ts
|
|
240
1033
|
import { launch } from "chrome-launcher";
|
|
241
1034
|
import { createRequire } from "module";
|
|
242
1035
|
import { mkdirSync } from "fs";
|
|
243
|
-
import { readFile as
|
|
244
|
-
import { dirname, join as
|
|
245
|
-
import { fileURLToPath } from "url";
|
|
1036
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
1037
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
1038
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
246
1039
|
var CDP = createRequire(import.meta.url)("chrome-remote-interface");
|
|
247
1040
|
var CSP_HEADERS = /* @__PURE__ */ new Set([
|
|
248
1041
|
"content-security-policy",
|
|
@@ -320,18 +1113,19 @@ async function serializeArgAsync(client, arg) {
|
|
|
320
1113
|
}
|
|
321
1114
|
async function installDockIcon(client) {
|
|
322
1115
|
try {
|
|
323
|
-
const iconPath =
|
|
324
|
-
const icon = await
|
|
1116
|
+
const iconPath = join8(dirname3(fileURLToPath2(import.meta.url)), "viewer", "icon.png");
|
|
1117
|
+
const icon = await readFile5(iconPath);
|
|
325
1118
|
await client.Browser.setDockTile({ image: icon.toString("base64") });
|
|
326
1119
|
} catch {
|
|
327
1120
|
}
|
|
328
1121
|
}
|
|
329
1122
|
async function launchChromeViewer(opts) {
|
|
330
1123
|
mkdirSync(opts.userDataDir, { recursive: true });
|
|
1124
|
+
const baseUrl = `http://localhost:${String(opts.port)}`;
|
|
331
1125
|
const chrome = await launch({
|
|
332
|
-
startingUrl:
|
|
1126
|
+
startingUrl: baseUrl,
|
|
333
1127
|
chromeFlags: [
|
|
334
|
-
`--app
|
|
1128
|
+
`--app=${baseUrl}`,
|
|
335
1129
|
"--no-first-run",
|
|
336
1130
|
"--no-default-browser-check",
|
|
337
1131
|
"--disable-extensions"
|
|
@@ -347,6 +1141,9 @@ async function launchChromeViewer(opts) {
|
|
|
347
1141
|
await new Promise((r) => setTimeout(r, 300));
|
|
348
1142
|
try {
|
|
349
1143
|
client = await CDP({ port: cdpPort });
|
|
1144
|
+
if (opts.path) {
|
|
1145
|
+
void client.send("Page.navigate", { url: `${baseUrl}${opts.path}` });
|
|
1146
|
+
}
|
|
350
1147
|
break;
|
|
351
1148
|
} catch {
|
|
352
1149
|
if (attempt === 9) {
|
|
@@ -465,188 +1262,63 @@ async function launchChromeViewer(opts) {
|
|
|
465
1262
|
c.on("Runtime.consoleAPICalled", (rawParams) => {
|
|
466
1263
|
void (async () => {
|
|
467
1264
|
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
|
-
}
|
|
487
|
-
|
|
488
|
-
// src/lib/proxyCache.ts
|
|
489
|
-
function createProxyCache(options = {}) {
|
|
490
|
-
const cache = /* @__PURE__ */ new Map();
|
|
491
|
-
const { onChange } = options;
|
|
492
|
-
const emitChange = () => {
|
|
493
|
-
onChange?.(cache.size);
|
|
494
|
-
};
|
|
495
|
-
return {
|
|
496
|
-
get(key, fetcher) {
|
|
497
|
-
const existing = cache.get(key);
|
|
498
|
-
if (existing !== void 0) {
|
|
499
|
-
return existing.then((response) => ({ response, fromCache: true }));
|
|
500
|
-
}
|
|
501
|
-
const pending = fetcher().then(async (response) => {
|
|
502
|
-
const headers = Object.fromEntries(response.headers);
|
|
503
|
-
delete headers["content-encoding"];
|
|
504
|
-
delete headers["content-length"];
|
|
505
|
-
return {
|
|
506
|
-
status: response.status,
|
|
507
|
-
headers,
|
|
508
|
-
body: Buffer.from(await response.arrayBuffer())
|
|
509
|
-
};
|
|
510
|
-
}).catch((error) => {
|
|
511
|
-
cache.delete(key);
|
|
512
|
-
emitChange();
|
|
513
|
-
throw error;
|
|
514
|
-
});
|
|
515
|
-
cache.set(key, pending);
|
|
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
|
-
});
|
|
524
|
-
},
|
|
525
|
-
clear() {
|
|
526
|
-
cache.clear();
|
|
527
|
-
emitChange();
|
|
528
|
-
}
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// src/lib/credentials.ts
|
|
533
|
-
import { mkdir as mkdir2, readFile as readFile3, readdir as readdir2, writeFile as writeFile2 } from "fs/promises";
|
|
534
|
-
import { homedir } from "os";
|
|
535
|
-
import { dirname as dirname2, join as join5 } from "path";
|
|
536
|
-
var ENVIRONMENTS = ["go", "fmo", "staging", "integration", "test1"];
|
|
537
|
-
var GLOBAL_CREDENTIALS_DIR = join5(homedir(), ".kizenappbuilder");
|
|
538
|
-
var GLOBAL_CREDENTIALS_PATH = join5(GLOBAL_CREDENTIALS_DIR, "credentials.json");
|
|
539
|
-
var DEFAULT_PROFILE_NAME = "credentials";
|
|
540
|
-
function isValidEnvironment(value) {
|
|
541
|
-
return ENVIRONMENTS.includes(value);
|
|
542
|
-
}
|
|
543
|
-
function parseCredentials(raw) {
|
|
544
|
-
if (typeof raw !== "object" || raw === null) {
|
|
545
|
-
throw new Error("Credentials must be a JSON object");
|
|
546
|
-
}
|
|
547
|
-
const obj = raw;
|
|
548
|
-
const env = obj.environment;
|
|
549
|
-
return {
|
|
550
|
-
apiKey: typeof obj.apiKey === "string" ? obj.apiKey : "",
|
|
551
|
-
userId: typeof obj.userId === "string" ? obj.userId : "",
|
|
552
|
-
businessId: typeof obj.businessId === "string" ? obj.businessId : "",
|
|
553
|
-
environment: isValidEnvironment(env) ? env : "go"
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
async function loadCredentialsFromFile(filePath) {
|
|
557
|
-
const content = await readFile3(filePath, "utf-8");
|
|
558
|
-
return parseCredentials(JSON.parse(content));
|
|
559
|
-
}
|
|
560
|
-
async function loadGlobalCredentials() {
|
|
561
|
-
try {
|
|
562
|
-
return await loadCredentialsFromFile(GLOBAL_CREDENTIALS_PATH);
|
|
563
|
-
} catch {
|
|
564
|
-
return null;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
async function saveGlobalCredentials(credentials) {
|
|
568
|
-
await mkdir2(dirname2(GLOBAL_CREDENTIALS_PATH), { recursive: true });
|
|
569
|
-
await writeFile2(GLOBAL_CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), "utf-8");
|
|
570
|
-
}
|
|
571
|
-
function getProfilePath(name) {
|
|
572
|
-
return join5(GLOBAL_CREDENTIALS_DIR, `${name}.json`);
|
|
573
|
-
}
|
|
574
|
-
async function listCredentialProfiles() {
|
|
575
|
-
const profiles = [
|
|
576
|
-
{ name: DEFAULT_PROFILE_NAME, path: GLOBAL_CREDENTIALS_PATH, isDefault: true }
|
|
577
|
-
];
|
|
578
|
-
try {
|
|
579
|
-
const entries = await readdir2(GLOBAL_CREDENTIALS_DIR);
|
|
580
|
-
for (const entry of entries) {
|
|
581
|
-
if (!entry.endsWith(".json")) {
|
|
582
|
-
continue;
|
|
583
|
-
}
|
|
584
|
-
const name = entry.slice(0, -5);
|
|
585
|
-
if (name === DEFAULT_PROFILE_NAME) {
|
|
586
|
-
continue;
|
|
1265
|
+
if (args[0]?.type === "string" && String(args[0].value).includes("Chrome Security")) {
|
|
1266
|
+
return;
|
|
587
1267
|
}
|
|
588
|
-
|
|
1268
|
+
const level = type === "warning" ? "warn" : ["log", "warn", "error", "info"].includes(type) ? type : "log";
|
|
1269
|
+
const serialized = await Promise.all(args.map((arg) => serializeArgAsync(c, arg)));
|
|
1270
|
+
opts.broadcast({ type: "console-message", level, args: serialized });
|
|
1271
|
+
})().catch(() => {
|
|
1272
|
+
});
|
|
1273
|
+
});
|
|
1274
|
+
const kill = () => {
|
|
1275
|
+
clearInterval(cookieTimer);
|
|
1276
|
+
try {
|
|
1277
|
+
void c.close();
|
|
1278
|
+
} catch {
|
|
589
1279
|
}
|
|
590
|
-
|
|
591
|
-
}
|
|
592
|
-
return
|
|
593
|
-
}
|
|
594
|
-
async function saveCredentialProfile(name, credentials) {
|
|
595
|
-
if (name === DEFAULT_PROFILE_NAME) {
|
|
596
|
-
await saveGlobalCredentials(credentials);
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
await mkdir2(GLOBAL_CREDENTIALS_DIR, { recursive: true });
|
|
600
|
-
await writeFile2(getProfilePath(name), JSON.stringify(credentials, null, 2), "utf-8");
|
|
601
|
-
}
|
|
602
|
-
async function loadCredentialProfile(name) {
|
|
603
|
-
try {
|
|
604
|
-
return await loadCredentialsFromFile(getProfilePath(name));
|
|
605
|
-
} catch {
|
|
606
|
-
return null;
|
|
607
|
-
}
|
|
1280
|
+
chrome.kill();
|
|
1281
|
+
};
|
|
1282
|
+
return { kill };
|
|
608
1283
|
}
|
|
609
1284
|
|
|
610
|
-
// src/
|
|
611
|
-
import {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
async function saveConfig(outputDir, config) {
|
|
622
|
-
await mkdir3(outputDir, { recursive: true });
|
|
623
|
-
await writeFile3(join6(outputDir, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
1285
|
+
// src/hooks/useLogHistory.ts
|
|
1286
|
+
import { useCallback, useState as useState3 } from "react";
|
|
1287
|
+
function useLogHistory(limit) {
|
|
1288
|
+
const [history, setHistory] = useState3([]);
|
|
1289
|
+
const append = useCallback(
|
|
1290
|
+
(message) => {
|
|
1291
|
+
setHistory((h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-limit));
|
|
1292
|
+
},
|
|
1293
|
+
[limit]
|
|
1294
|
+
);
|
|
1295
|
+
return [history, append];
|
|
624
1296
|
}
|
|
625
1297
|
|
|
626
1298
|
// src/ui/CredentialSetupUI.tsx
|
|
627
|
-
import { useCallback, useEffect as
|
|
628
|
-
import { Box as
|
|
629
|
-
import { jsx as
|
|
1299
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useState as useState4 } from "react";
|
|
1300
|
+
import { Box as Box4, Text as Text5, useInput } from "ink";
|
|
1301
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
630
1302
|
var FIELDS = ["apiKey", "userId", "businessId"];
|
|
631
1303
|
var FIELD_LABELS = {
|
|
632
1304
|
apiKey: "API Key",
|
|
633
1305
|
userId: "User ID",
|
|
634
1306
|
businessId: "Business ID"
|
|
635
1307
|
};
|
|
636
|
-
var Hint = ({ text }) => /* @__PURE__ */
|
|
1308
|
+
var Hint = ({ text }) => /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: text });
|
|
637
1309
|
var CredentialSetupUI = ({
|
|
638
1310
|
initialMode,
|
|
639
1311
|
showProfileManager,
|
|
640
1312
|
onComplete,
|
|
641
1313
|
onCancel
|
|
642
1314
|
}) => {
|
|
643
|
-
const [phase, setPhase] =
|
|
1315
|
+
const [phase, setPhase] = useState4(
|
|
644
1316
|
initialMode === "global" && !showProfileManager ? { type: "loading" } : initialMode === "global" && showProfileManager ? { type: "profile-loading" } : { type: "mode-select", cursor: 0 }
|
|
645
1317
|
);
|
|
646
|
-
const [inputBuffer, setInputBuffer] =
|
|
647
|
-
const [error, setError] =
|
|
648
|
-
const [activeProfileName, setActiveProfileName] =
|
|
649
|
-
const handleModeChosen =
|
|
1318
|
+
const [inputBuffer, setInputBuffer] = useState4("");
|
|
1319
|
+
const [error, setError] = useState4(null);
|
|
1320
|
+
const [activeProfileName, setActiveProfileName] = useState4(void 0);
|
|
1321
|
+
const handleModeChosen = useCallback2(
|
|
650
1322
|
(mode) => {
|
|
651
1323
|
if (mode === "local") {
|
|
652
1324
|
onComplete({ mode: "local", credentials: null });
|
|
@@ -656,7 +1328,7 @@ var CredentialSetupUI = ({
|
|
|
656
1328
|
},
|
|
657
1329
|
[onComplete]
|
|
658
1330
|
);
|
|
659
|
-
const handleProfileChosen =
|
|
1331
|
+
const handleProfileChosen = useCallback2(async (profile) => {
|
|
660
1332
|
if (profile === null) {
|
|
661
1333
|
setPhase({ type: "profile-loading" });
|
|
662
1334
|
const profiles = await listCredentialProfiles();
|
|
@@ -669,7 +1341,7 @@ var CredentialSetupUI = ({
|
|
|
669
1341
|
const envCursor2 = existing ? Math.max(0, ENVIRONMENTS.indexOf(existing.environment)) : 0;
|
|
670
1342
|
setPhase({ type: "creds-entry", field: 0, values: existing ?? {}, envCursor: envCursor2 });
|
|
671
1343
|
}, []);
|
|
672
|
-
const handleSave =
|
|
1344
|
+
const handleSave = useCallback2(
|
|
673
1345
|
async (values2, envCursor2) => {
|
|
674
1346
|
const environment = ENVIRONMENTS[envCursor2] ?? "go";
|
|
675
1347
|
const credentials = {
|
|
@@ -810,16 +1482,16 @@ var CredentialSetupUI = ({
|
|
|
810
1482
|
}
|
|
811
1483
|
}
|
|
812
1484
|
});
|
|
813
|
-
const loadProfileList =
|
|
1485
|
+
const loadProfileList = useCallback2(async () => {
|
|
814
1486
|
const profiles = await listCredentialProfiles();
|
|
815
1487
|
setPhase({ type: "profile-select", profiles, cursor: 0 });
|
|
816
1488
|
}, []);
|
|
817
|
-
|
|
1489
|
+
useEffect3(() => {
|
|
818
1490
|
if (phase.type === "profile-loading") {
|
|
819
1491
|
void loadProfileList();
|
|
820
1492
|
}
|
|
821
1493
|
}, [phase.type, loadProfileList]);
|
|
822
|
-
|
|
1494
|
+
useEffect3(() => {
|
|
823
1495
|
if (initialMode === "global" && !showProfileManager) {
|
|
824
1496
|
void (async () => {
|
|
825
1497
|
const existing = await loadGlobalCredentials();
|
|
@@ -828,14 +1500,14 @@ var CredentialSetupUI = ({
|
|
|
828
1500
|
})();
|
|
829
1501
|
}
|
|
830
1502
|
}, []);
|
|
831
|
-
|
|
1503
|
+
useEffect3(() => {
|
|
832
1504
|
if (phase.type === "creds-entry" && phase.field === 0) {
|
|
833
1505
|
setInputBuffer(phase.values.apiKey ?? "");
|
|
834
1506
|
}
|
|
835
1507
|
}, [phase.type]);
|
|
836
1508
|
if (phase.type === "loading" || phase.type === "saving" || phase.type === "profile-loading") {
|
|
837
1509
|
const label = phase.type === "saving" ? "Saving credentials\u2026" : phase.type === "profile-loading" ? "Loading profiles\u2026" : "Loading credentials\u2026";
|
|
838
|
-
return /* @__PURE__ */
|
|
1510
|
+
return /* @__PURE__ */ jsx5(Box4, { paddingY: 1, paddingX: 2, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: label }) });
|
|
839
1511
|
}
|
|
840
1512
|
if (phase.type === "done") {
|
|
841
1513
|
return null;
|
|
@@ -845,49 +1517,41 @@ var CredentialSetupUI = ({
|
|
|
845
1517
|
{ label: "Global", desc: `~/.kizenappbuilder/credentials.json`, mode: "global" },
|
|
846
1518
|
{ label: "Local", desc: "Enter credentials in the browser dev tools", mode: "local" }
|
|
847
1519
|
];
|
|
848
|
-
return /* @__PURE__ */
|
|
849
|
-
/* @__PURE__ */
|
|
850
|
-
/* @__PURE__ */
|
|
851
|
-
/* @__PURE__ */
|
|
852
|
-
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
853
|
-
] }),
|
|
854
|
-
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
855
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Credential mode" }),
|
|
1520
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
1521
|
+
/* @__PURE__ */ jsx5(AppHeader, {}),
|
|
1522
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 0, children: [
|
|
1523
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: "Credential mode" }),
|
|
856
1524
|
options.map((opt, i) => {
|
|
857
1525
|
const selected = phase.cursor === i;
|
|
858
|
-
return /* @__PURE__ */
|
|
859
|
-
/* @__PURE__ */
|
|
860
|
-
/* @__PURE__ */
|
|
861
|
-
/* @__PURE__ */
|
|
1526
|
+
return /* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1527
|
+
/* @__PURE__ */ jsx5(Text5, { ...selected && { color: "cyan" }, children: selected ? "\u276F" : " " }),
|
|
1528
|
+
/* @__PURE__ */ jsx5(Text5, { bold: selected, ...selected && { color: "cyan" }, children: opt.label }),
|
|
1529
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: opt.desc })
|
|
862
1530
|
] }, opt.mode);
|
|
863
1531
|
})
|
|
864
1532
|
] }),
|
|
865
|
-
/* @__PURE__ */
|
|
1533
|
+
/* @__PURE__ */ jsx5(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit" })
|
|
866
1534
|
] });
|
|
867
1535
|
}
|
|
868
1536
|
if (phase.type === "profile-select") {
|
|
869
1537
|
const { profiles, cursor } = phase;
|
|
870
1538
|
const addNewIdx = profiles.length;
|
|
871
|
-
return /* @__PURE__ */
|
|
872
|
-
/* @__PURE__ */
|
|
873
|
-
/* @__PURE__ */
|
|
874
|
-
/* @__PURE__ */
|
|
875
|
-
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
876
|
-
] }),
|
|
877
|
-
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
878
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "Credential profiles" }),
|
|
1539
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
1540
|
+
/* @__PURE__ */ jsx5(AppHeader, {}),
|
|
1541
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 0, children: [
|
|
1542
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: "Credential profiles" }),
|
|
879
1543
|
profiles.map((profile, i) => {
|
|
880
1544
|
const selected = cursor === i;
|
|
881
|
-
return /* @__PURE__ */
|
|
882
|
-
/* @__PURE__ */
|
|
883
|
-
/* @__PURE__ */
|
|
884
|
-
/* @__PURE__ */
|
|
1545
|
+
return /* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1546
|
+
/* @__PURE__ */ jsx5(Text5, { ...selected && { color: "cyan" }, children: selected ? "\u276F" : " " }),
|
|
1547
|
+
/* @__PURE__ */ jsx5(Text5, { bold: selected, ...selected && { color: "cyan" }, children: profile.isDefault ? "Default" : profile.name }),
|
|
1548
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: profile.path })
|
|
885
1549
|
] }, profile.name);
|
|
886
1550
|
}),
|
|
887
|
-
/* @__PURE__ */
|
|
888
|
-
/* @__PURE__ */
|
|
889
|
-
/* @__PURE__ */
|
|
890
|
-
|
|
1551
|
+
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1552
|
+
/* @__PURE__ */ jsx5(Text5, { ...cursor === addNewIdx && { color: "cyan" }, children: cursor === addNewIdx ? "\u276F" : " " }),
|
|
1553
|
+
/* @__PURE__ */ jsx5(
|
|
1554
|
+
Text5,
|
|
891
1555
|
{
|
|
892
1556
|
bold: cursor === addNewIdx,
|
|
893
1557
|
...cursor === addNewIdx && { color: "cyan" },
|
|
@@ -896,77 +1560,69 @@ var CredentialSetupUI = ({
|
|
|
896
1560
|
)
|
|
897
1561
|
] })
|
|
898
1562
|
] }),
|
|
899
|
-
/* @__PURE__ */
|
|
1563
|
+
/* @__PURE__ */ jsx5(Hint, { text: "\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel" })
|
|
900
1564
|
] });
|
|
901
1565
|
}
|
|
902
1566
|
if (phase.type === "name-entry") {
|
|
903
1567
|
const { nameBuffer, nameError } = phase;
|
|
904
|
-
return /* @__PURE__ */
|
|
905
|
-
/* @__PURE__ */
|
|
906
|
-
/* @__PURE__ */
|
|
907
|
-
|
|
908
|
-
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2500".repeat(24) })
|
|
909
|
-
] }),
|
|
910
|
-
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", gap: 0, children: /* @__PURE__ */ jsx3(Text3, { bold: true, children: "New credential profile" }) }),
|
|
911
|
-
nameError && /* @__PURE__ */ jsxs2(Text3, { color: "red", children: [
|
|
1568
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
1569
|
+
/* @__PURE__ */ jsx5(AppHeader, {}),
|
|
1570
|
+
/* @__PURE__ */ jsx5(Box4, { flexDirection: "column", gap: 0, children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "New credential profile" }) }),
|
|
1571
|
+
nameError && /* @__PURE__ */ jsxs3(Text5, { color: "red", children: [
|
|
912
1572
|
"Error: ",
|
|
913
1573
|
nameError
|
|
914
1574
|
] }),
|
|
915
|
-
/* @__PURE__ */
|
|
916
|
-
/* @__PURE__ */
|
|
917
|
-
/* @__PURE__ */
|
|
918
|
-
/* @__PURE__ */
|
|
919
|
-
/* @__PURE__ */
|
|
1575
|
+
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1576
|
+
/* @__PURE__ */ jsx5(Box4, { width: 12, children: /* @__PURE__ */ jsx5(Text5, { bold: true, color: "cyan", children: "Profile name" }) }),
|
|
1577
|
+
/* @__PURE__ */ jsx5(Text5, { color: "cyan", children: ">" }),
|
|
1578
|
+
/* @__PURE__ */ jsx5(Text5, { children: nameBuffer }),
|
|
1579
|
+
/* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2588" })
|
|
920
1580
|
] }),
|
|
921
|
-
/* @__PURE__ */
|
|
1581
|
+
/* @__PURE__ */ jsx5(Hint, { text: "Type a name \xB7 Enter to confirm \xB7 Esc to go back" })
|
|
922
1582
|
] });
|
|
923
1583
|
}
|
|
924
1584
|
const { field: activeField, values, envCursor } = phase;
|
|
925
1585
|
const isEnvField = activeField === FIELDS.length;
|
|
926
1586
|
const profileLabel = activeProfileName ?? DEFAULT_PROFILE_NAME;
|
|
927
|
-
return /* @__PURE__ */
|
|
928
|
-
/* @__PURE__ */
|
|
929
|
-
/* @__PURE__ */
|
|
930
|
-
/* @__PURE__ */
|
|
931
|
-
/* @__PURE__ */
|
|
932
|
-
] }),
|
|
933
|
-
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", gap: 0, children: [
|
|
934
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children: activeProfileName !== void 0 ? `Profile: ${activeProfileName}` : "Global credentials" }),
|
|
935
|
-
/* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
|
|
1587
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", paddingY: 1, paddingX: 2, gap: 1, children: [
|
|
1588
|
+
/* @__PURE__ */ jsx5(AppHeader, {}),
|
|
1589
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 0, children: [
|
|
1590
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: activeProfileName !== void 0 ? `Profile: ${activeProfileName}` : "Global credentials" }),
|
|
1591
|
+
/* @__PURE__ */ jsxs3(Text5, { dimColor: true, children: [
|
|
936
1592
|
"Saved to:",
|
|
937
1593
|
" ",
|
|
938
1594
|
activeProfileName !== void 0 ? `~/.kizenappbuilder/${activeProfileName}.json` : GLOBAL_CREDENTIALS_PATH
|
|
939
1595
|
] })
|
|
940
1596
|
] }),
|
|
941
|
-
error && /* @__PURE__ */
|
|
1597
|
+
error && /* @__PURE__ */ jsxs3(Text5, { color: "red", children: [
|
|
942
1598
|
"Error: ",
|
|
943
1599
|
error
|
|
944
1600
|
] }),
|
|
945
|
-
/* @__PURE__ */
|
|
1601
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 0, children: [
|
|
946
1602
|
FIELDS.map((name, i) => {
|
|
947
1603
|
const isActive = activeField === i;
|
|
948
1604
|
const displayValue = isActive ? inputBuffer : values[name] ?? "";
|
|
949
|
-
return /* @__PURE__ */
|
|
950
|
-
/* @__PURE__ */
|
|
951
|
-
/* @__PURE__ */
|
|
952
|
-
/* @__PURE__ */
|
|
953
|
-
isActive && /* @__PURE__ */
|
|
1605
|
+
return /* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1606
|
+
/* @__PURE__ */ jsx5(Box4, { width: 12, children: /* @__PURE__ */ jsx5(Text5, { bold: isActive, ...isActive && { color: "cyan" }, children: FIELD_LABELS[name] }) }),
|
|
1607
|
+
/* @__PURE__ */ jsx5(Text5, { ...isActive && { color: "cyan" }, children: ">" }),
|
|
1608
|
+
/* @__PURE__ */ jsx5(Text5, { children: displayValue }),
|
|
1609
|
+
isActive && /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u2588" })
|
|
954
1610
|
] }, name);
|
|
955
1611
|
}),
|
|
956
|
-
/* @__PURE__ */
|
|
957
|
-
/* @__PURE__ */
|
|
958
|
-
/* @__PURE__ */
|
|
959
|
-
/* @__PURE__ */
|
|
1612
|
+
/* @__PURE__ */ jsxs3(Box4, { gap: 2, children: [
|
|
1613
|
+
/* @__PURE__ */ jsx5(Box4, { width: 12, children: /* @__PURE__ */ jsx5(Text5, { bold: isEnvField, ...isEnvField && { color: "cyan" }, children: "Environment" }) }),
|
|
1614
|
+
/* @__PURE__ */ jsx5(Text5, { ...isEnvField && { color: "cyan" }, children: ">" }),
|
|
1615
|
+
/* @__PURE__ */ jsx5(Box4, { gap: 1, children: ENVIRONMENTS.map((env, i) => {
|
|
960
1616
|
const isSelected = i === envCursor;
|
|
961
1617
|
if (isEnvField) {
|
|
962
|
-
return /* @__PURE__ */
|
|
1618
|
+
return /* @__PURE__ */ jsx5(Text5, { bold: isSelected, ...isSelected && { color: "cyan" }, children: isSelected ? `[${env}]` : env }, env);
|
|
963
1619
|
}
|
|
964
|
-
return /* @__PURE__ */
|
|
1620
|
+
return /* @__PURE__ */ jsx5(Text5, { dimColor: !isSelected, bold: isSelected, children: env }, env);
|
|
965
1621
|
}) })
|
|
966
1622
|
] })
|
|
967
1623
|
] }),
|
|
968
|
-
isEnvField ? /* @__PURE__ */
|
|
969
|
-
/* @__PURE__ */
|
|
1624
|
+
isEnvField ? /* @__PURE__ */ jsx5(Hint, { text: "\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel" }) : /* @__PURE__ */ jsx5(Hint, { text: "\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel" }),
|
|
1625
|
+
/* @__PURE__ */ jsxs3(Text5, { dimColor: true, children: [
|
|
970
1626
|
"Profile: ",
|
|
971
1627
|
profileLabel
|
|
972
1628
|
] })
|
|
@@ -974,235 +1630,44 @@ var CredentialSetupUI = ({
|
|
|
974
1630
|
};
|
|
975
1631
|
|
|
976
1632
|
// src/ui/DevUI.tsx
|
|
977
|
-
import { jsx as
|
|
978
|
-
function proxyLogEntryToString(entry) {
|
|
979
|
-
if (entry.kind === "info") {
|
|
980
|
-
return entry.message;
|
|
981
|
-
}
|
|
982
|
-
const cache = entry.fromCache ? " [cache]" : "";
|
|
983
|
-
return `${entry.method} ${entry.url} \u2192 ${String(entry.status)}${cache}`;
|
|
984
|
-
}
|
|
1633
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
985
1634
|
var SKIP_WATCH_PREFIXES = [".kizenapp", ".git"];
|
|
986
|
-
var LOG_LIMIT = 50;
|
|
987
|
-
var LOG_DISPLAY = 8;
|
|
988
|
-
var MIME_TYPES = {
|
|
989
|
-
".html": "text/html; charset=utf-8",
|
|
990
|
-
".js": "application/javascript; charset=utf-8",
|
|
991
|
-
".mjs": "application/javascript; charset=utf-8",
|
|
992
|
-
".css": "text/css; charset=utf-8",
|
|
993
|
-
".png": "image/png",
|
|
994
|
-
".jpg": "image/jpeg",
|
|
995
|
-
".svg": "image/svg+xml",
|
|
996
|
-
".ico": "image/x-icon",
|
|
997
|
-
".json": "application/json; charset=utf-8",
|
|
998
|
-
".woff": "font/woff",
|
|
999
|
-
".woff2": "font/woff2",
|
|
1000
|
-
".ttf": "font/ttf",
|
|
1001
|
-
".map": "application/json"
|
|
1002
|
-
};
|
|
1003
|
-
var SPINNER_FRAMES2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1004
|
-
var Spinner2 = () => {
|
|
1005
|
-
const [frame, setFrame] = useState3(0);
|
|
1006
|
-
useEffect3(() => {
|
|
1007
|
-
const id = setInterval(() => {
|
|
1008
|
-
setFrame((prev) => (prev + 1) % SPINNER_FRAMES2.length);
|
|
1009
|
-
}, 80);
|
|
1010
|
-
return () => {
|
|
1011
|
-
clearInterval(id);
|
|
1012
|
-
};
|
|
1013
|
-
}, []);
|
|
1014
|
-
return /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: SPINNER_FRAMES2[frame] ?? "\u280B" });
|
|
1015
|
-
};
|
|
1016
|
-
function getViewerPath() {
|
|
1017
|
-
const filename = fileURLToPath2(import.meta.url);
|
|
1018
|
-
return join7(dirname3(filename), "viewer");
|
|
1019
|
-
}
|
|
1020
|
-
async function fileExists(filePath) {
|
|
1021
|
-
try {
|
|
1022
|
-
await access(filePath);
|
|
1023
|
-
return true;
|
|
1024
|
-
} catch {
|
|
1025
|
-
return false;
|
|
1026
|
-
}
|
|
1027
|
-
}
|
|
1028
|
-
function createRequestHandler(viewerPath, createServerLog, createProxyLog, credentialsRef, activeProfileRef, outputDir, broadcast, onProxyCacheChange) {
|
|
1029
|
-
const proxyCache = createProxyCache({ onChange: onProxyCacheChange });
|
|
1030
|
-
return (req, res) => {
|
|
1031
|
-
void (async () => {
|
|
1032
|
-
const url = req.url ?? "/";
|
|
1033
|
-
try {
|
|
1034
|
-
createServerLog(`Received request: ${url}`);
|
|
1035
|
-
if (url === "/api/credentials") {
|
|
1036
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1037
|
-
res.end(credentialsRef.current !== null ? JSON.stringify(credentialsRef.current) : "{}");
|
|
1038
|
-
return;
|
|
1039
|
-
}
|
|
1040
|
-
if (url === "/api/credential-profiles" && req.method === "GET") {
|
|
1041
|
-
const profiles = await listCredentialProfiles();
|
|
1042
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1043
|
-
res.end(JSON.stringify({ profiles, active: activeProfileRef.current }));
|
|
1044
|
-
return;
|
|
1045
|
-
}
|
|
1046
|
-
if (url === "/api/credentials/switch" && req.method === "POST") {
|
|
1047
|
-
const chunks = [];
|
|
1048
|
-
for await (const chunk of req) {
|
|
1049
|
-
chunks.push(chunk);
|
|
1050
|
-
}
|
|
1051
|
-
const body = JSON.parse(Buffer.concat(chunks).toString("utf-8") || "{}");
|
|
1052
|
-
const profileName = body.profile;
|
|
1053
|
-
const creds = profileName === void 0 || profileName === "" ? await loadGlobalCredentials() : await loadCredentialProfile(profileName);
|
|
1054
|
-
if (creds !== null) {
|
|
1055
|
-
credentialsRef.current = creds;
|
|
1056
|
-
activeProfileRef.current = profileName ?? void 0;
|
|
1057
|
-
const active = activeProfileRef.current;
|
|
1058
|
-
await saveConfig(outputDir, {
|
|
1059
|
-
credentialMode: "global",
|
|
1060
|
-
...active !== void 0 && { activeCredentialProfile: active }
|
|
1061
|
-
});
|
|
1062
|
-
broadcast({ type: "credentials-updated", credentials: creds });
|
|
1063
|
-
}
|
|
1064
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1065
|
-
res.end(JSON.stringify({ ok: creds !== null }));
|
|
1066
|
-
return;
|
|
1067
|
-
}
|
|
1068
|
-
if (url === "/api/bundle") {
|
|
1069
|
-
const bundlePath = join7(process.cwd(), ".kizenapp", "bundle.json");
|
|
1070
|
-
try {
|
|
1071
|
-
const content = await readFile5(bundlePath, "utf-8");
|
|
1072
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1073
|
-
res.end(content);
|
|
1074
|
-
} catch {
|
|
1075
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1076
|
-
res.end("{}");
|
|
1077
|
-
}
|
|
1078
|
-
return;
|
|
1079
|
-
}
|
|
1080
|
-
if (url === "/api/proxy-cache/clear") {
|
|
1081
|
-
proxyCache.clear();
|
|
1082
|
-
createProxyLog({ kind: "info", message: "Proxy cache cleared" });
|
|
1083
|
-
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
1084
|
-
res.end('{"ok":true}');
|
|
1085
|
-
return;
|
|
1086
|
-
}
|
|
1087
|
-
if (url.startsWith("/api/proxy")) {
|
|
1088
|
-
const proxyTarget = req.headers["x-proxy-target"];
|
|
1089
|
-
if (typeof proxyTarget !== "string") {
|
|
1090
|
-
res.writeHead(400);
|
|
1091
|
-
res.end("Missing x-proxy-target header");
|
|
1092
|
-
return;
|
|
1093
|
-
}
|
|
1094
|
-
const upstreamPath = url.slice("/api/proxy".length) || "/";
|
|
1095
|
-
const upstreamUrl = `${proxyTarget}${upstreamPath}`;
|
|
1096
|
-
const method = req.method ?? "GET";
|
|
1097
|
-
const chunks = [];
|
|
1098
|
-
for await (const chunk of req) {
|
|
1099
|
-
chunks.push(chunk);
|
|
1100
|
-
}
|
|
1101
|
-
const { host, "x-proxy-target": _drop, ...forwardHeaders } = req.headers;
|
|
1102
|
-
if (method === "GET") {
|
|
1103
|
-
const cacheKey = `GET::${upstreamUrl}`;
|
|
1104
|
-
const { response: cached, fromCache } = await proxyCache.get(
|
|
1105
|
-
cacheKey,
|
|
1106
|
-
() => fetch(upstreamUrl, {
|
|
1107
|
-
method: "GET",
|
|
1108
|
-
headers: forwardHeaders
|
|
1109
|
-
})
|
|
1110
|
-
);
|
|
1111
|
-
createProxyLog({
|
|
1112
|
-
kind: "request",
|
|
1113
|
-
method: "GET",
|
|
1114
|
-
status: cached.status,
|
|
1115
|
-
fromCache,
|
|
1116
|
-
url: upstreamPath
|
|
1117
|
-
});
|
|
1118
|
-
res.writeHead(cached.status, cached.headers);
|
|
1119
|
-
res.end(cached.body);
|
|
1120
|
-
return;
|
|
1121
|
-
}
|
|
1122
|
-
const body = chunks.length > 0 ? Buffer.concat(chunks) : void 0;
|
|
1123
|
-
const resolvedBody = body && body.length > 0 ? body : void 0;
|
|
1124
|
-
const upstream = await fetch(upstreamUrl, {
|
|
1125
|
-
method,
|
|
1126
|
-
headers: forwardHeaders,
|
|
1127
|
-
...resolvedBody !== void 0 && { body: resolvedBody }
|
|
1128
|
-
});
|
|
1129
|
-
createProxyLog({
|
|
1130
|
-
kind: "request",
|
|
1131
|
-
method,
|
|
1132
|
-
status: upstream.status,
|
|
1133
|
-
fromCache: false,
|
|
1134
|
-
url: upstreamPath
|
|
1135
|
-
});
|
|
1136
|
-
const responseHeaders = Object.fromEntries(upstream.headers);
|
|
1137
|
-
delete responseHeaders["content-encoding"];
|
|
1138
|
-
delete responseHeaders["content-length"];
|
|
1139
|
-
res.writeHead(upstream.status, responseHeaders);
|
|
1140
|
-
res.end(Buffer.from(await upstream.arrayBuffer()));
|
|
1141
|
-
return;
|
|
1142
|
-
}
|
|
1143
|
-
const rawPath = url === "/" ? "/index.html" : url;
|
|
1144
|
-
const filePath = join7(viewerPath, rawPath);
|
|
1145
|
-
const resolvedPath = await fileExists(filePath) ? filePath : join7(viewerPath, "index.html");
|
|
1146
|
-
const ext = extname(resolvedPath);
|
|
1147
|
-
const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
1148
|
-
res.writeHead(200, { "Content-Type": mimeType });
|
|
1149
|
-
createReadStream(resolvedPath).pipe(res);
|
|
1150
|
-
} catch (err) {
|
|
1151
|
-
if (url.startsWith("/api/proxy")) {
|
|
1152
|
-
createProxyLog({
|
|
1153
|
-
kind: "request",
|
|
1154
|
-
method: req.method ?? "GET",
|
|
1155
|
-
status: 502,
|
|
1156
|
-
fromCache: false,
|
|
1157
|
-
url: url.slice("/api/proxy".length) || "/"
|
|
1158
|
-
});
|
|
1159
|
-
} else {
|
|
1160
|
-
createProxyLog({
|
|
1161
|
-
kind: "info",
|
|
1162
|
-
message: `Error handling ${url}: ${err instanceof Error ? err.message : String(err)}`
|
|
1163
|
-
});
|
|
1164
|
-
}
|
|
1165
|
-
if (!res.headersSent) {
|
|
1166
|
-
res.writeHead(502);
|
|
1167
|
-
res.end("Bad Gateway");
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
})();
|
|
1171
|
-
};
|
|
1172
|
-
}
|
|
1173
1635
|
var DevUI = ({
|
|
1174
1636
|
port,
|
|
1175
1637
|
pluginDir,
|
|
1176
1638
|
outputDir,
|
|
1177
1639
|
credentials: initialCredentials,
|
|
1178
1640
|
credentialMode: initialCredentialMode,
|
|
1179
|
-
activeCredentialProfile: initialActiveProfile
|
|
1641
|
+
activeCredentialProfile: initialActiveProfile,
|
|
1642
|
+
lastPath: initialLastPath
|
|
1180
1643
|
}) => {
|
|
1181
1644
|
const credentialsRef = useRef(initialCredentials);
|
|
1182
1645
|
const activeProfileRef = useRef(initialActiveProfile);
|
|
1183
|
-
const
|
|
1184
|
-
const [
|
|
1646
|
+
const lastPathRef = useRef(initialLastPath);
|
|
1647
|
+
const [credMode, setCredMode] = useState5("main");
|
|
1648
|
+
const [credentialMode, setCredentialMode] = useState5(
|
|
1185
1649
|
initialCredentialMode
|
|
1186
1650
|
);
|
|
1187
|
-
const [status, setStatus] =
|
|
1188
|
-
const [errorMessage, setErrorMessage] =
|
|
1189
|
-
const [serverLogHistory,
|
|
1190
|
-
const [buildLogHistory,
|
|
1191
|
-
const [proxyLogHistory, setProxyLogHistory] =
|
|
1192
|
-
const [buildStatus, setBuildStatus] =
|
|
1193
|
-
const [buildError, setBuildError] =
|
|
1194
|
-
const [lastBuilt, setLastBuilt] =
|
|
1195
|
-
const [
|
|
1196
|
-
const [
|
|
1197
|
-
const [
|
|
1198
|
-
const [
|
|
1651
|
+
const [status, setStatus] = useState5("starting");
|
|
1652
|
+
const [errorMessage, setErrorMessage] = useState5(null);
|
|
1653
|
+
const [serverLogHistory, appendServerLog] = useLogHistory(LOG_LIMIT);
|
|
1654
|
+
const [buildLogHistory, appendBuildLog] = useLogHistory(LOG_LIMIT);
|
|
1655
|
+
const [proxyLogHistory, setProxyLogHistory] = useState5([]);
|
|
1656
|
+
const [buildStatus, setBuildStatus] = useState5("pending");
|
|
1657
|
+
const [buildError, setBuildError] = useState5(null);
|
|
1658
|
+
const [lastBuilt, setLastBuilt] = useState5(null);
|
|
1659
|
+
const [lastBundleSize, setLastBundleSize] = useState5(null);
|
|
1660
|
+
const [wsClientCount, setWsClientCount] = useState5(0);
|
|
1661
|
+
const [proxyCacheSize, setProxyCacheSize] = useState5(0);
|
|
1662
|
+
const [proxyCacheHits, setProxyCacheHits] = useState5(0);
|
|
1663
|
+
const [proxyCacheMisses, setProxyCacheMisses] = useState5(0);
|
|
1199
1664
|
const buildingRef = useRef(false);
|
|
1200
1665
|
const viewerLaunchedRef = useRef(false);
|
|
1201
1666
|
const chromeHandleRef = useRef(null);
|
|
1202
1667
|
const debounceTimerRef = useRef(null);
|
|
1203
1668
|
const wsClientsRef = useRef(/* @__PURE__ */ new Set());
|
|
1204
1669
|
const pendingMessagesRef = useRef([]);
|
|
1205
|
-
const broadcast =
|
|
1670
|
+
const broadcast = useCallback3((msg) => {
|
|
1206
1671
|
const json = JSON.stringify(msg);
|
|
1207
1672
|
if (wsClientsRef.current.size === 0) {
|
|
1208
1673
|
pendingMessagesRef.current = [...pendingMessagesRef.current, json].slice(-LOG_LIMIT);
|
|
@@ -1214,18 +1679,15 @@ var DevUI = ({
|
|
|
1214
1679
|
}
|
|
1215
1680
|
}
|
|
1216
1681
|
}, []);
|
|
1217
|
-
const createServerLog =
|
|
1218
|
-
|
|
1219
|
-
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
1220
|
-
);
|
|
1221
|
-
}, []);
|
|
1222
|
-
const launchChromeViewerCb = useCallback2(() => {
|
|
1682
|
+
const createServerLog = appendServerLog;
|
|
1683
|
+
const launchChromeViewerCb = useCallback3(() => {
|
|
1223
1684
|
chromeHandleRef.current?.kill();
|
|
1224
1685
|
chromeHandleRef.current = null;
|
|
1225
1686
|
void launchChromeViewer({
|
|
1226
1687
|
port,
|
|
1227
|
-
userDataDir:
|
|
1228
|
-
broadcast
|
|
1688
|
+
userDataDir: join9(outputDir, ".chrome"),
|
|
1689
|
+
broadcast,
|
|
1690
|
+
...lastPathRef.current !== void 0 && { path: lastPathRef.current }
|
|
1229
1691
|
}).then((handle) => {
|
|
1230
1692
|
chromeHandleRef.current = handle;
|
|
1231
1693
|
process.on("exit", () => {
|
|
@@ -1247,14 +1709,14 @@ var DevUI = ({
|
|
|
1247
1709
|
},
|
|
1248
1710
|
{ isActive: credMode === "main" }
|
|
1249
1711
|
);
|
|
1250
|
-
|
|
1712
|
+
useEffect4(() => {
|
|
1251
1713
|
if (status !== "running" || viewerLaunchedRef.current) {
|
|
1252
1714
|
return;
|
|
1253
1715
|
}
|
|
1254
1716
|
viewerLaunchedRef.current = true;
|
|
1255
1717
|
launchChromeViewerCb();
|
|
1256
1718
|
}, [status, launchChromeViewerCb]);
|
|
1257
|
-
const handleCredentialsDone =
|
|
1719
|
+
const handleCredentialsDone = useCallback3(
|
|
1258
1720
|
(result) => {
|
|
1259
1721
|
credentialsRef.current = result.credentials;
|
|
1260
1722
|
activeProfileRef.current = result.profileName;
|
|
@@ -1269,7 +1731,7 @@ var DevUI = ({
|
|
|
1269
1731
|
},
|
|
1270
1732
|
[outputDir, broadcast]
|
|
1271
1733
|
);
|
|
1272
|
-
const createProxyLog =
|
|
1734
|
+
const createProxyLog = useCallback3(
|
|
1273
1735
|
(entry) => {
|
|
1274
1736
|
setProxyLogHistory(
|
|
1275
1737
|
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${proxyLogEntryToString(entry)}`].slice(
|
|
@@ -1287,16 +1749,14 @@ var DevUI = ({
|
|
|
1287
1749
|
},
|
|
1288
1750
|
[broadcast]
|
|
1289
1751
|
);
|
|
1290
|
-
const createBuildLog =
|
|
1752
|
+
const createBuildLog = useCallback3(
|
|
1291
1753
|
(message) => {
|
|
1292
|
-
|
|
1293
|
-
(h) => [...h, `${(/* @__PURE__ */ new Date()).toLocaleTimeString()}: ${message}`].slice(-LOG_LIMIT)
|
|
1294
|
-
);
|
|
1754
|
+
appendBuildLog(message);
|
|
1295
1755
|
broadcast({ type: "log", message });
|
|
1296
1756
|
},
|
|
1297
|
-
[broadcast]
|
|
1757
|
+
[appendBuildLog, broadcast]
|
|
1298
1758
|
);
|
|
1299
|
-
const triggerBuild =
|
|
1759
|
+
const triggerBuild = useCallback3(() => {
|
|
1300
1760
|
if (buildingRef.current) {
|
|
1301
1761
|
return;
|
|
1302
1762
|
}
|
|
@@ -1304,10 +1764,11 @@ var DevUI = ({
|
|
|
1304
1764
|
setBuildStatus("building");
|
|
1305
1765
|
setBuildError(null);
|
|
1306
1766
|
createBuildLog("Build started");
|
|
1307
|
-
void runBuild(pluginDir, outputDir).then(() => {
|
|
1308
|
-
createBuildLog(
|
|
1767
|
+
void runBuild(pluginDir, outputDir).then(({ bundleSize }) => {
|
|
1768
|
+
createBuildLog(`Build finished \u2014 bundle: ${formatBytes(bundleSize)}`);
|
|
1309
1769
|
setBuildStatus("done");
|
|
1310
1770
|
setLastBuilt(/* @__PURE__ */ new Date());
|
|
1771
|
+
setLastBundleSize(bundleSize);
|
|
1311
1772
|
createBuildLog("Notifying viewers to reload");
|
|
1312
1773
|
for (const client of wsClientsRef.current) {
|
|
1313
1774
|
if (client.readyState === 1) {
|
|
@@ -1322,7 +1783,7 @@ var DevUI = ({
|
|
|
1322
1783
|
buildingRef.current = false;
|
|
1323
1784
|
});
|
|
1324
1785
|
}, [pluginDir, outputDir, createBuildLog]);
|
|
1325
|
-
|
|
1786
|
+
useEffect4(() => {
|
|
1326
1787
|
triggerBuild();
|
|
1327
1788
|
const watcher = watch(pluginDir, { recursive: true }, (_, filename) => {
|
|
1328
1789
|
if (!filename) {
|
|
@@ -1336,7 +1797,7 @@ var DevUI = ({
|
|
|
1336
1797
|
if (debounceTimerRef.current !== null) {
|
|
1337
1798
|
clearTimeout(debounceTimerRef.current);
|
|
1338
1799
|
}
|
|
1339
|
-
debounceTimerRef.current = setTimeout(triggerBuild,
|
|
1800
|
+
debounceTimerRef.current = setTimeout(triggerBuild, FILE_WATCH_DEBOUNCE_MS);
|
|
1340
1801
|
});
|
|
1341
1802
|
return () => {
|
|
1342
1803
|
watcher.close();
|
|
@@ -1345,9 +1806,9 @@ var DevUI = ({
|
|
|
1345
1806
|
}
|
|
1346
1807
|
};
|
|
1347
1808
|
}, [pluginDir, triggerBuild, createBuildLog]);
|
|
1348
|
-
|
|
1809
|
+
useEffect4(() => {
|
|
1349
1810
|
const viewerPath = getViewerPath();
|
|
1350
|
-
void fileExists(
|
|
1811
|
+
void fileExists(join9(viewerPath, "index.html")).then((viewerBuilt) => {
|
|
1351
1812
|
if (!viewerBuilt) {
|
|
1352
1813
|
setErrorMessage("Viewer not built. Run 'pnpm build:viewer' first.");
|
|
1353
1814
|
setStatus("error");
|
|
@@ -1361,7 +1822,8 @@ var DevUI = ({
|
|
|
1361
1822
|
activeProfileRef,
|
|
1362
1823
|
outputDir,
|
|
1363
1824
|
broadcast,
|
|
1364
|
-
setProxyCacheSize
|
|
1825
|
+
setProxyCacheSize,
|
|
1826
|
+
lastPathRef
|
|
1365
1827
|
);
|
|
1366
1828
|
const server = createServer(handler);
|
|
1367
1829
|
const wss = new WebSocketServer({ server });
|
|
@@ -1395,7 +1857,7 @@ var DevUI = ({
|
|
|
1395
1857
|
});
|
|
1396
1858
|
}, [port, createServerLog, createProxyLog, broadcast, outputDir]);
|
|
1397
1859
|
if (credMode === "editing") {
|
|
1398
|
-
return /* @__PURE__ */
|
|
1860
|
+
return /* @__PURE__ */ jsx6(
|
|
1399
1861
|
CredentialSetupUI,
|
|
1400
1862
|
{
|
|
1401
1863
|
...credentialMode !== void 0 && { initialMode: credentialMode },
|
|
@@ -1409,80 +1871,80 @@ var DevUI = ({
|
|
|
1409
1871
|
}
|
|
1410
1872
|
const elapsedSeconds = lastBuilt !== null ? Math.round((Date.now() - lastBuilt.getTime()) / 1e3) : null;
|
|
1411
1873
|
const elapsedLabel = elapsedSeconds === null ? "" : elapsedSeconds < 5 ? " (just now)" : ` (${String(elapsedSeconds)}s ago)`;
|
|
1412
|
-
return /* @__PURE__ */
|
|
1413
|
-
/* @__PURE__ */
|
|
1414
|
-
/* @__PURE__ */
|
|
1415
|
-
/* @__PURE__ */
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
buildStatus === "pending" && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "waiting\u2026" }),
|
|
1422
|
-
buildStatus === "building" && /* @__PURE__ */ jsxs3(Box4, { gap: 1, children: [
|
|
1423
|
-
/* @__PURE__ */ jsx4(Spinner2, {}),
|
|
1424
|
-
/* @__PURE__ */ jsx4(Text4, { children: "Building plugin package\u2026" })
|
|
1874
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", paddingY: 1, paddingX: 2, children: [
|
|
1875
|
+
/* @__PURE__ */ jsx6(AppHeader, { marginBottom: 1 }),
|
|
1876
|
+
/* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
|
|
1877
|
+
/* @__PURE__ */ jsxs4(Box5, { gap: 2, marginBottom: 0, children: [
|
|
1878
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, dimColor: true, children: "App Build" }),
|
|
1879
|
+
buildStatus === "pending" && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "waiting\u2026" }),
|
|
1880
|
+
buildStatus === "building" && /* @__PURE__ */ jsxs4(Box5, { gap: 1, children: [
|
|
1881
|
+
/* @__PURE__ */ jsx6(Spinner, {}),
|
|
1882
|
+
/* @__PURE__ */ jsx6(Text6, { children: "Building plugin package\u2026" })
|
|
1425
1883
|
] }),
|
|
1426
|
-
buildStatus === "done" && /* @__PURE__ */
|
|
1427
|
-
/* @__PURE__ */
|
|
1428
|
-
lastBuilt !== null && /* @__PURE__ */
|
|
1884
|
+
buildStatus === "done" && /* @__PURE__ */ jsxs4(Box5, { gap: 1, children: [
|
|
1885
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713 Built" }),
|
|
1886
|
+
lastBuilt !== null && /* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1429
1887
|
"at ",
|
|
1430
1888
|
lastBuilt.toLocaleTimeString(),
|
|
1431
1889
|
elapsedLabel
|
|
1890
|
+
] }),
|
|
1891
|
+
lastBundleSize !== null && /* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1892
|
+
"\xB7 bundle: ",
|
|
1893
|
+
formatBytes(lastBundleSize)
|
|
1432
1894
|
] })
|
|
1433
1895
|
] }),
|
|
1434
|
-
buildStatus === "error" && /* @__PURE__ */
|
|
1896
|
+
buildStatus === "error" && /* @__PURE__ */ jsxs4(Text6, { color: "red", children: [
|
|
1435
1897
|
"\u2717 ",
|
|
1436
1898
|
buildError ?? "unknown error"
|
|
1437
1899
|
] })
|
|
1438
1900
|
] }),
|
|
1439
|
-
/* @__PURE__ */
|
|
1440
|
-
|
|
1901
|
+
/* @__PURE__ */ jsx6(
|
|
1902
|
+
Box5,
|
|
1441
1903
|
{
|
|
1442
1904
|
flexDirection: "column",
|
|
1443
1905
|
height: LOG_DISPLAY + 2,
|
|
1444
1906
|
borderStyle: "single",
|
|
1445
1907
|
borderColor: "gray",
|
|
1446
1908
|
overflow: "hidden",
|
|
1447
|
-
children: buildLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */
|
|
1909
|
+
children: buildLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate", children: log }, index))
|
|
1448
1910
|
}
|
|
1449
1911
|
)
|
|
1450
1912
|
] }),
|
|
1451
|
-
/* @__PURE__ */
|
|
1452
|
-
/* @__PURE__ */
|
|
1453
|
-
/* @__PURE__ */
|
|
1454
|
-
status === "starting" && /* @__PURE__ */
|
|
1455
|
-
status === "running" && /* @__PURE__ */
|
|
1456
|
-
/* @__PURE__ */
|
|
1457
|
-
/* @__PURE__ */
|
|
1913
|
+
/* @__PURE__ */ jsxs4(Box5, { marginTop: 1, flexDirection: "column", children: [
|
|
1914
|
+
/* @__PURE__ */ jsxs4(Box5, { gap: 2, children: [
|
|
1915
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, dimColor: true, children: "Web Server" }),
|
|
1916
|
+
status === "starting" && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "starting\u2026" }),
|
|
1917
|
+
status === "running" && /* @__PURE__ */ jsxs4(Box5, { gap: 2, children: [
|
|
1918
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713 Running" }),
|
|
1919
|
+
/* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1458
1920
|
"\u25CF ",
|
|
1459
1921
|
wsClientCount,
|
|
1460
1922
|
" viewer",
|
|
1461
1923
|
wsClientCount !== 1 ? "s" : ""
|
|
1462
1924
|
] })
|
|
1463
1925
|
] }),
|
|
1464
|
-
status === "error" && /* @__PURE__ */
|
|
1926
|
+
status === "error" && /* @__PURE__ */ jsxs4(Text6, { color: "red", children: [
|
|
1465
1927
|
"\u2717 ",
|
|
1466
1928
|
errorMessage ?? "Server error"
|
|
1467
1929
|
] })
|
|
1468
1930
|
] }),
|
|
1469
|
-
/* @__PURE__ */
|
|
1470
|
-
|
|
1931
|
+
/* @__PURE__ */ jsx6(
|
|
1932
|
+
Box5,
|
|
1471
1933
|
{
|
|
1472
1934
|
flexDirection: "column",
|
|
1473
1935
|
height: LOG_DISPLAY + 2,
|
|
1474
1936
|
borderStyle: "single",
|
|
1475
1937
|
borderColor: "gray",
|
|
1476
1938
|
overflow: "hidden",
|
|
1477
|
-
children: serverLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */
|
|
1939
|
+
children: serverLogHistory.slice(-LOG_DISPLAY).map((log, index) => /* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate", children: log }, index))
|
|
1478
1940
|
}
|
|
1479
1941
|
)
|
|
1480
1942
|
] }),
|
|
1481
|
-
/* @__PURE__ */
|
|
1482
|
-
/* @__PURE__ */
|
|
1483
|
-
/* @__PURE__ */
|
|
1484
|
-
/* @__PURE__ */
|
|
1485
|
-
/* @__PURE__ */
|
|
1943
|
+
/* @__PURE__ */ jsxs4(Box5, { marginTop: 1, flexDirection: "column", children: [
|
|
1944
|
+
/* @__PURE__ */ jsxs4(Box5, { gap: 2, children: [
|
|
1945
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, dimColor: true, children: "Network Proxy" }),
|
|
1946
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713 Active" }),
|
|
1947
|
+
/* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1486
1948
|
"\u25CF ",
|
|
1487
1949
|
proxyCacheSize,
|
|
1488
1950
|
" key",
|
|
@@ -1495,26 +1957,26 @@ var DevUI = ({
|
|
|
1495
1957
|
" miss"
|
|
1496
1958
|
] })
|
|
1497
1959
|
] }),
|
|
1498
|
-
/* @__PURE__ */
|
|
1499
|
-
|
|
1960
|
+
/* @__PURE__ */ jsx6(
|
|
1961
|
+
Box5,
|
|
1500
1962
|
{
|
|
1501
1963
|
flexDirection: "column",
|
|
1502
1964
|
height: LOG_DISPLAY + 2,
|
|
1503
1965
|
borderStyle: "single",
|
|
1504
1966
|
borderColor: "gray",
|
|
1505
1967
|
overflow: "hidden",
|
|
1506
|
-
children: proxyLogHistory.length === 0 ? /* @__PURE__ */
|
|
1968
|
+
children: proxyLogHistory.length === 0 ? /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " No requests yet." }) : proxyLogHistory.slice(-LOG_DISPLAY).map((log, i) => /* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate", children: log }, i))
|
|
1507
1969
|
}
|
|
1508
1970
|
)
|
|
1509
1971
|
] }),
|
|
1510
|
-
/* @__PURE__ */
|
|
1511
|
-
/* @__PURE__ */
|
|
1512
|
-
/* @__PURE__ */
|
|
1513
|
-
/* @__PURE__ */
|
|
1514
|
-
/* @__PURE__ */
|
|
1515
|
-
/* @__PURE__ */
|
|
1516
|
-
/* @__PURE__ */
|
|
1517
|
-
/* @__PURE__ */
|
|
1972
|
+
/* @__PURE__ */ jsxs4(Box5, { marginTop: 1, gap: 1, children: [
|
|
1973
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "[" }),
|
|
1974
|
+
/* @__PURE__ */ jsx6(Text6, { children: "q" }),
|
|
1975
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "] quit [" }),
|
|
1976
|
+
/* @__PURE__ */ jsx6(Text6, { children: "c" }),
|
|
1977
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "] credentials [" }),
|
|
1978
|
+
/* @__PURE__ */ jsx6(Text6, { children: "v" }),
|
|
1979
|
+
/* @__PURE__ */ jsxs4(Text6, { dimColor: true, children: [
|
|
1518
1980
|
"] ",
|
|
1519
1981
|
wsClientCount === 0 ? "open viewer" : "relaunch viewer"
|
|
1520
1982
|
] })
|
|
@@ -1549,6 +2011,7 @@ function devCommand(program2) {
|
|
|
1549
2011
|
let credentials = null;
|
|
1550
2012
|
let credentialMode;
|
|
1551
2013
|
let activeCredentialProfile;
|
|
2014
|
+
const { lastPath } = await loadConfig(outputDir);
|
|
1552
2015
|
if (options.credentials) {
|
|
1553
2016
|
credentials = await loadCredentialsFromFile(options.credentials);
|
|
1554
2017
|
} else {
|
|
@@ -1591,7 +2054,8 @@ function devCommand(program2) {
|
|
|
1591
2054
|
outputDir,
|
|
1592
2055
|
credentials,
|
|
1593
2056
|
...credentialMode !== void 0 && { credentialMode },
|
|
1594
|
-
...activeCredentialProfile !== void 0 && { activeCredentialProfile }
|
|
2057
|
+
...activeCredentialProfile !== void 0 && { activeCredentialProfile },
|
|
2058
|
+
...lastPath !== void 0 && { lastPath }
|
|
1595
2059
|
}),
|
|
1596
2060
|
{ exitOnCtrlC: false }
|
|
1597
2061
|
);
|