multi-app-mcp 1.0.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/README.md +106 -0
- package/index.js +59 -0
- package/package.json +20 -0
- package/plugins/quickreviewer/auth.js +478 -0
- package/plugins/quickreviewer/documents.js +476 -0
- package/plugins/quickreviewer/folders.js +453 -0
- package/plugins/quickreviewer/index.js +32 -0
- package/plugins/quickreviewer/session.js +30 -0
- package/plugins/quickreviewer/teams.js +280 -0
- package/plugins/quickreviewer/upload.js +234 -0
- package/plugins/quickreviewer/workflows.js +14 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// FOLDERS — Folder management tools
|
|
3
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
import { getAuthHeaders, requireLogin } from "./session.js";
|
|
6
|
+
|
|
7
|
+
const QR_API_URL = process.env.QR_API_URL || "https://app.quickreviewer.com/api";
|
|
8
|
+
|
|
9
|
+
// ─── Tool Definitions ─────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
export const tools = [
|
|
12
|
+
{
|
|
13
|
+
name: "qr_get_folders",
|
|
14
|
+
description: "Get all folders of the logged-in user. User must be logged in.",
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {},
|
|
18
|
+
required: [],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "qr_get_folder_tree",
|
|
23
|
+
description:
|
|
24
|
+
"Get full folder tree with documents inside. " +
|
|
25
|
+
"Use folderId=0 for root. User must be logged in.",
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
folderId: { type: "integer", description: "Folder ID (0 for root)" },
|
|
30
|
+
},
|
|
31
|
+
required: ["folderId"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "qr_get_folder_detail",
|
|
36
|
+
description: "Get details of a specific folder by folderId. User must be logged in.",
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: {
|
|
40
|
+
folderId: { type: "integer", description: "Folder ID" },
|
|
41
|
+
},
|
|
42
|
+
required: ["folderId"],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "qr_get_folder_children",
|
|
47
|
+
description:
|
|
48
|
+
"Get all sub-folders inside a folder. " +
|
|
49
|
+
"Use parentId=0 for root level folders. User must be logged in.",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
parentId: { type: "integer", description: "Parent folder ID (0 for root)" },
|
|
54
|
+
},
|
|
55
|
+
required: ["parentId"],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "qr_create_folder",
|
|
60
|
+
description:
|
|
61
|
+
"Create a new folder. " +
|
|
62
|
+
"For root level folder use parentId=0, left=1, right=2, level=1, position=1. " +
|
|
63
|
+
"visibleToAll: 1 = visible to all, 0 = private. " +
|
|
64
|
+
"User must be logged in.",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
type: "object",
|
|
67
|
+
properties: {
|
|
68
|
+
folderName: { type: "string", description: "Name of the new folder" },
|
|
69
|
+
parentId: { type: "integer", description: "Parent folder ID (0 for root)" },
|
|
70
|
+
visibleToAll: { type: "integer", description: "1 = visible to all, 0 = private" },
|
|
71
|
+
left: { type: "integer", description: "Tree left value (use 1 for root)" },
|
|
72
|
+
right: { type: "integer", description: "Tree right value (use 2 for root)" },
|
|
73
|
+
level: { type: "integer", description: "Folder depth level (1 for root)" },
|
|
74
|
+
position: { type: "integer", description: "Position in folder list (start from 1)" },
|
|
75
|
+
},
|
|
76
|
+
required: ["folderName", "parentId", "visibleToAll", "left", "right", "level", "position"],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "qr_rename_folder",
|
|
81
|
+
description: "Rename a folder. User must be logged in.",
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
folderId: { type: "integer", description: "Folder ID to rename" },
|
|
86
|
+
folderName: { type: "string", description: "New folder name" },
|
|
87
|
+
},
|
|
88
|
+
required: ["folderId", "folderName"],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: "qr_trash_folder",
|
|
93
|
+
description: "Move a folder to trash. User must be logged in.",
|
|
94
|
+
inputSchema: {
|
|
95
|
+
type: "object",
|
|
96
|
+
properties: {
|
|
97
|
+
folderId: {
|
|
98
|
+
type: "array",
|
|
99
|
+
items: { type: "integer" },
|
|
100
|
+
description: "Array of folder IDs to trash",
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
required: ["folderId"],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "qr_delete_folder",
|
|
108
|
+
description:
|
|
109
|
+
"Delete a folder by moving it to trash first using qr_trash_folder. " +
|
|
110
|
+
"Always use qr_trash_folder instead of this tool — it is more reliable. " +
|
|
111
|
+
"This tool only removes folder from tree map, not from the actual folder list. " +
|
|
112
|
+
"User must be logged in.",
|
|
113
|
+
inputSchema: {
|
|
114
|
+
type: "object",
|
|
115
|
+
properties: {
|
|
116
|
+
folderId: {
|
|
117
|
+
type: "array",
|
|
118
|
+
items: { type: "integer" },
|
|
119
|
+
description: "Array of folder IDs to delete",
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
required: ["folderId"],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "qr_share_folder",
|
|
127
|
+
description:
|
|
128
|
+
"Share a folder with someone via email. " +
|
|
129
|
+
"shareAction: 'view', 'comment', or 'approve'. " +
|
|
130
|
+
"download: 1 = allow, 0 = disallow. " +
|
|
131
|
+
"anybody: 1 = anyone with link, 0 = specific email only. " +
|
|
132
|
+
"User must be logged in.",
|
|
133
|
+
inputSchema: {
|
|
134
|
+
type: "object",
|
|
135
|
+
properties: {
|
|
136
|
+
folderId: {
|
|
137
|
+
type: "array",
|
|
138
|
+
items: { type: "integer" },
|
|
139
|
+
description: "Array of folder IDs to share",
|
|
140
|
+
},
|
|
141
|
+
shareEmail: { type: "string", description: "Email address to share with" },
|
|
142
|
+
shareAction: { type: "string", description: "Permission: 'view', 'comment', or 'approve'" },
|
|
143
|
+
download: { type: "integer", description: "Allow download: 1 = yes, 0 = no" },
|
|
144
|
+
anybody: { type: "integer", description: "Anyone with link: 1 = yes, 0 = no" },
|
|
145
|
+
},
|
|
146
|
+
required: ["folderId", "shareEmail", "shareAction", "download", "anybody"],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: "qr_get_trashed_folders",
|
|
151
|
+
description:
|
|
152
|
+
"Get all trashed (deleted) folders of the logged-in user. " +
|
|
153
|
+
"Use folderId=0 to get all trashed folders. " +
|
|
154
|
+
"User must be logged in.",
|
|
155
|
+
inputSchema: {
|
|
156
|
+
type: "object",
|
|
157
|
+
properties: {
|
|
158
|
+
folderId: { type: "integer", description: "Folder ID filter (0 = all trashed folders)" },
|
|
159
|
+
},
|
|
160
|
+
required: ["folderId"],
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
// ─── Handlers ─────────────────────────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
export const handlers = {
|
|
168
|
+
|
|
169
|
+
qr_get_folders: async () => {
|
|
170
|
+
const authError = requireLogin();
|
|
171
|
+
if (authError) return authError;
|
|
172
|
+
|
|
173
|
+
const res = await fetch(`${QR_API_URL}/folders`, {
|
|
174
|
+
method: "GET",
|
|
175
|
+
headers: getAuthHeaders(),
|
|
176
|
+
});
|
|
177
|
+
const data = await res.json();
|
|
178
|
+
|
|
179
|
+
if (res.ok) {
|
|
180
|
+
return {
|
|
181
|
+
content: [{
|
|
182
|
+
type: "text",
|
|
183
|
+
text: `✅ Folders fetched\n\n${JSON.stringify(data, null, 2)}`,
|
|
184
|
+
}],
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
content: [{
|
|
189
|
+
type: "text",
|
|
190
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
191
|
+
}],
|
|
192
|
+
isError: true,
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
qr_get_folder_tree: async ({ folderId }) => {
|
|
197
|
+
const authError = requireLogin();
|
|
198
|
+
if (authError) return authError;
|
|
199
|
+
|
|
200
|
+
const res = await fetch(`${QR_API_URL}/folder/get-tree`, {
|
|
201
|
+
method: "POST",
|
|
202
|
+
headers: getAuthHeaders(),
|
|
203
|
+
body: JSON.stringify({ folderId }),
|
|
204
|
+
});
|
|
205
|
+
const data = await res.json();
|
|
206
|
+
|
|
207
|
+
if (res.ok) {
|
|
208
|
+
return {
|
|
209
|
+
content: [{
|
|
210
|
+
type: "text",
|
|
211
|
+
text: `✅ Folder tree fetched\n\n${JSON.stringify(data, null, 2)}`,
|
|
212
|
+
}],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
content: [{
|
|
217
|
+
type: "text",
|
|
218
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
219
|
+
}],
|
|
220
|
+
isError: true,
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
qr_get_folder_detail: async ({ folderId }) => {
|
|
225
|
+
const authError = requireLogin();
|
|
226
|
+
if (authError) return authError;
|
|
227
|
+
|
|
228
|
+
const res = await fetch(`${QR_API_URL}/folder/folder-detail`, {
|
|
229
|
+
method: "POST",
|
|
230
|
+
headers: getAuthHeaders(),
|
|
231
|
+
body: JSON.stringify({ folderId }),
|
|
232
|
+
});
|
|
233
|
+
const data = await res.json();
|
|
234
|
+
|
|
235
|
+
if (res.ok) {
|
|
236
|
+
return {
|
|
237
|
+
content: [{
|
|
238
|
+
type: "text",
|
|
239
|
+
text: `✅ Folder detail fetched\n\n${JSON.stringify(data, null, 2)}`,
|
|
240
|
+
}],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
content: [{
|
|
245
|
+
type: "text",
|
|
246
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
247
|
+
}],
|
|
248
|
+
isError: true,
|
|
249
|
+
};
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
qr_get_folder_children: async ({ parentId }) => {
|
|
253
|
+
const authError = requireLogin();
|
|
254
|
+
if (authError) return authError;
|
|
255
|
+
|
|
256
|
+
const res = await fetch(`${QR_API_URL}/folder/getchildren`, {
|
|
257
|
+
method: "POST",
|
|
258
|
+
headers: getAuthHeaders(),
|
|
259
|
+
body: JSON.stringify({ parentId }),
|
|
260
|
+
});
|
|
261
|
+
const data = await res.json();
|
|
262
|
+
|
|
263
|
+
if (res.ok) {
|
|
264
|
+
return {
|
|
265
|
+
content: [{
|
|
266
|
+
type: "text",
|
|
267
|
+
text: `✅ Sub-folders fetched\n\n${JSON.stringify(data, null, 2)}`,
|
|
268
|
+
}],
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
content: [{
|
|
273
|
+
type: "text",
|
|
274
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
275
|
+
}],
|
|
276
|
+
isError: true,
|
|
277
|
+
};
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
qr_create_folder: async ({ folderName, parentId, visibleToAll, left, right, level, position }) => {
|
|
281
|
+
const authError = requireLogin();
|
|
282
|
+
if (authError) return authError;
|
|
283
|
+
|
|
284
|
+
const res = await fetch(`${QR_API_URL}/folder/create`, {
|
|
285
|
+
method: "POST",
|
|
286
|
+
headers: getAuthHeaders(),
|
|
287
|
+
body: JSON.stringify({ folderName, parentId, visibleToAll, left, right, level, position }),
|
|
288
|
+
});
|
|
289
|
+
const data = await res.json();
|
|
290
|
+
|
|
291
|
+
if (res.ok) {
|
|
292
|
+
return {
|
|
293
|
+
content: [{
|
|
294
|
+
type: "text",
|
|
295
|
+
text: `✅ Folder created successfully!\n\nName: ${folderName}\n\n${JSON.stringify(data, null, 2)}`,
|
|
296
|
+
}],
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
content: [{
|
|
301
|
+
type: "text",
|
|
302
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
303
|
+
}],
|
|
304
|
+
isError: true,
|
|
305
|
+
};
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
qr_rename_folder: async ({ folderId, folderName }) => {
|
|
309
|
+
const authError = requireLogin();
|
|
310
|
+
if (authError) return authError;
|
|
311
|
+
|
|
312
|
+
const res = await fetch(`${QR_API_URL}/folder/rnnode`, {
|
|
313
|
+
method: "POST",
|
|
314
|
+
headers: getAuthHeaders(),
|
|
315
|
+
body: JSON.stringify({ folderId, folderName }),
|
|
316
|
+
});
|
|
317
|
+
const data = await res.json();
|
|
318
|
+
|
|
319
|
+
if (res.ok) {
|
|
320
|
+
return {
|
|
321
|
+
content: [{
|
|
322
|
+
type: "text",
|
|
323
|
+
text: `✅ Folder renamed successfully!\n\nNew name: ${folderName}`,
|
|
324
|
+
}],
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
content: [{
|
|
329
|
+
type: "text",
|
|
330
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
331
|
+
}],
|
|
332
|
+
isError: true,
|
|
333
|
+
};
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
qr_trash_folder: async ({ folderId }) => {
|
|
337
|
+
const authError = requireLogin();
|
|
338
|
+
if (authError) return authError;
|
|
339
|
+
|
|
340
|
+
const res = await fetch(`${QR_API_URL}/folder/trash`, {
|
|
341
|
+
method: "POST",
|
|
342
|
+
headers: getAuthHeaders(),
|
|
343
|
+
body: JSON.stringify({ folderId }),
|
|
344
|
+
});
|
|
345
|
+
const data = await res.json();
|
|
346
|
+
|
|
347
|
+
if (res.ok) {
|
|
348
|
+
return {
|
|
349
|
+
content: [{
|
|
350
|
+
type: "text",
|
|
351
|
+
text: `✅ Folder(s) moved to trash!\n\nFolder IDs: ${folderId.join(", ")}`,
|
|
352
|
+
}],
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
content: [{
|
|
357
|
+
type: "text",
|
|
358
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
359
|
+
}],
|
|
360
|
+
isError: true,
|
|
361
|
+
};
|
|
362
|
+
},
|
|
363
|
+
|
|
364
|
+
qr_delete_folder: async ({ folderId }) => {
|
|
365
|
+
const authError = requireLogin();
|
|
366
|
+
if (authError) return authError;
|
|
367
|
+
|
|
368
|
+
const res = await fetch(`${QR_API_URL}/folder/delete`, {
|
|
369
|
+
method: "POST",
|
|
370
|
+
headers: getAuthHeaders(),
|
|
371
|
+
body: JSON.stringify({ folderId }),
|
|
372
|
+
});
|
|
373
|
+
const data = await res.json();
|
|
374
|
+
|
|
375
|
+
if (res.ok) {
|
|
376
|
+
return {
|
|
377
|
+
content: [{
|
|
378
|
+
type: "text",
|
|
379
|
+
text: `✅ Folder(s) deleted permanently!\n\nFolder IDs: ${folderId.join(", ")}`,
|
|
380
|
+
}],
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
content: [{
|
|
385
|
+
type: "text",
|
|
386
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
387
|
+
}],
|
|
388
|
+
isError: true,
|
|
389
|
+
};
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
qr_share_folder: async ({ folderId, shareEmail, shareAction, download, anybody }) => {
|
|
393
|
+
const authError = requireLogin();
|
|
394
|
+
if (authError) return authError;
|
|
395
|
+
|
|
396
|
+
const res = await fetch(`${QR_API_URL}/folder/share`, {
|
|
397
|
+
method: "POST",
|
|
398
|
+
headers: getAuthHeaders(),
|
|
399
|
+
body: JSON.stringify({ folderId, shareEmail, shareAction, download, anybody }),
|
|
400
|
+
});
|
|
401
|
+
const data = await res.json();
|
|
402
|
+
|
|
403
|
+
if (res.ok) {
|
|
404
|
+
return {
|
|
405
|
+
content: [{
|
|
406
|
+
type: "text",
|
|
407
|
+
text:
|
|
408
|
+
`✅ Folder shared successfully!\n\n` +
|
|
409
|
+
`Shared with: ${shareEmail}\n` +
|
|
410
|
+
`Permission: ${shareAction}\n` +
|
|
411
|
+
`Download allowed: ${download === 1 ? "Yes" : "No"}`,
|
|
412
|
+
}],
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
content: [{
|
|
417
|
+
type: "text",
|
|
418
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
419
|
+
}],
|
|
420
|
+
isError: true,
|
|
421
|
+
};
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
qr_get_trashed_folders: async ({ folderId = 0 }) => {
|
|
425
|
+
const authError = requireLogin();
|
|
426
|
+
if (authError) return authError;
|
|
427
|
+
|
|
428
|
+
const res = await fetch(`${QR_API_URL}/trashed-folder`, {
|
|
429
|
+
method: "POST",
|
|
430
|
+
headers: getAuthHeaders(),
|
|
431
|
+
body: JSON.stringify({ folderId }),
|
|
432
|
+
});
|
|
433
|
+
const data = await res.json();
|
|
434
|
+
|
|
435
|
+
if (res.ok) {
|
|
436
|
+
const items = Array.isArray(data) ? data : (data.rows || []);
|
|
437
|
+
return {
|
|
438
|
+
content: [{
|
|
439
|
+
type: "text",
|
|
440
|
+
text: `✅ Trashed folders fetched (${items.length} items)\n\n${JSON.stringify(data, null, 2)}`,
|
|
441
|
+
}],
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
return {
|
|
445
|
+
content: [{
|
|
446
|
+
type: "text",
|
|
447
|
+
text: `❌ Failed (HTTP ${res.status})\n\n${JSON.stringify(data, null, 2)}`,
|
|
448
|
+
}],
|
|
449
|
+
isError: true,
|
|
450
|
+
};
|
|
451
|
+
},
|
|
452
|
+
|
|
453
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// QUICKREVIEWER PLUGIN — Main entry point
|
|
3
|
+
// Sab domain files ko combine karta hai
|
|
4
|
+
// Naya domain add karna ho to:
|
|
5
|
+
// 1. Nayi file banao (e.g. jira.js)
|
|
6
|
+
// 2. Yahan import karo aur spread karo
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
import { tools as authTools, handlers as authHandlers } from "./auth.js";
|
|
10
|
+
import { tools as documentTools, handlers as documentHandlers } from "./documents.js";
|
|
11
|
+
import { tools as folderTools, handlers as folderHandlers } from "./folders.js";
|
|
12
|
+
import { tools as workflowTools, handlers as workflowHandlers } from "./workflows.js";
|
|
13
|
+
import { tools as teamTools, handlers as teamHandlers } from "./teams.js";
|
|
14
|
+
import { tools as uploadTools, handlers as uploadHandlers } from "./upload.js";
|
|
15
|
+
|
|
16
|
+
export const tools = [
|
|
17
|
+
...authTools,
|
|
18
|
+
...documentTools,
|
|
19
|
+
...folderTools,
|
|
20
|
+
...workflowTools,
|
|
21
|
+
...teamTools,
|
|
22
|
+
...uploadTools,
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export const handlers = {
|
|
26
|
+
...authHandlers,
|
|
27
|
+
...documentHandlers,
|
|
28
|
+
...folderHandlers,
|
|
29
|
+
...workflowHandlers,
|
|
30
|
+
...teamHandlers,
|
|
31
|
+
...uploadHandlers,
|
|
32
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// SESSION — Shared in-memory token store
|
|
3
|
+
// Sab plugin files yahan se import karti hain
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
export const session = {
|
|
7
|
+
token: null,
|
|
8
|
+
userId: null,
|
|
9
|
+
userName: null,
|
|
10
|
+
userEmail: null,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function getAuthHeaders() {
|
|
14
|
+
const baseUrl = (process.env.QR_API_URL || "https://app.quickreviewer.com/api").replace('/api', '');
|
|
15
|
+
return {
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
"Referer": `${baseUrl}/`,
|
|
18
|
+
...(session.token && { Authorization: `AUTH ${session.token}` }),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function requireLogin() {
|
|
23
|
+
if (!session.token) {
|
|
24
|
+
return {
|
|
25
|
+
content: [{ type: "text", text: "❌ Not logged in. Please call qr_login first." }],
|
|
26
|
+
isError: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return null; // null means logged in — proceed
|
|
30
|
+
}
|