@vibe80/vibe80 0.2.1 → 0.2.2
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/README.md +93 -4
- package/bin/vibe80.js +1728 -16
- package/client/dist/assets/{DiffPanel-Luk1GrAd.js → DiffPanel-BUJhQj_Q.js} +1 -1
- package/client/dist/assets/{ExplorerPanel-CGVmxql1.js → ExplorerPanel-DugEeaO2.js} +1 -1
- package/client/dist/assets/{LogsPanel-D8Z8Zam8.js → LogsPanel-BQrGxMu_.js} +1 -1
- package/client/dist/assets/{SettingsPanel-H2q2eoDf.js → SettingsPanel-Ci2BdIYO.js} +1 -1
- package/client/dist/assets/{TerminalPanel-kEz-cjes.js → TerminalPanel-C-T3t-6T.js} +1 -1
- package/client/dist/assets/index-cFi4LM0j.js +711 -0
- package/client/dist/assets/index-qNyFxUjK.css +32 -0
- package/client/dist/icon_square-512x512.png +0 -0
- package/client/dist/icon_square.svg +58 -0
- package/client/dist/index.html +3 -2
- package/client/dist/sw.js +1 -1
- package/client/index.html +1 -0
- package/client/public/icon_square-512x512.png +0 -0
- package/client/public/icon_square.svg +58 -0
- package/client/src/App.jsx +204 -2
- package/client/src/assets/vibe80_dark.png +0 -0
- package/client/src/assets/vibe80_light.png +0 -0
- package/client/src/components/Chat/ChatMessages.jsx +1 -1
- package/client/src/components/SessionGate/SessionGate.jsx +282 -90
- package/client/src/components/WorktreeTabs.css +11 -0
- package/client/src/components/WorktreeTabs.jsx +77 -47
- package/client/src/hooks/useChatSocket.js +8 -7
- package/client/src/hooks/useRepoBranchesModels.js +12 -6
- package/client/src/hooks/useWorktreeCloseConfirm.js +19 -7
- package/client/src/hooks/useWorktrees.js +3 -1
- package/client/src/index.css +26 -3
- package/client/src/locales/en.json +12 -1
- package/client/src/locales/fr.json +12 -1
- package/docs/api/openapi.json +1 -1
- package/package.json +2 -1
- package/server/scripts/rotate-workspace-secret.js +1 -1
- package/server/src/claudeClient.js +3 -3
- package/server/src/codexClient.js +3 -3
- package/server/src/config.js +6 -6
- package/server/src/index.js +14 -12
- package/server/src/middleware/auth.js +7 -7
- package/server/src/middleware/debug.js +36 -4
- package/server/src/providerLogger.js +2 -2
- package/server/src/routes/sessions.js +133 -21
- package/server/src/routes/workspaces.js +1 -1
- package/server/src/runAs.js +14 -14
- package/server/src/services/auth.js +3 -3
- package/server/src/services/session.js +182 -14
- package/server/src/services/workspace.js +86 -42
- package/server/src/storage/index.js +2 -2
- package/server/src/storage/redis.js +38 -36
- package/server/src/storage/sqlite.js +13 -13
- package/server/src/worktreeManager.js +87 -19
- package/server/tests/integration/routes/workspaces-routes.test.js +8 -8
- package/server/tests/setup/env.js +5 -5
- package/server/tests/unit/services/auth.test.js +3 -3
- package/client/dist/assets/index-BDQQz6SJ.css +0 -32
- package/client/dist/assets/index-knjescVH.js +0 -711
|
@@ -63,6 +63,16 @@ const runSessionCommandOutput = (session, command, args, options = {}) =>
|
|
|
63
63
|
env: buildSessionEnv(session, options),
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
+
const parseCloneDepth = (value) => {
|
|
67
|
+
const parsed = Number.parseInt(String(value ?? "").trim(), 10);
|
|
68
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
69
|
+
return 50;
|
|
70
|
+
}
|
|
71
|
+
return parsed;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const cloneDepth = parseCloneDepth(process.env.VIBE80_CLONE_DEPTH);
|
|
75
|
+
|
|
66
76
|
const resolveSessionGitDir = (session) =>
|
|
67
77
|
session?.gitDir || path.join(session.dir, "git");
|
|
68
78
|
|
|
@@ -153,14 +163,26 @@ const touchSession = async (session) => {
|
|
|
153
163
|
return updated;
|
|
154
164
|
};
|
|
155
165
|
|
|
156
|
-
const loadWorktree = async (worktreeId) => {
|
|
166
|
+
const loadWorktree = async (session, worktreeId) => {
|
|
157
167
|
if (!worktreeId) return null;
|
|
158
|
-
|
|
168
|
+
const worktree = await storage.getWorktree(session.sessionId, worktreeId);
|
|
169
|
+
if (!worktree) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
if (worktree.sessionId && worktree.sessionId !== session.sessionId) {
|
|
173
|
+
console.warn("Cross-session worktree access blocked", {
|
|
174
|
+
requestedSessionId: session.sessionId,
|
|
175
|
+
worktreeId,
|
|
176
|
+
ownerSessionId: worktree.sessionId,
|
|
177
|
+
});
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
return worktree;
|
|
159
181
|
};
|
|
160
182
|
|
|
161
183
|
const ensureMainWorktree = async (session) => {
|
|
162
184
|
const worktreeId = getMainWorktreeStorageId(session.sessionId);
|
|
163
|
-
const existing = await loadWorktree(worktreeId);
|
|
185
|
+
const existing = await loadWorktree(session, worktreeId);
|
|
164
186
|
if (existing) return existing;
|
|
165
187
|
const branchName = await resolveCurrentBranchName(session);
|
|
166
188
|
const worktree = {
|
|
@@ -275,7 +297,7 @@ export async function createWorktree(session, options) {
|
|
|
275
297
|
let startCommit = "HEAD";
|
|
276
298
|
let sourceBranchName = "";
|
|
277
299
|
if (parentWorktreeId) {
|
|
278
|
-
const parent = await loadWorktree(parentWorktreeId);
|
|
300
|
+
const parent = await loadWorktree(session, parentWorktreeId);
|
|
279
301
|
if (parent) {
|
|
280
302
|
startCommit = await runSessionCommandOutput(
|
|
281
303
|
session,
|
|
@@ -318,8 +340,45 @@ export async function createWorktree(session, options) {
|
|
|
318
340
|
}
|
|
319
341
|
};
|
|
320
342
|
|
|
343
|
+
const ensureRemoteBranchAvailable = async (branch) => {
|
|
344
|
+
const normalized = normalizeBranchName(branch);
|
|
345
|
+
if (!normalized) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
const alreadyAvailable = await checkRemoteBranchExists(normalized);
|
|
349
|
+
if (alreadyAvailable) {
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
const remoteHead = `refs/heads/${normalized}`;
|
|
353
|
+
const localRemoteRef = `refs/remotes/origin/${normalized}`;
|
|
354
|
+
try {
|
|
355
|
+
await runSessionCommand(
|
|
356
|
+
session,
|
|
357
|
+
"git",
|
|
358
|
+
[
|
|
359
|
+
"fetch",
|
|
360
|
+
"--depth",
|
|
361
|
+
String(cloneDepth),
|
|
362
|
+
"origin",
|
|
363
|
+
`${remoteHead}:${localRemoteRef}`,
|
|
364
|
+
],
|
|
365
|
+
{ cwd: session.repoDir }
|
|
366
|
+
);
|
|
367
|
+
} catch {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
return checkRemoteBranchExists(normalized);
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
if (startingBranch) {
|
|
374
|
+
const normalizedStartingBranch = normalizeBranchName(startingBranch);
|
|
375
|
+
if (normalizedStartingBranch) {
|
|
376
|
+
await ensureRemoteBranchAvailable(normalizedStartingBranch);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
321
380
|
const remoteBranchExists = requestedBranchName
|
|
322
|
-
? await
|
|
381
|
+
? await ensureRemoteBranchAvailable(requestedBranchName)
|
|
323
382
|
: false;
|
|
324
383
|
|
|
325
384
|
if (requestedBranchName) {
|
|
@@ -436,7 +495,7 @@ export async function removeWorktree(session, worktreeId, deleteBranch = true) {
|
|
|
436
495
|
if (isMainWorktreeStorageId(session, resolvedId)) {
|
|
437
496
|
throw new Error("Main worktree cannot be removed");
|
|
438
497
|
}
|
|
439
|
-
const worktree = await loadWorktree(resolvedId);
|
|
498
|
+
const worktree = await loadWorktree(session, resolvedId);
|
|
440
499
|
if (!worktree) {
|
|
441
500
|
throw new Error("Worktree not found");
|
|
442
501
|
}
|
|
@@ -477,7 +536,7 @@ export async function removeWorktree(session, worktreeId, deleteBranch = true) {
|
|
|
477
536
|
|
|
478
537
|
export async function getWorktreeDiff(session, worktreeId) {
|
|
479
538
|
const resolvedId = resolveWorktreeStorageId(session, worktreeId);
|
|
480
|
-
const worktree = await loadWorktree(resolvedId);
|
|
539
|
+
const worktree = await loadWorktree(session, resolvedId);
|
|
481
540
|
if (!worktree) {
|
|
482
541
|
throw new Error("Worktree not found");
|
|
483
542
|
}
|
|
@@ -492,7 +551,7 @@ export async function getWorktreeDiff(session, worktreeId) {
|
|
|
492
551
|
|
|
493
552
|
export async function getWorktreeCommits(session, worktreeId, limit = 20) {
|
|
494
553
|
const resolvedId = resolveWorktreeStorageId(session, worktreeId);
|
|
495
|
-
const worktree = await loadWorktree(resolvedId);
|
|
554
|
+
const worktree = await loadWorktree(session, resolvedId);
|
|
496
555
|
if (!worktree) {
|
|
497
556
|
throw new Error("Worktree not found");
|
|
498
557
|
}
|
|
@@ -515,11 +574,17 @@ export async function getWorktreeCommits(session, worktreeId, limit = 20) {
|
|
|
515
574
|
}
|
|
516
575
|
|
|
517
576
|
export async function mergeWorktree(session, sourceWorktreeId, targetWorktreeId) {
|
|
518
|
-
const source = await loadWorktree(
|
|
577
|
+
const source = await loadWorktree(
|
|
578
|
+
session,
|
|
579
|
+
resolveWorktreeStorageId(session, sourceWorktreeId)
|
|
580
|
+
);
|
|
519
581
|
if (!source) {
|
|
520
582
|
throw new Error("Source worktree not found");
|
|
521
583
|
}
|
|
522
|
-
const target = await loadWorktree(
|
|
584
|
+
const target = await loadWorktree(
|
|
585
|
+
session,
|
|
586
|
+
resolveWorktreeStorageId(session, targetWorktreeId)
|
|
587
|
+
);
|
|
523
588
|
if (!target) {
|
|
524
589
|
throw new Error("Target worktree not found");
|
|
525
590
|
}
|
|
@@ -548,7 +613,7 @@ export async function mergeWorktree(session, sourceWorktreeId, targetWorktreeId)
|
|
|
548
613
|
}
|
|
549
614
|
|
|
550
615
|
export async function abortMerge(session, worktreeId) {
|
|
551
|
-
const worktree = await loadWorktree(resolveWorktreeStorageId(session, worktreeId));
|
|
616
|
+
const worktree = await loadWorktree(session, resolveWorktreeStorageId(session, worktreeId));
|
|
552
617
|
if (!worktree) {
|
|
553
618
|
throw new Error("Worktree not found");
|
|
554
619
|
}
|
|
@@ -556,7 +621,10 @@ export async function abortMerge(session, worktreeId) {
|
|
|
556
621
|
}
|
|
557
622
|
|
|
558
623
|
export async function cherryPickCommit(session, commitSha, targetWorktreeId) {
|
|
559
|
-
const target = await loadWorktree(
|
|
624
|
+
const target = await loadWorktree(
|
|
625
|
+
session,
|
|
626
|
+
resolveWorktreeStorageId(session, targetWorktreeId)
|
|
627
|
+
);
|
|
560
628
|
if (!target) {
|
|
561
629
|
throw new Error("Target worktree not found");
|
|
562
630
|
}
|
|
@@ -618,7 +686,7 @@ export async function getWorktree(session, worktreeId) {
|
|
|
618
686
|
const mainWorktree = await ensureMainWorktree(session);
|
|
619
687
|
return mainWorktree;
|
|
620
688
|
}
|
|
621
|
-
const worktree = await loadWorktree(resolvedId);
|
|
689
|
+
const worktree = await loadWorktree(session, resolvedId);
|
|
622
690
|
if (!worktree) return null;
|
|
623
691
|
const runtime = getSessionRuntime(session.sessionId);
|
|
624
692
|
if (runtime?.worktreeClients?.has(resolvedId)) {
|
|
@@ -629,7 +697,7 @@ export async function getWorktree(session, worktreeId) {
|
|
|
629
697
|
|
|
630
698
|
export async function updateWorktreeStatus(session, worktreeId, status) {
|
|
631
699
|
const resolvedId = resolveWorktreeStorageId(session, worktreeId);
|
|
632
|
-
let worktree = await loadWorktree(resolvedId);
|
|
700
|
+
let worktree = await loadWorktree(session, resolvedId);
|
|
633
701
|
if (!worktree && isMainWorktreeStorageId(session, resolvedId)) {
|
|
634
702
|
worktree = await ensureMainWorktree(session);
|
|
635
703
|
}
|
|
@@ -644,7 +712,7 @@ export async function updateWorktreeStatus(session, worktreeId, status) {
|
|
|
644
712
|
|
|
645
713
|
export async function updateWorktreeThreadId(session, worktreeId, threadId) {
|
|
646
714
|
const resolvedId = resolveWorktreeStorageId(session, worktreeId);
|
|
647
|
-
const worktree = await loadWorktree(resolvedId);
|
|
715
|
+
const worktree = await loadWorktree(session, resolvedId);
|
|
648
716
|
if (!worktree || !threadId) return;
|
|
649
717
|
const updated = {
|
|
650
718
|
...worktree,
|
|
@@ -661,7 +729,7 @@ export async function updateWorktreeModel(
|
|
|
661
729
|
reasoningEffort = null
|
|
662
730
|
) {
|
|
663
731
|
const resolvedId = resolveWorktreeStorageId(session, worktreeId);
|
|
664
|
-
let worktree = await loadWorktree(resolvedId);
|
|
732
|
+
let worktree = await loadWorktree(session, resolvedId);
|
|
665
733
|
if (!worktree && isMainWorktreeStorageId(session, resolvedId)) {
|
|
666
734
|
worktree = await ensureMainWorktree(session);
|
|
667
735
|
}
|
|
@@ -677,7 +745,7 @@ export async function updateWorktreeModel(
|
|
|
677
745
|
|
|
678
746
|
export async function appendWorktreeMessage(session, worktreeId, message) {
|
|
679
747
|
const resolvedId = resolveWorktreeStorageId(session, worktreeId);
|
|
680
|
-
let worktree = await loadWorktree(resolvedId);
|
|
748
|
+
let worktree = await loadWorktree(session, resolvedId);
|
|
681
749
|
if (!worktree && isMainWorktreeStorageId(session, resolvedId)) {
|
|
682
750
|
worktree = await ensureMainWorktree(session);
|
|
683
751
|
}
|
|
@@ -694,7 +762,7 @@ export async function appendWorktreeMessage(session, worktreeId, message) {
|
|
|
694
762
|
|
|
695
763
|
export async function clearWorktreeMessages(session, worktreeId) {
|
|
696
764
|
const resolvedId = resolveWorktreeStorageId(session, worktreeId);
|
|
697
|
-
let worktree = await loadWorktree(resolvedId);
|
|
765
|
+
let worktree = await loadWorktree(session, resolvedId);
|
|
698
766
|
if (!worktree && isMainWorktreeStorageId(session, resolvedId)) {
|
|
699
767
|
worktree = await ensureMainWorktree(session);
|
|
700
768
|
}
|
|
@@ -710,7 +778,7 @@ export async function clearWorktreeMessages(session, worktreeId) {
|
|
|
710
778
|
export async function renameWorktree(session, worktreeId, newName) {
|
|
711
779
|
const resolvedId = resolveWorktreeStorageId(session, worktreeId);
|
|
712
780
|
if (isMainWorktreeStorageId(session, resolvedId)) return;
|
|
713
|
-
const worktree = await loadWorktree(resolvedId);
|
|
781
|
+
const worktree = await loadWorktree(session, resolvedId);
|
|
714
782
|
if (!worktree || !newName) return;
|
|
715
783
|
const updated = { ...worktree, name: newName };
|
|
716
784
|
await storage.saveWorktree(session.sessionId, resolvedId, serializeWorktree(updated));
|
|
@@ -49,7 +49,7 @@ describe("routes/workspaces", () => {
|
|
|
49
49
|
|
|
50
50
|
beforeEach(() => {
|
|
51
51
|
vi.clearAllMocks();
|
|
52
|
-
process.env.
|
|
52
|
+
process.env.VIBE80_DEPLOYMENT_MODE = "multi_user";
|
|
53
53
|
issueWorkspaceTokensMock.mockResolvedValue({
|
|
54
54
|
workspaceToken: "workspace-token",
|
|
55
55
|
refreshToken: "refresh-token",
|
|
@@ -89,7 +89,7 @@ describe("routes/workspaces", () => {
|
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
it("POST /api/v1/workspaces/login mono_auth_token renvoie 403 hors mono_user", async () => {
|
|
92
|
-
process.env.
|
|
92
|
+
process.env.VIBE80_DEPLOYMENT_MODE = "multi_user";
|
|
93
93
|
const handler = await createRouteHandler("/workspaces/login", "post");
|
|
94
94
|
const res = createMockRes();
|
|
95
95
|
await handler(
|
|
@@ -104,7 +104,7 @@ describe("routes/workspaces", () => {
|
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
it("POST /api/v1/workspaces renvoie 403 en mode mono_user", async () => {
|
|
107
|
-
process.env.
|
|
107
|
+
process.env.VIBE80_DEPLOYMENT_MODE = "mono_user";
|
|
108
108
|
const handler = await createRouteHandler("/workspaces", "post");
|
|
109
109
|
const res = createMockRes();
|
|
110
110
|
await handler(
|
|
@@ -124,7 +124,7 @@ describe("routes/workspaces", () => {
|
|
|
124
124
|
});
|
|
125
125
|
|
|
126
126
|
it("POST /api/v1/workspaces/login credentials renvoie 403 en mode mono_user", async () => {
|
|
127
|
-
process.env.
|
|
127
|
+
process.env.VIBE80_DEPLOYMENT_MODE = "mono_user";
|
|
128
128
|
const handler = await createRouteHandler("/workspaces/login", "post");
|
|
129
129
|
const res = createMockRes();
|
|
130
130
|
await handler(
|
|
@@ -145,7 +145,7 @@ describe("routes/workspaces", () => {
|
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
it("POST /api/v1/workspaces/login mono_auth_token renvoie 400 si token manquant", async () => {
|
|
148
|
-
process.env.
|
|
148
|
+
process.env.VIBE80_DEPLOYMENT_MODE = "mono_user";
|
|
149
149
|
const handler = await createRouteHandler("/workspaces/login", "post");
|
|
150
150
|
const res = createMockRes();
|
|
151
151
|
await handler({ body: { grantType: "mono_auth_token" } }, res);
|
|
@@ -157,7 +157,7 @@ describe("routes/workspaces", () => {
|
|
|
157
157
|
});
|
|
158
158
|
|
|
159
159
|
it("POST /api/v1/workspaces/login mono_auth_token renvoie 401 si token invalide", async () => {
|
|
160
|
-
process.env.
|
|
160
|
+
process.env.VIBE80_DEPLOYMENT_MODE = "mono_user";
|
|
161
161
|
consumeMonoAuthTokenMock.mockReturnValueOnce({
|
|
162
162
|
ok: false,
|
|
163
163
|
code: "MONO_AUTH_TOKEN_INVALID",
|
|
@@ -176,7 +176,7 @@ describe("routes/workspaces", () => {
|
|
|
176
176
|
});
|
|
177
177
|
|
|
178
178
|
it("POST /api/v1/workspaces/login mono_auth_token renvoie 401 si workspace non résolu", async () => {
|
|
179
|
-
process.env.
|
|
179
|
+
process.env.VIBE80_DEPLOYMENT_MODE = "mono_user";
|
|
180
180
|
consumeMonoAuthTokenMock.mockReturnValueOnce({
|
|
181
181
|
ok: true,
|
|
182
182
|
workspaceId: validCredentials.workspaceId,
|
|
@@ -201,7 +201,7 @@ describe("routes/workspaces", () => {
|
|
|
201
201
|
});
|
|
202
202
|
|
|
203
203
|
it("POST /api/v1/workspaces/login mono_auth_token renvoie 200 en succès", async () => {
|
|
204
|
-
process.env.
|
|
204
|
+
process.env.VIBE80_DEPLOYMENT_MODE = "mono_user";
|
|
205
205
|
consumeMonoAuthTokenMock.mockReturnValueOnce({
|
|
206
206
|
ok: true,
|
|
207
207
|
workspaceId: validCredentials.workspaceId,
|
|
@@ -2,8 +2,8 @@ import path from "path";
|
|
|
2
2
|
import os from "os";
|
|
3
3
|
|
|
4
4
|
process.env.NODE_ENV = "test";
|
|
5
|
-
process.env.
|
|
6
|
-
process.env.
|
|
7
|
-
process.env.
|
|
8
|
-
process.env.
|
|
9
|
-
process.env.
|
|
5
|
+
process.env.VIBE80_STORAGE_BACKEND = process.env.VIBE80_STORAGE_BACKEND || "sqlite";
|
|
6
|
+
process.env.VIBE80_DEPLOYMENT_MODE = process.env.VIBE80_DEPLOYMENT_MODE || "multi_user";
|
|
7
|
+
process.env.VIBE80_JWT_KEY = process.env.VIBE80_JWT_KEY || "test-jwt-key";
|
|
8
|
+
process.env.VIBE80_JWT_KEY_PATH =
|
|
9
|
+
process.env.VIBE80_JWT_KEY_PATH || path.join(os.tmpdir(), "vibe80-jwt-test.key");
|
|
@@ -34,7 +34,7 @@ describe("services/auth", () => {
|
|
|
34
34
|
vi.clearAllMocks();
|
|
35
35
|
idSeq.value = 0;
|
|
36
36
|
vi.useRealTimers();
|
|
37
|
-
delete process.env.
|
|
37
|
+
delete process.env.VIBE80_MONO_AUTH_TOKEN_TTL_MS;
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
it("issueWorkspaceTokens crée un refresh token indépendant", async () => {
|
|
@@ -128,7 +128,7 @@ describe("services/auth", () => {
|
|
|
128
128
|
|
|
129
129
|
it("consumeMonoAuthToken retourne EXPIRED pour un token expiré", async () => {
|
|
130
130
|
vi.useFakeTimers();
|
|
131
|
-
process.env.
|
|
131
|
+
process.env.VIBE80_MONO_AUTH_TOKEN_TTL_MS = "1";
|
|
132
132
|
const { createMonoAuthToken, consumeMonoAuthToken } = await loadAuthModule();
|
|
133
133
|
const record = createMonoAuthToken("default");
|
|
134
134
|
vi.advanceTimersByTime(10);
|
|
@@ -162,7 +162,7 @@ describe("services/auth", () => {
|
|
|
162
162
|
|
|
163
163
|
it("cleanupMonoAuthTokens purge les tokens expirés", async () => {
|
|
164
164
|
vi.useFakeTimers();
|
|
165
|
-
process.env.
|
|
165
|
+
process.env.VIBE80_MONO_AUTH_TOKEN_TTL_MS = "1";
|
|
166
166
|
const {
|
|
167
167
|
createMonoAuthToken,
|
|
168
168
|
cleanupMonoAuthTokens,
|