vibora 0.1.10 → 0.1.11
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/bin/vibora.js +36 -4
- package/dist/assets/index-C7bo3ECQ.css +1 -0
- package/dist/assets/index-QutiQrzr.js +45 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/index.js +677 -246
package/server/index.js
CHANGED
|
@@ -3101,128 +3101,6 @@ var Hono2 = class extends Hono {
|
|
|
3101
3101
|
}
|
|
3102
3102
|
};
|
|
3103
3103
|
|
|
3104
|
-
// node_modules/hono/dist/utils/encode.js
|
|
3105
|
-
var decodeBase64 = (str) => {
|
|
3106
|
-
const binary = atob(str);
|
|
3107
|
-
const bytes = new Uint8Array(new ArrayBuffer(binary.length));
|
|
3108
|
-
const half = binary.length / 2;
|
|
3109
|
-
for (let i = 0, j = binary.length - 1;i <= half; i++, j--) {
|
|
3110
|
-
bytes[i] = binary.charCodeAt(i);
|
|
3111
|
-
bytes[j] = binary.charCodeAt(j);
|
|
3112
|
-
}
|
|
3113
|
-
return bytes;
|
|
3114
|
-
};
|
|
3115
|
-
|
|
3116
|
-
// node_modules/hono/dist/utils/basic-auth.js
|
|
3117
|
-
var CREDENTIALS_REGEXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/;
|
|
3118
|
-
var USER_PASS_REGEXP = /^([^:]*):(.*)$/;
|
|
3119
|
-
var utf8Decoder = new TextDecoder;
|
|
3120
|
-
var auth = (req) => {
|
|
3121
|
-
const match2 = CREDENTIALS_REGEXP.exec(req.headers.get("Authorization") || "");
|
|
3122
|
-
if (!match2) {
|
|
3123
|
-
return;
|
|
3124
|
-
}
|
|
3125
|
-
let userPass = undefined;
|
|
3126
|
-
try {
|
|
3127
|
-
userPass = USER_PASS_REGEXP.exec(utf8Decoder.decode(decodeBase64(match2[1])));
|
|
3128
|
-
} catch {}
|
|
3129
|
-
if (!userPass) {
|
|
3130
|
-
return;
|
|
3131
|
-
}
|
|
3132
|
-
return { username: userPass[1], password: userPass[2] };
|
|
3133
|
-
};
|
|
3134
|
-
|
|
3135
|
-
// node_modules/hono/dist/utils/crypto.js
|
|
3136
|
-
var sha256 = async (data) => {
|
|
3137
|
-
const algorithm = { name: "SHA-256", alias: "sha256" };
|
|
3138
|
-
const hash = await createHash(data, algorithm);
|
|
3139
|
-
return hash;
|
|
3140
|
-
};
|
|
3141
|
-
var createHash = async (data, algorithm) => {
|
|
3142
|
-
let sourceBuffer;
|
|
3143
|
-
if (ArrayBuffer.isView(data) || data instanceof ArrayBuffer) {
|
|
3144
|
-
sourceBuffer = data;
|
|
3145
|
-
} else {
|
|
3146
|
-
if (typeof data === "object") {
|
|
3147
|
-
data = JSON.stringify(data);
|
|
3148
|
-
}
|
|
3149
|
-
sourceBuffer = new TextEncoder().encode(String(data));
|
|
3150
|
-
}
|
|
3151
|
-
if (crypto && crypto.subtle) {
|
|
3152
|
-
const buffer = await crypto.subtle.digest({
|
|
3153
|
-
name: algorithm.name
|
|
3154
|
-
}, sourceBuffer);
|
|
3155
|
-
const hash = Array.prototype.map.call(new Uint8Array(buffer), (x) => ("00" + x.toString(16)).slice(-2)).join("");
|
|
3156
|
-
return hash;
|
|
3157
|
-
}
|
|
3158
|
-
return null;
|
|
3159
|
-
};
|
|
3160
|
-
|
|
3161
|
-
// node_modules/hono/dist/utils/buffer.js
|
|
3162
|
-
var timingSafeEqual = async (a, b, hashFunction) => {
|
|
3163
|
-
if (!hashFunction) {
|
|
3164
|
-
hashFunction = sha256;
|
|
3165
|
-
}
|
|
3166
|
-
const [sa, sb] = await Promise.all([hashFunction(a), hashFunction(b)]);
|
|
3167
|
-
if (!sa || !sb) {
|
|
3168
|
-
return false;
|
|
3169
|
-
}
|
|
3170
|
-
return sa === sb && a === b;
|
|
3171
|
-
};
|
|
3172
|
-
|
|
3173
|
-
// node_modules/hono/dist/middleware/basic-auth/index.js
|
|
3174
|
-
var basicAuth = (options, ...users) => {
|
|
3175
|
-
const usernamePasswordInOptions = "username" in options && "password" in options;
|
|
3176
|
-
const verifyUserInOptions = "verifyUser" in options;
|
|
3177
|
-
if (!(usernamePasswordInOptions || verifyUserInOptions)) {
|
|
3178
|
-
throw new Error('basic auth middleware requires options for "username and password" or "verifyUser"');
|
|
3179
|
-
}
|
|
3180
|
-
if (!options.realm) {
|
|
3181
|
-
options.realm = "Secure Area";
|
|
3182
|
-
}
|
|
3183
|
-
if (!options.invalidUserMessage) {
|
|
3184
|
-
options.invalidUserMessage = "Unauthorized";
|
|
3185
|
-
}
|
|
3186
|
-
if (usernamePasswordInOptions) {
|
|
3187
|
-
users.unshift({ username: options.username, password: options.password });
|
|
3188
|
-
}
|
|
3189
|
-
return async function basicAuth2(ctx, next) {
|
|
3190
|
-
const requestUser = auth(ctx.req.raw);
|
|
3191
|
-
if (requestUser) {
|
|
3192
|
-
if (verifyUserInOptions) {
|
|
3193
|
-
if (await options.verifyUser(requestUser.username, requestUser.password, ctx)) {
|
|
3194
|
-
await next();
|
|
3195
|
-
return;
|
|
3196
|
-
}
|
|
3197
|
-
} else {
|
|
3198
|
-
for (const user of users) {
|
|
3199
|
-
const [usernameEqual, passwordEqual] = await Promise.all([
|
|
3200
|
-
timingSafeEqual(user.username, requestUser.username, options.hashFunction),
|
|
3201
|
-
timingSafeEqual(user.password, requestUser.password, options.hashFunction)
|
|
3202
|
-
]);
|
|
3203
|
-
if (usernameEqual && passwordEqual) {
|
|
3204
|
-
await next();
|
|
3205
|
-
return;
|
|
3206
|
-
}
|
|
3207
|
-
}
|
|
3208
|
-
}
|
|
3209
|
-
}
|
|
3210
|
-
const status = 401;
|
|
3211
|
-
const headers = {
|
|
3212
|
-
"WWW-Authenticate": 'Basic realm="' + options.realm?.replace(/"/g, "\\\"") + '"'
|
|
3213
|
-
};
|
|
3214
|
-
const responseMessage = typeof options.invalidUserMessage === "function" ? await options.invalidUserMessage(ctx) : options.invalidUserMessage;
|
|
3215
|
-
const res = typeof responseMessage === "string" ? new Response(responseMessage, { status, headers }) : new Response(JSON.stringify(responseMessage), {
|
|
3216
|
-
status,
|
|
3217
|
-
headers: {
|
|
3218
|
-
...headers,
|
|
3219
|
-
"content-type": "application/json"
|
|
3220
|
-
}
|
|
3221
|
-
});
|
|
3222
|
-
throw new HTTPException(status, { res });
|
|
3223
|
-
};
|
|
3224
|
-
};
|
|
3225
|
-
|
|
3226
3104
|
// node_modules/hono/dist/middleware/cors/index.js
|
|
3227
3105
|
var cors = (options) => {
|
|
3228
3106
|
const defaults = {
|
|
@@ -3368,10 +3246,263 @@ var logger = (fn = console.log) => {
|
|
|
3368
3246
|
};
|
|
3369
3247
|
};
|
|
3370
3248
|
|
|
3249
|
+
// node_modules/hono/dist/helper/factory/index.js
|
|
3250
|
+
var Factory = class {
|
|
3251
|
+
initApp;
|
|
3252
|
+
#defaultAppOptions;
|
|
3253
|
+
constructor(init) {
|
|
3254
|
+
this.initApp = init?.initApp;
|
|
3255
|
+
this.#defaultAppOptions = init?.defaultAppOptions;
|
|
3256
|
+
}
|
|
3257
|
+
createApp = (options) => {
|
|
3258
|
+
const app = new Hono2(options && this.#defaultAppOptions ? { ...this.#defaultAppOptions, ...options } : options ?? this.#defaultAppOptions);
|
|
3259
|
+
if (this.initApp) {
|
|
3260
|
+
this.initApp(app);
|
|
3261
|
+
}
|
|
3262
|
+
return app;
|
|
3263
|
+
};
|
|
3264
|
+
createMiddleware = (middleware) => middleware;
|
|
3265
|
+
createHandlers = (...handlers) => {
|
|
3266
|
+
return handlers.filter((handler) => handler !== undefined);
|
|
3267
|
+
};
|
|
3268
|
+
};
|
|
3269
|
+
var createMiddleware = (middleware) => middleware;
|
|
3270
|
+
|
|
3271
|
+
// node_modules/hono/dist/utils/cookie.js
|
|
3272
|
+
var algorithm = { name: "HMAC", hash: "SHA-256" };
|
|
3273
|
+
var getCryptoKey = async (secret) => {
|
|
3274
|
+
const secretBuf = typeof secret === "string" ? new TextEncoder().encode(secret) : secret;
|
|
3275
|
+
return await crypto.subtle.importKey("raw", secretBuf, algorithm, false, ["sign", "verify"]);
|
|
3276
|
+
};
|
|
3277
|
+
var makeSignature = async (value, secret) => {
|
|
3278
|
+
const key = await getCryptoKey(secret);
|
|
3279
|
+
const signature = await crypto.subtle.sign(algorithm.name, key, new TextEncoder().encode(value));
|
|
3280
|
+
return btoa(String.fromCharCode(...new Uint8Array(signature)));
|
|
3281
|
+
};
|
|
3282
|
+
var verifySignature = async (base64Signature, value, secret) => {
|
|
3283
|
+
try {
|
|
3284
|
+
const signatureBinStr = atob(base64Signature);
|
|
3285
|
+
const signature = new Uint8Array(signatureBinStr.length);
|
|
3286
|
+
for (let i = 0, len = signatureBinStr.length;i < len; i++) {
|
|
3287
|
+
signature[i] = signatureBinStr.charCodeAt(i);
|
|
3288
|
+
}
|
|
3289
|
+
return await crypto.subtle.verify(algorithm, secret, signature, new TextEncoder().encode(value));
|
|
3290
|
+
} catch {
|
|
3291
|
+
return false;
|
|
3292
|
+
}
|
|
3293
|
+
};
|
|
3294
|
+
var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
|
|
3295
|
+
var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
|
|
3296
|
+
var parse = (cookie, name) => {
|
|
3297
|
+
if (name && cookie.indexOf(name) === -1) {
|
|
3298
|
+
return {};
|
|
3299
|
+
}
|
|
3300
|
+
const pairs = cookie.trim().split(";");
|
|
3301
|
+
const parsedCookie = {};
|
|
3302
|
+
for (let pairStr of pairs) {
|
|
3303
|
+
pairStr = pairStr.trim();
|
|
3304
|
+
const valueStartPos = pairStr.indexOf("=");
|
|
3305
|
+
if (valueStartPos === -1) {
|
|
3306
|
+
continue;
|
|
3307
|
+
}
|
|
3308
|
+
const cookieName = pairStr.substring(0, valueStartPos).trim();
|
|
3309
|
+
if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName)) {
|
|
3310
|
+
continue;
|
|
3311
|
+
}
|
|
3312
|
+
let cookieValue = pairStr.substring(valueStartPos + 1).trim();
|
|
3313
|
+
if (cookieValue.startsWith('"') && cookieValue.endsWith('"')) {
|
|
3314
|
+
cookieValue = cookieValue.slice(1, -1);
|
|
3315
|
+
}
|
|
3316
|
+
if (validCookieValueRegEx.test(cookieValue)) {
|
|
3317
|
+
parsedCookie[cookieName] = cookieValue.indexOf("%") !== -1 ? tryDecode(cookieValue, decodeURIComponent_) : cookieValue;
|
|
3318
|
+
if (name) {
|
|
3319
|
+
break;
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
return parsedCookie;
|
|
3324
|
+
};
|
|
3325
|
+
var parseSigned = async (cookie, secret, name) => {
|
|
3326
|
+
const parsedCookie = {};
|
|
3327
|
+
const secretKey = await getCryptoKey(secret);
|
|
3328
|
+
for (const [key, value] of Object.entries(parse(cookie, name))) {
|
|
3329
|
+
const signatureStartPos = value.lastIndexOf(".");
|
|
3330
|
+
if (signatureStartPos < 1) {
|
|
3331
|
+
continue;
|
|
3332
|
+
}
|
|
3333
|
+
const signedValue = value.substring(0, signatureStartPos);
|
|
3334
|
+
const signature = value.substring(signatureStartPos + 1);
|
|
3335
|
+
if (signature.length !== 44 || !signature.endsWith("=")) {
|
|
3336
|
+
continue;
|
|
3337
|
+
}
|
|
3338
|
+
const isVerified = await verifySignature(signature, signedValue, secretKey);
|
|
3339
|
+
parsedCookie[key] = isVerified ? signedValue : false;
|
|
3340
|
+
}
|
|
3341
|
+
return parsedCookie;
|
|
3342
|
+
};
|
|
3343
|
+
var _serialize = (name, value, opt = {}) => {
|
|
3344
|
+
let cookie = `${name}=${value}`;
|
|
3345
|
+
if (name.startsWith("__Secure-") && !opt.secure) {
|
|
3346
|
+
throw new Error("__Secure- Cookie must have Secure attributes");
|
|
3347
|
+
}
|
|
3348
|
+
if (name.startsWith("__Host-")) {
|
|
3349
|
+
if (!opt.secure) {
|
|
3350
|
+
throw new Error("__Host- Cookie must have Secure attributes");
|
|
3351
|
+
}
|
|
3352
|
+
if (opt.path !== "/") {
|
|
3353
|
+
throw new Error('__Host- Cookie must have Path attributes with "/"');
|
|
3354
|
+
}
|
|
3355
|
+
if (opt.domain) {
|
|
3356
|
+
throw new Error("__Host- Cookie must not have Domain attributes");
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
3359
|
+
if (opt && typeof opt.maxAge === "number" && opt.maxAge >= 0) {
|
|
3360
|
+
if (opt.maxAge > 34560000) {
|
|
3361
|
+
throw new Error("Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.");
|
|
3362
|
+
}
|
|
3363
|
+
cookie += `; Max-Age=${opt.maxAge | 0}`;
|
|
3364
|
+
}
|
|
3365
|
+
if (opt.domain && opt.prefix !== "host") {
|
|
3366
|
+
cookie += `; Domain=${opt.domain}`;
|
|
3367
|
+
}
|
|
3368
|
+
if (opt.path) {
|
|
3369
|
+
cookie += `; Path=${opt.path}`;
|
|
3370
|
+
}
|
|
3371
|
+
if (opt.expires) {
|
|
3372
|
+
if (opt.expires.getTime() - Date.now() > 34560000000) {
|
|
3373
|
+
throw new Error("Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.");
|
|
3374
|
+
}
|
|
3375
|
+
cookie += `; Expires=${opt.expires.toUTCString()}`;
|
|
3376
|
+
}
|
|
3377
|
+
if (opt.httpOnly) {
|
|
3378
|
+
cookie += "; HttpOnly";
|
|
3379
|
+
}
|
|
3380
|
+
if (opt.secure) {
|
|
3381
|
+
cookie += "; Secure";
|
|
3382
|
+
}
|
|
3383
|
+
if (opt.sameSite) {
|
|
3384
|
+
cookie += `; SameSite=${opt.sameSite.charAt(0).toUpperCase() + opt.sameSite.slice(1)}`;
|
|
3385
|
+
}
|
|
3386
|
+
if (opt.priority) {
|
|
3387
|
+
cookie += `; Priority=${opt.priority.charAt(0).toUpperCase() + opt.priority.slice(1)}`;
|
|
3388
|
+
}
|
|
3389
|
+
if (opt.partitioned) {
|
|
3390
|
+
if (!opt.secure) {
|
|
3391
|
+
throw new Error("Partitioned Cookie must have Secure attributes");
|
|
3392
|
+
}
|
|
3393
|
+
cookie += "; Partitioned";
|
|
3394
|
+
}
|
|
3395
|
+
return cookie;
|
|
3396
|
+
};
|
|
3397
|
+
var serialize = (name, value, opt) => {
|
|
3398
|
+
value = encodeURIComponent(value);
|
|
3399
|
+
return _serialize(name, value, opt);
|
|
3400
|
+
};
|
|
3401
|
+
var serializeSigned = async (name, value, secret, opt = {}) => {
|
|
3402
|
+
const signature = await makeSignature(value, secret);
|
|
3403
|
+
value = `${value}.${signature}`;
|
|
3404
|
+
value = encodeURIComponent(value);
|
|
3405
|
+
return _serialize(name, value, opt);
|
|
3406
|
+
};
|
|
3407
|
+
|
|
3408
|
+
// node_modules/hono/dist/helper/cookie/index.js
|
|
3409
|
+
var getCookie = (c, key, prefix) => {
|
|
3410
|
+
const cookie = c.req.raw.headers.get("Cookie");
|
|
3411
|
+
if (typeof key === "string") {
|
|
3412
|
+
if (!cookie) {
|
|
3413
|
+
return;
|
|
3414
|
+
}
|
|
3415
|
+
let finalKey = key;
|
|
3416
|
+
if (prefix === "secure") {
|
|
3417
|
+
finalKey = "__Secure-" + key;
|
|
3418
|
+
} else if (prefix === "host") {
|
|
3419
|
+
finalKey = "__Host-" + key;
|
|
3420
|
+
}
|
|
3421
|
+
const obj2 = parse(cookie, finalKey);
|
|
3422
|
+
return obj2[finalKey];
|
|
3423
|
+
}
|
|
3424
|
+
if (!cookie) {
|
|
3425
|
+
return {};
|
|
3426
|
+
}
|
|
3427
|
+
const obj = parse(cookie);
|
|
3428
|
+
return obj;
|
|
3429
|
+
};
|
|
3430
|
+
var getSignedCookie = async (c, secret, key, prefix) => {
|
|
3431
|
+
const cookie = c.req.raw.headers.get("Cookie");
|
|
3432
|
+
if (typeof key === "string") {
|
|
3433
|
+
if (!cookie) {
|
|
3434
|
+
return;
|
|
3435
|
+
}
|
|
3436
|
+
let finalKey = key;
|
|
3437
|
+
if (prefix === "secure") {
|
|
3438
|
+
finalKey = "__Secure-" + key;
|
|
3439
|
+
} else if (prefix === "host") {
|
|
3440
|
+
finalKey = "__Host-" + key;
|
|
3441
|
+
}
|
|
3442
|
+
const obj2 = await parseSigned(cookie, secret, finalKey);
|
|
3443
|
+
return obj2[finalKey];
|
|
3444
|
+
}
|
|
3445
|
+
if (!cookie) {
|
|
3446
|
+
return {};
|
|
3447
|
+
}
|
|
3448
|
+
const obj = await parseSigned(cookie, secret);
|
|
3449
|
+
return obj;
|
|
3450
|
+
};
|
|
3451
|
+
var generateCookie = (name, value, opt) => {
|
|
3452
|
+
let cookie;
|
|
3453
|
+
if (opt?.prefix === "secure") {
|
|
3454
|
+
cookie = serialize("__Secure-" + name, value, { path: "/", ...opt, secure: true });
|
|
3455
|
+
} else if (opt?.prefix === "host") {
|
|
3456
|
+
cookie = serialize("__Host-" + name, value, {
|
|
3457
|
+
...opt,
|
|
3458
|
+
path: "/",
|
|
3459
|
+
secure: true,
|
|
3460
|
+
domain: undefined
|
|
3461
|
+
});
|
|
3462
|
+
} else {
|
|
3463
|
+
cookie = serialize(name, value, { path: "/", ...opt });
|
|
3464
|
+
}
|
|
3465
|
+
return cookie;
|
|
3466
|
+
};
|
|
3467
|
+
var setCookie = (c, name, value, opt) => {
|
|
3468
|
+
const cookie = generateCookie(name, value, opt);
|
|
3469
|
+
c.header("Set-Cookie", cookie, { append: true });
|
|
3470
|
+
};
|
|
3471
|
+
var generateSignedCookie = async (name, value, secret, opt) => {
|
|
3472
|
+
let cookie;
|
|
3473
|
+
if (opt?.prefix === "secure") {
|
|
3474
|
+
cookie = await serializeSigned("__Secure-" + name, value, secret, {
|
|
3475
|
+
path: "/",
|
|
3476
|
+
...opt,
|
|
3477
|
+
secure: true
|
|
3478
|
+
});
|
|
3479
|
+
} else if (opt?.prefix === "host") {
|
|
3480
|
+
cookie = await serializeSigned("__Host-" + name, value, secret, {
|
|
3481
|
+
...opt,
|
|
3482
|
+
path: "/",
|
|
3483
|
+
secure: true,
|
|
3484
|
+
domain: undefined
|
|
3485
|
+
});
|
|
3486
|
+
} else {
|
|
3487
|
+
cookie = await serializeSigned(name, value, secret, { path: "/", ...opt });
|
|
3488
|
+
}
|
|
3489
|
+
return cookie;
|
|
3490
|
+
};
|
|
3491
|
+
var setSignedCookie = async (c, name, value, secret, opt) => {
|
|
3492
|
+
const cookie = await generateSignedCookie(name, value, secret, opt);
|
|
3493
|
+
c.header("set-cookie", cookie, { append: true });
|
|
3494
|
+
};
|
|
3495
|
+
var deleteCookie = (c, name, opt) => {
|
|
3496
|
+
const deletedCookie = getCookie(c, name, opt?.prefix);
|
|
3497
|
+
setCookie(c, name, "", { ...opt, maxAge: 0 });
|
|
3498
|
+
return deletedCookie;
|
|
3499
|
+
};
|
|
3500
|
+
|
|
3371
3501
|
// server/lib/settings.ts
|
|
3372
3502
|
import * as fs from "fs";
|
|
3373
3503
|
import * as path from "path";
|
|
3374
3504
|
import * as os from "os";
|
|
3505
|
+
import * as crypto3 from "crypto";
|
|
3375
3506
|
var DEFAULT_SETTINGS = {
|
|
3376
3507
|
port: 3333,
|
|
3377
3508
|
defaultGitReposDir: os.homedir(),
|
|
@@ -3477,6 +3608,13 @@ function getSettings() {
|
|
|
3477
3608
|
function getSetting(key) {
|
|
3478
3609
|
return getSettings()[key];
|
|
3479
3610
|
}
|
|
3611
|
+
function getSessionSecret() {
|
|
3612
|
+
const settings = getSettings();
|
|
3613
|
+
if (!settings.basicAuthPassword) {
|
|
3614
|
+
return null;
|
|
3615
|
+
}
|
|
3616
|
+
return crypto3.createHash("sha256").update(settings.basicAuthPassword + "vibora-session").digest("hex");
|
|
3617
|
+
}
|
|
3480
3618
|
function updateSettings(updates) {
|
|
3481
3619
|
ensureViboraDir();
|
|
3482
3620
|
const current = getSettings();
|
|
@@ -3542,6 +3680,44 @@ function updateNotificationSettings(updates) {
|
|
|
3542
3680
|
return updated;
|
|
3543
3681
|
}
|
|
3544
3682
|
|
|
3683
|
+
// server/middleware/auth.ts
|
|
3684
|
+
var SESSION_COOKIE_NAME = "vibora_session";
|
|
3685
|
+
var PUBLIC_PATHS = ["/health", "/api/auth/login", "/api/auth/check"];
|
|
3686
|
+
var sessionAuthMiddleware = createMiddleware(async (c, next) => {
|
|
3687
|
+
const settings = getSettings();
|
|
3688
|
+
if (!settings.basicAuthUsername || !settings.basicAuthPassword) {
|
|
3689
|
+
return next();
|
|
3690
|
+
}
|
|
3691
|
+
const path2 = c.req.path;
|
|
3692
|
+
if (PUBLIC_PATHS.some((p) => path2 === p || path2.startsWith(p + "/"))) {
|
|
3693
|
+
return next();
|
|
3694
|
+
}
|
|
3695
|
+
const secret = getSessionSecret();
|
|
3696
|
+
if (secret) {
|
|
3697
|
+
const sessionCookie = await getSignedCookie(c, secret, SESSION_COOKIE_NAME);
|
|
3698
|
+
if (sessionCookie) {
|
|
3699
|
+
try {
|
|
3700
|
+
const session = JSON.parse(sessionCookie);
|
|
3701
|
+
if (session.exp && session.exp > Date.now()) {
|
|
3702
|
+
return next();
|
|
3703
|
+
}
|
|
3704
|
+
} catch {}
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
const authHeader = c.req.header("Authorization");
|
|
3708
|
+
if (authHeader?.startsWith("Basic ")) {
|
|
3709
|
+
const base64Credentials = authHeader.slice(6);
|
|
3710
|
+
try {
|
|
3711
|
+
const credentials = atob(base64Credentials);
|
|
3712
|
+
const [username, password] = credentials.split(":");
|
|
3713
|
+
if (username === settings.basicAuthUsername && password === settings.basicAuthPassword) {
|
|
3714
|
+
return next();
|
|
3715
|
+
}
|
|
3716
|
+
} catch {}
|
|
3717
|
+
}
|
|
3718
|
+
throw new HTTPException(401, { message: "Unauthorized" });
|
|
3719
|
+
});
|
|
3720
|
+
|
|
3545
3721
|
// server/app.ts
|
|
3546
3722
|
import { readFile } from "fs/promises";
|
|
3547
3723
|
import { join as join11 } from "path";
|
|
@@ -7439,7 +7615,7 @@ function drizzle(...params) {
|
|
|
7439
7615
|
})(drizzle || (drizzle = {}));
|
|
7440
7616
|
|
|
7441
7617
|
// node_modules/drizzle-orm/migrator.js
|
|
7442
|
-
import
|
|
7618
|
+
import crypto4 from "crypto";
|
|
7443
7619
|
import fs2 from "fs";
|
|
7444
7620
|
function readMigrationFiles(config) {
|
|
7445
7621
|
const migrationFolderTo = config.migrationsFolder;
|
|
@@ -7461,7 +7637,7 @@ function readMigrationFiles(config) {
|
|
|
7461
7637
|
sql: result,
|
|
7462
7638
|
bps: journalEntry.breakpoints,
|
|
7463
7639
|
folderMillis: journalEntry.when,
|
|
7464
|
-
hash:
|
|
7640
|
+
hash: crypto4.createHash("sha256").update(query).digest("hex")
|
|
7465
7641
|
});
|
|
7466
7642
|
} catch {
|
|
7467
7643
|
throw new Error(`No file ${migrationPath} found in ${migrationFolderTo} folder`);
|
|
@@ -138191,6 +138367,37 @@ app3.post("/merge-to-main", async (c) => {
|
|
|
138191
138367
|
error: "Failed to determine worktree branch"
|
|
138192
138368
|
}, 500);
|
|
138193
138369
|
}
|
|
138370
|
+
try {
|
|
138371
|
+
const worktreeStatus = gitExec(worktreePath, "status --porcelain");
|
|
138372
|
+
if (worktreeStatus.trim()) {
|
|
138373
|
+
const lines = worktreeStatus.trim().split(`
|
|
138374
|
+
`).filter((l) => l);
|
|
138375
|
+
const untracked = [];
|
|
138376
|
+
const uncommitted = [];
|
|
138377
|
+
for (const line of lines) {
|
|
138378
|
+
const statusCode = line.substring(0, 2);
|
|
138379
|
+
const filename = line.substring(3);
|
|
138380
|
+
if (statusCode === "??") {
|
|
138381
|
+
untracked.push(filename);
|
|
138382
|
+
} else {
|
|
138383
|
+
uncommitted.push(filename);
|
|
138384
|
+
}
|
|
138385
|
+
}
|
|
138386
|
+
const messages = [];
|
|
138387
|
+
if (uncommitted.length > 0) {
|
|
138388
|
+
messages.push(`${uncommitted.length} uncommitted change(s)`);
|
|
138389
|
+
}
|
|
138390
|
+
if (untracked.length > 0) {
|
|
138391
|
+
messages.push(`${untracked.length} untracked file(s)`);
|
|
138392
|
+
}
|
|
138393
|
+
return c.json({
|
|
138394
|
+
error: `Worktree has ${messages.join(" and ")}. Please commit or stash changes before merging.`,
|
|
138395
|
+
hasUncommittedChanges: true,
|
|
138396
|
+
uncommittedFiles: uncommitted,
|
|
138397
|
+
untrackedFiles: untracked
|
|
138398
|
+
}, 409);
|
|
138399
|
+
}
|
|
138400
|
+
} catch {}
|
|
138194
138401
|
const defaultBranch = getDefaultBranch(repoPath, baseBranch);
|
|
138195
138402
|
let originalBranch;
|
|
138196
138403
|
try {
|
|
@@ -138785,8 +138992,145 @@ app6.post("/", async (c) => {
|
|
|
138785
138992
|
});
|
|
138786
138993
|
var uploads_default = app6;
|
|
138787
138994
|
|
|
138995
|
+
// node_modules/hono/dist/utils/stream.js
|
|
138996
|
+
var StreamingApi = class {
|
|
138997
|
+
writer;
|
|
138998
|
+
encoder;
|
|
138999
|
+
writable;
|
|
139000
|
+
abortSubscribers = [];
|
|
139001
|
+
responseReadable;
|
|
139002
|
+
aborted = false;
|
|
139003
|
+
closed = false;
|
|
139004
|
+
constructor(writable, _readable) {
|
|
139005
|
+
this.writable = writable;
|
|
139006
|
+
this.writer = writable.getWriter();
|
|
139007
|
+
this.encoder = new TextEncoder;
|
|
139008
|
+
const reader = _readable.getReader();
|
|
139009
|
+
this.abortSubscribers.push(async () => {
|
|
139010
|
+
await reader.cancel();
|
|
139011
|
+
});
|
|
139012
|
+
this.responseReadable = new ReadableStream({
|
|
139013
|
+
async pull(controller) {
|
|
139014
|
+
const { done, value } = await reader.read();
|
|
139015
|
+
done ? controller.close() : controller.enqueue(value);
|
|
139016
|
+
},
|
|
139017
|
+
cancel: () => {
|
|
139018
|
+
this.abort();
|
|
139019
|
+
}
|
|
139020
|
+
});
|
|
139021
|
+
}
|
|
139022
|
+
async write(input) {
|
|
139023
|
+
try {
|
|
139024
|
+
if (typeof input === "string") {
|
|
139025
|
+
input = this.encoder.encode(input);
|
|
139026
|
+
}
|
|
139027
|
+
await this.writer.write(input);
|
|
139028
|
+
} catch {}
|
|
139029
|
+
return this;
|
|
139030
|
+
}
|
|
139031
|
+
async writeln(input) {
|
|
139032
|
+
await this.write(input + `
|
|
139033
|
+
`);
|
|
139034
|
+
return this;
|
|
139035
|
+
}
|
|
139036
|
+
sleep(ms) {
|
|
139037
|
+
return new Promise((res) => setTimeout(res, ms));
|
|
139038
|
+
}
|
|
139039
|
+
async close() {
|
|
139040
|
+
try {
|
|
139041
|
+
await this.writer.close();
|
|
139042
|
+
} catch {}
|
|
139043
|
+
this.closed = true;
|
|
139044
|
+
}
|
|
139045
|
+
async pipe(body) {
|
|
139046
|
+
this.writer.releaseLock();
|
|
139047
|
+
await body.pipeTo(this.writable, { preventClose: true });
|
|
139048
|
+
this.writer = this.writable.getWriter();
|
|
139049
|
+
}
|
|
139050
|
+
onAbort(listener) {
|
|
139051
|
+
this.abortSubscribers.push(listener);
|
|
139052
|
+
}
|
|
139053
|
+
abort() {
|
|
139054
|
+
if (!this.aborted) {
|
|
139055
|
+
this.aborted = true;
|
|
139056
|
+
this.abortSubscribers.forEach((subscriber) => subscriber());
|
|
139057
|
+
}
|
|
139058
|
+
}
|
|
139059
|
+
};
|
|
139060
|
+
|
|
139061
|
+
// node_modules/hono/dist/helper/streaming/utils.js
|
|
139062
|
+
var isOldBunVersion = () => {
|
|
139063
|
+
const version2 = typeof Bun !== "undefined" ? Bun.version : undefined;
|
|
139064
|
+
if (version2 === undefined) {
|
|
139065
|
+
return false;
|
|
139066
|
+
}
|
|
139067
|
+
const result = version2.startsWith("1.1") || version2.startsWith("1.0") || version2.startsWith("0.");
|
|
139068
|
+
isOldBunVersion = () => result;
|
|
139069
|
+
return result;
|
|
139070
|
+
};
|
|
139071
|
+
|
|
139072
|
+
// node_modules/hono/dist/helper/streaming/sse.js
|
|
139073
|
+
var SSEStreamingApi = class extends StreamingApi {
|
|
139074
|
+
constructor(writable, readable) {
|
|
139075
|
+
super(writable, readable);
|
|
139076
|
+
}
|
|
139077
|
+
async writeSSE(message) {
|
|
139078
|
+
const data = await resolveCallback(message.data, HtmlEscapedCallbackPhase.Stringify, false, {});
|
|
139079
|
+
const dataLines = data.split(`
|
|
139080
|
+
`).map((line) => {
|
|
139081
|
+
return `data: ${line}`;
|
|
139082
|
+
}).join(`
|
|
139083
|
+
`);
|
|
139084
|
+
const sseData = [
|
|
139085
|
+
message.event && `event: ${message.event}`,
|
|
139086
|
+
dataLines,
|
|
139087
|
+
message.id && `id: ${message.id}`,
|
|
139088
|
+
message.retry && `retry: ${message.retry}`
|
|
139089
|
+
].filter(Boolean).join(`
|
|
139090
|
+
`) + `
|
|
139091
|
+
|
|
139092
|
+
`;
|
|
139093
|
+
await this.write(sseData);
|
|
139094
|
+
}
|
|
139095
|
+
};
|
|
139096
|
+
var run = async (stream2, cb, onError) => {
|
|
139097
|
+
try {
|
|
139098
|
+
await cb(stream2);
|
|
139099
|
+
} catch (e) {
|
|
139100
|
+
if (e instanceof Error && onError) {
|
|
139101
|
+
await onError(e, stream2);
|
|
139102
|
+
await stream2.writeSSE({
|
|
139103
|
+
event: "error",
|
|
139104
|
+
data: e.message
|
|
139105
|
+
});
|
|
139106
|
+
} else {
|
|
139107
|
+
console.error(e);
|
|
139108
|
+
}
|
|
139109
|
+
} finally {
|
|
139110
|
+
stream2.close();
|
|
139111
|
+
}
|
|
139112
|
+
};
|
|
139113
|
+
var contextStash = /* @__PURE__ */ new WeakMap;
|
|
139114
|
+
var streamSSE = (c, cb, onError) => {
|
|
139115
|
+
const { readable, writable } = new TransformStream;
|
|
139116
|
+
const stream2 = new SSEStreamingApi(writable, readable);
|
|
139117
|
+
if (isOldBunVersion()) {
|
|
139118
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
139119
|
+
if (!stream2.closed) {
|
|
139120
|
+
stream2.abort();
|
|
139121
|
+
}
|
|
139122
|
+
});
|
|
139123
|
+
}
|
|
139124
|
+
contextStash.set(stream2.responseReadable, c);
|
|
139125
|
+
c.header("Transfer-Encoding", "chunked");
|
|
139126
|
+
c.header("Content-Type", "text/event-stream");
|
|
139127
|
+
c.header("Cache-Control", "no-cache");
|
|
139128
|
+
c.header("Connection", "keep-alive");
|
|
139129
|
+
run(stream2, cb, onError);
|
|
139130
|
+
return c.newResponse(stream2.responseReadable);
|
|
139131
|
+
};
|
|
139132
|
+
|
|
138788
139133
|
// server/routes/worktrees.ts
|
|
138789
|
-
import { execSync as execSync4 } from "child_process";
|
|
138790
139134
|
import * as fs6 from "fs";
|
|
138791
139135
|
import * as path8 from "path";
|
|
138792
139136
|
function formatBytes(bytes) {
|
|
@@ -138797,28 +139141,27 @@ function formatBytes(bytes) {
|
|
|
138797
139141
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
138798
139142
|
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
138799
139143
|
}
|
|
138800
|
-
function
|
|
139144
|
+
async function getDirectorySizeAsync(dirPath) {
|
|
138801
139145
|
try {
|
|
138802
139146
|
const platform = process.platform;
|
|
138803
|
-
|
|
138804
|
-
|
|
138805
|
-
|
|
138806
|
-
|
|
138807
|
-
|
|
138808
|
-
const output = execSync4(`du -sb "${dirPath}" 2>/dev/null`, { encoding: "utf-8" });
|
|
138809
|
-
return parseInt(output.split("\t")[0], 10);
|
|
138810
|
-
}
|
|
139147
|
+
const cmd = platform === "darwin" ? ["du", "-sk", dirPath] : ["du", "-sb", dirPath];
|
|
139148
|
+
const proc2 = Bun.spawn(cmd, { stdout: "pipe", stderr: "pipe" });
|
|
139149
|
+
const output = await new Response(proc2.stdout).text();
|
|
139150
|
+
const sizeValue = parseInt(output.split("\t")[0], 10);
|
|
139151
|
+
return platform === "darwin" ? sizeValue * 1024 : sizeValue;
|
|
138811
139152
|
} catch {
|
|
138812
139153
|
return 0;
|
|
138813
139154
|
}
|
|
138814
139155
|
}
|
|
138815
|
-
function
|
|
139156
|
+
async function getGitBranchAsync(gitPath) {
|
|
138816
139157
|
try {
|
|
138817
|
-
const
|
|
139158
|
+
const proc2 = Bun.spawn(["git", "rev-parse", "--abbrev-ref", "HEAD"], {
|
|
138818
139159
|
cwd: gitPath,
|
|
138819
|
-
|
|
138820
|
-
|
|
138821
|
-
|
|
139160
|
+
stdout: "pipe",
|
|
139161
|
+
stderr: "pipe"
|
|
139162
|
+
});
|
|
139163
|
+
const output = await new Response(proc2.stdout).text();
|
|
139164
|
+
return output.trim() || "unknown";
|
|
138822
139165
|
} catch {
|
|
138823
139166
|
return "unknown";
|
|
138824
139167
|
}
|
|
@@ -138834,91 +139177,131 @@ function destroyTerminalsForWorktree2(worktreePath) {
|
|
|
138834
139177
|
}
|
|
138835
139178
|
} catch {}
|
|
138836
139179
|
}
|
|
138837
|
-
function deleteWorktree(worktreePath, repoPath) {
|
|
139180
|
+
async function deleteWorktree(worktreePath, repoPath) {
|
|
138838
139181
|
if (!fs6.existsSync(worktreePath))
|
|
138839
139182
|
return;
|
|
138840
139183
|
if (repoPath && fs6.existsSync(repoPath)) {
|
|
138841
139184
|
try {
|
|
138842
|
-
|
|
139185
|
+
const proc2 = Bun.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
138843
139186
|
cwd: repoPath,
|
|
138844
|
-
|
|
139187
|
+
stdout: "pipe",
|
|
139188
|
+
stderr: "pipe"
|
|
138845
139189
|
});
|
|
138846
|
-
|
|
139190
|
+
await proc2.exited;
|
|
139191
|
+
if (proc2.exitCode === 0)
|
|
139192
|
+
return;
|
|
138847
139193
|
} catch {}
|
|
138848
139194
|
}
|
|
138849
139195
|
fs6.rmSync(worktreePath, { recursive: true, force: true });
|
|
138850
139196
|
if (repoPath && fs6.existsSync(repoPath)) {
|
|
138851
139197
|
try {
|
|
138852
|
-
|
|
139198
|
+
Bun.spawn(["git", "worktree", "prune"], { cwd: repoPath });
|
|
138853
139199
|
} catch {}
|
|
138854
139200
|
}
|
|
138855
139201
|
}
|
|
138856
139202
|
var app7 = new Hono2;
|
|
138857
139203
|
app7.get("/", (c) => {
|
|
138858
|
-
|
|
138859
|
-
|
|
138860
|
-
|
|
138861
|
-
|
|
138862
|
-
|
|
138863
|
-
|
|
138864
|
-
|
|
138865
|
-
|
|
138866
|
-
|
|
139204
|
+
return streamSSE(c, async (stream3) => {
|
|
139205
|
+
const worktreeBasePath = getWorktreeBasePath();
|
|
139206
|
+
if (!fs6.existsSync(worktreeBasePath)) {
|
|
139207
|
+
await stream3.writeSSE({
|
|
139208
|
+
event: "worktree:basic",
|
|
139209
|
+
data: JSON.stringify([])
|
|
139210
|
+
});
|
|
139211
|
+
await stream3.writeSSE({
|
|
139212
|
+
event: "worktree:complete",
|
|
139213
|
+
data: JSON.stringify({
|
|
139214
|
+
total: 0,
|
|
139215
|
+
orphaned: 0,
|
|
139216
|
+
totalSize: 0,
|
|
139217
|
+
totalSizeFormatted: "0 B"
|
|
139218
|
+
})
|
|
139219
|
+
});
|
|
139220
|
+
return;
|
|
139221
|
+
}
|
|
139222
|
+
const allTasks = db.select().from(tasks).all();
|
|
139223
|
+
const worktreeToTask = new Map;
|
|
139224
|
+
for (const task of allTasks) {
|
|
139225
|
+
if (task.worktreePath) {
|
|
139226
|
+
worktreeToTask.set(task.worktreePath, task);
|
|
138867
139227
|
}
|
|
138868
|
-
};
|
|
138869
|
-
return c.json(response2);
|
|
138870
|
-
}
|
|
138871
|
-
const allTasks = db.select().from(tasks).all();
|
|
138872
|
-
const worktreeToTask = new Map;
|
|
138873
|
-
for (const task of allTasks) {
|
|
138874
|
-
if (task.worktreePath) {
|
|
138875
|
-
worktreeToTask.set(task.worktreePath, task);
|
|
138876
139228
|
}
|
|
138877
|
-
|
|
138878
|
-
|
|
138879
|
-
|
|
138880
|
-
|
|
138881
|
-
|
|
138882
|
-
|
|
138883
|
-
|
|
138884
|
-
|
|
138885
|
-
|
|
138886
|
-
|
|
138887
|
-
|
|
138888
|
-
|
|
138889
|
-
|
|
138890
|
-
|
|
138891
|
-
|
|
138892
|
-
|
|
138893
|
-
|
|
138894
|
-
|
|
138895
|
-
|
|
138896
|
-
|
|
138897
|
-
|
|
138898
|
-
|
|
138899
|
-
|
|
138900
|
-
|
|
138901
|
-
|
|
139229
|
+
const entries = fs6.readdirSync(worktreeBasePath, { withFileTypes: true });
|
|
139230
|
+
const basicWorktrees = [];
|
|
139231
|
+
const pathsToProcess = [];
|
|
139232
|
+
for (const entry of entries) {
|
|
139233
|
+
if (!entry.isDirectory())
|
|
139234
|
+
continue;
|
|
139235
|
+
const fullPath = path8.join(worktreeBasePath, entry.name);
|
|
139236
|
+
const gitPath = path8.join(fullPath, ".git");
|
|
139237
|
+
if (!fs6.existsSync(gitPath))
|
|
139238
|
+
continue;
|
|
139239
|
+
const stats = fs6.statSync(fullPath);
|
|
139240
|
+
const linkedTask = worktreeToTask.get(fullPath);
|
|
139241
|
+
basicWorktrees.push({
|
|
139242
|
+
path: fullPath,
|
|
139243
|
+
name: entry.name,
|
|
139244
|
+
lastModified: stats.mtime.toISOString(),
|
|
139245
|
+
isOrphaned: !linkedTask,
|
|
139246
|
+
taskId: linkedTask?.id,
|
|
139247
|
+
taskTitle: linkedTask?.title,
|
|
139248
|
+
taskStatus: linkedTask?.status,
|
|
139249
|
+
repoPath: linkedTask?.repoPath
|
|
139250
|
+
});
|
|
139251
|
+
pathsToProcess.push(fullPath);
|
|
139252
|
+
}
|
|
139253
|
+
basicWorktrees.sort((a, b) => {
|
|
139254
|
+
if (a.isOrphaned !== b.isOrphaned) {
|
|
139255
|
+
return a.isOrphaned ? -1 : 1;
|
|
139256
|
+
}
|
|
139257
|
+
return new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime();
|
|
138902
139258
|
});
|
|
138903
|
-
|
|
138904
|
-
|
|
138905
|
-
|
|
138906
|
-
|
|
139259
|
+
await stream3.writeSSE({
|
|
139260
|
+
event: "worktree:basic",
|
|
139261
|
+
data: JSON.stringify(basicWorktrees)
|
|
139262
|
+
});
|
|
139263
|
+
let totalSize = 0;
|
|
139264
|
+
const CONCURRENCY = 4;
|
|
139265
|
+
async function processWorktree(fullPath) {
|
|
139266
|
+
try {
|
|
139267
|
+
const [size, branch] = await Promise.all([
|
|
139268
|
+
getDirectorySizeAsync(fullPath),
|
|
139269
|
+
getGitBranchAsync(fullPath)
|
|
139270
|
+
]);
|
|
139271
|
+
totalSize += size;
|
|
139272
|
+
await stream3.writeSSE({
|
|
139273
|
+
event: "worktree:details",
|
|
139274
|
+
data: JSON.stringify({
|
|
139275
|
+
path: fullPath,
|
|
139276
|
+
size,
|
|
139277
|
+
sizeFormatted: formatBytes(size),
|
|
139278
|
+
branch
|
|
139279
|
+
})
|
|
139280
|
+
});
|
|
139281
|
+
} catch (error) {
|
|
139282
|
+
await stream3.writeSSE({
|
|
139283
|
+
event: "worktree:error",
|
|
139284
|
+
data: JSON.stringify({
|
|
139285
|
+
path: fullPath,
|
|
139286
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
139287
|
+
})
|
|
139288
|
+
});
|
|
139289
|
+
}
|
|
138907
139290
|
}
|
|
138908
|
-
|
|
138909
|
-
|
|
138910
|
-
|
|
138911
|
-
const orphanedCount = worktrees.filter((w) => w.isOrphaned).length;
|
|
138912
|
-
const response = {
|
|
138913
|
-
worktrees,
|
|
138914
|
-
summary: {
|
|
138915
|
-
total: worktrees.length,
|
|
138916
|
-
orphaned: orphanedCount,
|
|
138917
|
-
totalSize,
|
|
138918
|
-
totalSizeFormatted: formatBytes(totalSize)
|
|
139291
|
+
for (let i = 0;i < pathsToProcess.length; i += CONCURRENCY) {
|
|
139292
|
+
const batch = pathsToProcess.slice(i, i + CONCURRENCY);
|
|
139293
|
+
await Promise.all(batch.map(processWorktree));
|
|
138919
139294
|
}
|
|
138920
|
-
|
|
138921
|
-
|
|
139295
|
+
await stream3.writeSSE({
|
|
139296
|
+
event: "worktree:complete",
|
|
139297
|
+
data: JSON.stringify({
|
|
139298
|
+
total: basicWorktrees.length,
|
|
139299
|
+
orphaned: basicWorktrees.filter((w) => w.isOrphaned).length,
|
|
139300
|
+
totalSize,
|
|
139301
|
+
totalSizeFormatted: formatBytes(totalSize)
|
|
139302
|
+
})
|
|
139303
|
+
});
|
|
139304
|
+
});
|
|
138922
139305
|
});
|
|
138923
139306
|
app7.delete("/", async (c) => {
|
|
138924
139307
|
try {
|
|
@@ -138936,7 +139319,7 @@ app7.delete("/", async (c) => {
|
|
|
138936
139319
|
}
|
|
138937
139320
|
const linkedTask = db.select().from(tasks).where(eq(tasks.worktreePath, body.worktreePath)).get();
|
|
138938
139321
|
destroyTerminalsForWorktree2(body.worktreePath);
|
|
138939
|
-
deleteWorktree(body.worktreePath, body.repoPath || linkedTask?.repoPath);
|
|
139322
|
+
await deleteWorktree(body.worktreePath, body.repoPath || linkedTask?.repoPath);
|
|
138940
139323
|
let deletedTaskId;
|
|
138941
139324
|
if (linkedTask) {
|
|
138942
139325
|
const columnTasks = db.select().from(tasks).where(eq(tasks.status, linkedTask.status)).all();
|
|
@@ -139446,7 +139829,7 @@ function expand2(template, context) {
|
|
|
139446
139829
|
return template.replace(/\/$/, "");
|
|
139447
139830
|
}
|
|
139448
139831
|
}
|
|
139449
|
-
function
|
|
139832
|
+
function parse2(options) {
|
|
139450
139833
|
let method = options.method.toUpperCase();
|
|
139451
139834
|
let url = (options.url || "/").replace(/:([a-z]\w+)/g, "{$1}");
|
|
139452
139835
|
let headers = Object.assign({}, options.headers);
|
|
@@ -139501,7 +139884,7 @@ function parse(options) {
|
|
|
139501
139884
|
return Object.assign({ method, url, headers }, typeof body !== "undefined" ? { body } : null, options.request ? { request: options.request } : null);
|
|
139502
139885
|
}
|
|
139503
139886
|
function endpointWithDefaults(defaults2, route, options) {
|
|
139504
|
-
return
|
|
139887
|
+
return parse2(merge(defaults2, route, options));
|
|
139505
139888
|
}
|
|
139506
139889
|
function withDefaults(oldDefaults, newDefaults) {
|
|
139507
139890
|
const DEFAULTS2 = merge(oldDefaults, newDefaults);
|
|
@@ -139510,7 +139893,7 @@ function withDefaults(oldDefaults, newDefaults) {
|
|
|
139510
139893
|
DEFAULTS: DEFAULTS2,
|
|
139511
139894
|
defaults: withDefaults.bind(null, DEFAULTS2),
|
|
139512
139895
|
merge: merge.bind(null, DEFAULTS2),
|
|
139513
|
-
parse
|
|
139896
|
+
parse: parse2
|
|
139514
139897
|
});
|
|
139515
139898
|
}
|
|
139516
139899
|
var endpoint = withDefaults(null, DEFAULTS);
|
|
@@ -139861,7 +140244,7 @@ var b64url = "(?:[a-zA-Z0-9_-]+)";
|
|
|
139861
140244
|
var sep3 = "\\.";
|
|
139862
140245
|
var jwtRE = new RegExp(`^${b64url}${sep3}${b64url}${sep3}${b64url}$`);
|
|
139863
140246
|
var isJWT = jwtRE.test.bind(jwtRE);
|
|
139864
|
-
async function
|
|
140247
|
+
async function auth(token) {
|
|
139865
140248
|
const isApp = isJWT(token);
|
|
139866
140249
|
const isInstallation = token.startsWith("v1.") || token.startsWith("ghs_");
|
|
139867
140250
|
const isUserToServer = token.startsWith("ghu_");
|
|
@@ -139891,7 +140274,7 @@ var createTokenAuth = function createTokenAuth2(token) {
|
|
|
139891
140274
|
throw new Error("[@octokit/auth-token] Token passed to createTokenAuth is not a string");
|
|
139892
140275
|
}
|
|
139893
140276
|
token = token.replace(/^(token|bearer) +/i, "");
|
|
139894
|
-
return Object.assign(
|
|
140277
|
+
return Object.assign(auth.bind(null, token), {
|
|
139895
140278
|
hook: hook.bind(null, token)
|
|
139896
140279
|
});
|
|
139897
140280
|
};
|
|
@@ -139978,20 +140361,20 @@ class Octokit {
|
|
|
139978
140361
|
type: "unauthenticated"
|
|
139979
140362
|
});
|
|
139980
140363
|
} else {
|
|
139981
|
-
const
|
|
139982
|
-
hook2.wrap("request",
|
|
139983
|
-
this.auth =
|
|
140364
|
+
const auth2 = createTokenAuth(options.auth);
|
|
140365
|
+
hook2.wrap("request", auth2.hook);
|
|
140366
|
+
this.auth = auth2;
|
|
139984
140367
|
}
|
|
139985
140368
|
} else {
|
|
139986
140369
|
const { authStrategy, ...otherOptions } = options;
|
|
139987
|
-
const
|
|
140370
|
+
const auth2 = authStrategy(Object.assign({
|
|
139988
140371
|
request: this.request,
|
|
139989
140372
|
log: this.log,
|
|
139990
140373
|
octokit: this,
|
|
139991
140374
|
octokitOptions: otherOptions
|
|
139992
140375
|
}, options.auth));
|
|
139993
|
-
hook2.wrap("request",
|
|
139994
|
-
this.auth =
|
|
140376
|
+
hook2.wrap("request", auth2.hook);
|
|
140377
|
+
this.auth = auth2;
|
|
139995
140378
|
}
|
|
139996
140379
|
const classConstructor = this.constructor;
|
|
139997
140380
|
for (let i = 0;i < classConstructor.plugins.length; ++i) {
|
|
@@ -142816,6 +143199,59 @@ app11.get("/prs", async (c) => {
|
|
|
142816
143199
|
});
|
|
142817
143200
|
var github_default = app11;
|
|
142818
143201
|
|
|
143202
|
+
// server/routes/auth.ts
|
|
143203
|
+
var SESSION_COOKIE_NAME2 = "vibora_session";
|
|
143204
|
+
var SESSION_EXPIRY_MS = 14 * 24 * 60 * 60 * 1000;
|
|
143205
|
+
var app12 = new Hono2;
|
|
143206
|
+
app12.post("/login", async (c) => {
|
|
143207
|
+
const { username, password } = await c.req.json();
|
|
143208
|
+
const settings = getSettings();
|
|
143209
|
+
if (!settings.basicAuthUsername || !settings.basicAuthPassword) {
|
|
143210
|
+
return c.json({ error: "Authentication not configured" }, 500);
|
|
143211
|
+
}
|
|
143212
|
+
if (username !== settings.basicAuthUsername || password !== settings.basicAuthPassword) {
|
|
143213
|
+
return c.json({ error: "Invalid credentials" }, 401);
|
|
143214
|
+
}
|
|
143215
|
+
const secret = getSessionSecret();
|
|
143216
|
+
if (!secret) {
|
|
143217
|
+
return c.json({ error: "Session secret not available" }, 500);
|
|
143218
|
+
}
|
|
143219
|
+
const expiry = Date.now() + SESSION_EXPIRY_MS;
|
|
143220
|
+
const sessionData = JSON.stringify({ exp: expiry });
|
|
143221
|
+
await setSignedCookie(c, SESSION_COOKIE_NAME2, sessionData, secret, {
|
|
143222
|
+
path: "/",
|
|
143223
|
+
httpOnly: true,
|
|
143224
|
+
sameSite: "Strict",
|
|
143225
|
+
maxAge: SESSION_EXPIRY_MS / 1000
|
|
143226
|
+
});
|
|
143227
|
+
return c.json({ success: true, expiresAt: new Date(expiry).toISOString() });
|
|
143228
|
+
});
|
|
143229
|
+
app12.post("/logout", async (c) => {
|
|
143230
|
+
deleteCookie(c, SESSION_COOKIE_NAME2, { path: "/" });
|
|
143231
|
+
return c.json({ success: true });
|
|
143232
|
+
});
|
|
143233
|
+
app12.get("/check", async (c) => {
|
|
143234
|
+
const settings = getSettings();
|
|
143235
|
+
if (!settings.basicAuthUsername || !settings.basicAuthPassword) {
|
|
143236
|
+
return c.json({ authRequired: false, authenticated: true });
|
|
143237
|
+
}
|
|
143238
|
+
const secret = getSessionSecret();
|
|
143239
|
+
if (!secret) {
|
|
143240
|
+
return c.json({ authRequired: true, authenticated: false });
|
|
143241
|
+
}
|
|
143242
|
+
const sessionCookie = await getSignedCookie(c, secret, SESSION_COOKIE_NAME2);
|
|
143243
|
+
if (sessionCookie) {
|
|
143244
|
+
try {
|
|
143245
|
+
const session = JSON.parse(sessionCookie);
|
|
143246
|
+
if (session.exp && session.exp > Date.now()) {
|
|
143247
|
+
return c.json({ authRequired: true, authenticated: true });
|
|
143248
|
+
}
|
|
143249
|
+
} catch {}
|
|
143250
|
+
}
|
|
143251
|
+
return c.json({ authRequired: true, authenticated: false });
|
|
143252
|
+
});
|
|
143253
|
+
var auth_default = app12;
|
|
143254
|
+
|
|
142819
143255
|
// server/app.ts
|
|
142820
143256
|
function getDistPath() {
|
|
142821
143257
|
if (process.env.VIBORA_PACKAGE_ROOT) {
|
|
@@ -142824,31 +143260,26 @@ function getDistPath() {
|
|
|
142824
143260
|
return join11(process.cwd(), "dist");
|
|
142825
143261
|
}
|
|
142826
143262
|
function createApp() {
|
|
142827
|
-
const
|
|
142828
|
-
|
|
142829
|
-
|
|
143263
|
+
const app13 = new Hono2;
|
|
143264
|
+
app13.use("*", logger());
|
|
143265
|
+
app13.use("*", cors({
|
|
142830
143266
|
origin: "*",
|
|
142831
143267
|
allowMethods: ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"],
|
|
142832
143268
|
allowHeaders: ["Content-Type", "Authorization"]
|
|
142833
143269
|
}));
|
|
142834
|
-
|
|
142835
|
-
|
|
142836
|
-
|
|
142837
|
-
|
|
142838
|
-
|
|
142839
|
-
|
|
142840
|
-
|
|
142841
|
-
|
|
142842
|
-
|
|
142843
|
-
|
|
142844
|
-
|
|
142845
|
-
|
|
142846
|
-
|
|
142847
|
-
app12.route("/api/worktrees", worktrees_default);
|
|
142848
|
-
app12.route("/api/terminal-view-state", terminal_view_state_default);
|
|
142849
|
-
app12.route("/api/repositories", repositories_default);
|
|
142850
|
-
app12.route("/api/linear", linear_default);
|
|
142851
|
-
app12.route("/api/github", github_default);
|
|
143270
|
+
app13.use("*", sessionAuthMiddleware);
|
|
143271
|
+
app13.route("/health", health_default);
|
|
143272
|
+
app13.route("/api/tasks", tasks_default);
|
|
143273
|
+
app13.route("/api/git", git_default);
|
|
143274
|
+
app13.route("/api/fs", filesystem_default);
|
|
143275
|
+
app13.route("/api/config", config_default);
|
|
143276
|
+
app13.route("/api/uploads", uploads_default);
|
|
143277
|
+
app13.route("/api/worktrees", worktrees_default);
|
|
143278
|
+
app13.route("/api/terminal-view-state", terminal_view_state_default);
|
|
143279
|
+
app13.route("/api/repositories", repositories_default);
|
|
143280
|
+
app13.route("/api/linear", linear_default);
|
|
143281
|
+
app13.route("/api/github", github_default);
|
|
143282
|
+
app13.route("/api/auth", auth_default);
|
|
142852
143283
|
if (process.env.VIBORA_PACKAGE_ROOT) {
|
|
142853
143284
|
const distPath = getDistPath();
|
|
142854
143285
|
const serveFile = async (filePath) => {
|
|
@@ -142871,7 +143302,7 @@ function createApp() {
|
|
|
142871
143302
|
headers: { "Content-Type": mimeTypes[ext2 || ""] || "application/octet-stream" }
|
|
142872
143303
|
});
|
|
142873
143304
|
};
|
|
142874
|
-
|
|
143305
|
+
app13.get("/assets/*", async (c) => {
|
|
142875
143306
|
const assetPath = join11(distPath, c.req.path);
|
|
142876
143307
|
if (existsSync10(assetPath)) {
|
|
142877
143308
|
return serveFile(assetPath);
|
|
@@ -142880,7 +143311,7 @@ function createApp() {
|
|
|
142880
143311
|
});
|
|
142881
143312
|
const staticFiles = ["favicon.ico", "vibora-icon.png", "vibora-logo.jpeg", "vite.svg"];
|
|
142882
143313
|
for (const file of staticFiles) {
|
|
142883
|
-
|
|
143314
|
+
app13.get(`/${file}`, async () => {
|
|
142884
143315
|
const filePath = join11(distPath, file);
|
|
142885
143316
|
if (existsSync10(filePath)) {
|
|
142886
143317
|
return serveFile(filePath);
|
|
@@ -142888,7 +143319,7 @@ function createApp() {
|
|
|
142888
143319
|
return new Response("Not Found", { status: 404 });
|
|
142889
143320
|
});
|
|
142890
143321
|
}
|
|
142891
|
-
|
|
143322
|
+
app13.get("*", async (c, next) => {
|
|
142892
143323
|
const path9 = c.req.path;
|
|
142893
143324
|
if (path9.startsWith("/api/") || path9.startsWith("/ws/") || path9 === "/health") {
|
|
142894
143325
|
return next();
|
|
@@ -142897,11 +143328,11 @@ function createApp() {
|
|
|
142897
143328
|
return c.html(html);
|
|
142898
143329
|
});
|
|
142899
143330
|
}
|
|
142900
|
-
return
|
|
143331
|
+
return app13;
|
|
142901
143332
|
}
|
|
142902
143333
|
|
|
142903
143334
|
// server/services/pr-monitor.ts
|
|
142904
|
-
import { execSync as
|
|
143335
|
+
import { execSync as execSync4 } from "child_process";
|
|
142905
143336
|
var POLL_INTERVAL = 60000;
|
|
142906
143337
|
function parsePrUrl(url) {
|
|
142907
143338
|
const match3 = url.match(/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/);
|
|
@@ -142916,7 +143347,7 @@ function checkPrStatus(prUrl) {
|
|
|
142916
143347
|
return null;
|
|
142917
143348
|
}
|
|
142918
143349
|
try {
|
|
142919
|
-
const output =
|
|
143350
|
+
const output = execSync4(`gh pr view ${parsed.number} --repo ${parsed.owner}/${parsed.repo} --json state,mergedAt`, { encoding: "utf-8", timeout: 1e4, stdio: ["pipe", "pipe", "pipe"] });
|
|
142920
143351
|
const data = JSON.parse(output);
|
|
142921
143352
|
return {
|
|
142922
143353
|
state: data.state,
|
|
@@ -142983,11 +143414,11 @@ setBroadcastDestroyed((terminalId) => {
|
|
|
142983
143414
|
payload: { terminalId }
|
|
142984
143415
|
});
|
|
142985
143416
|
});
|
|
142986
|
-
var
|
|
142987
|
-
var { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app:
|
|
142988
|
-
|
|
143417
|
+
var app13 = createApp();
|
|
143418
|
+
var { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: app13 });
|
|
143419
|
+
app13.get("/ws/terminal", upgradeWebSocket(() => terminalWebSocketHandlers));
|
|
142989
143420
|
var server = serve({
|
|
142990
|
-
fetch:
|
|
143421
|
+
fetch: app13.fetch,
|
|
142991
143422
|
port: PORT,
|
|
142992
143423
|
hostname: "0.0.0.0"
|
|
142993
143424
|
}, (info) => {
|