OhMyDitzzy commited on
Commit
83f446a
·
1 Parent(s): f535bab

disabled: komiku

Browse files
src/components/PluginCard.tsx CHANGED
@@ -6,7 +6,7 @@ import { Input } from "@/components/ui/input";
6
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
7
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
8
  import { PluginMetadata } from "@/client/hooks/usePlugin";
9
- import { Play, ChevronDown, ChevronUp, Copy, Check } from "lucide-react";
10
  import { CodeBlock } from "@/components/CodeBlock";
11
  import { getApiUrl } from "@/lib/api-url";
12
 
@@ -32,11 +32,27 @@ export function PluginCard({ plugin }: PluginCardProps) {
32
  const [copiedUrl, setCopiedUrl] = useState(false);
33
  const [copiedRequestUrl, setCopiedRequestUrl] = useState(false);
34
 
 
 
 
35
  const handleParamChange = (paramName: string, value: string) => {
36
  setParamValues((prev) => ({ ...prev, [paramName]: value }));
37
  };
38
 
39
  const handleExecute = async () => {
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  setLoading(true);
41
 
42
  try {
@@ -123,8 +139,9 @@ export function PluginCard({ plugin }: PluginCardProps) {
123
  <Select
124
  value={paramValues[param.name] || ""}
125
  onValueChange={(value) => handleParamChange(param.name, value)}
 
126
  >
127
- <SelectTrigger className="bg-black/50 border-white/10 text-white focus:border-purple-500">
128
  <SelectValue placeholder={`Select ${param.name}...`} />
129
  </SelectTrigger>
130
  <SelectContent className="bg-zinc-900 border-white/10">
@@ -147,7 +164,8 @@ export function PluginCard({ plugin }: PluginCardProps) {
147
  placeholder={param.example?.toString() || param.description}
148
  value={paramValues[param.name] || ""}
149
  onChange={(e) => handleParamChange(param.name, e.target.value)}
150
- className="bg-black/50 border-white/10 text-white focus:border-purple-500"
 
151
  />
152
  );
153
  }
@@ -210,7 +228,7 @@ export function PluginCard({ plugin }: PluginCardProps) {
210
  };
211
 
212
  return (
213
- <Card className="bg-white/[0.02] border-white/10 overflow-hidden w-full">
214
  {/* Collapsible Header */}
215
  <div
216
  className="p-4 border-b border-white/10 cursor-pointer hover:bg-white/[0.02] transition-colors"
@@ -221,6 +239,21 @@ export function PluginCard({ plugin }: PluginCardProps) {
221
  {plugin.method}
222
  </Badge>
223
  <code className="text-sm text-purple-400 font-mono flex-1 min-w-0 break-all">{plugin.endpoint}</code>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  <div className="flex items-center gap-1 flex-shrink-0">
225
  <button
226
  onClick={(e) => {
@@ -257,6 +290,27 @@ export function PluginCard({ plugin }: PluginCardProps) {
257
  <h3 className="text-xl font-bold text-white mb-2">{plugin.name}</h3>
258
  <p className="text-gray-400 text-sm leading-relaxed">{plugin.description || "No description provided"}</p>
259
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  {/* Tags */}
261
  {plugin.tags && plugin.tags.length > 0 && (
262
  <div className="flex flex-wrap gap-2 mt-3">
@@ -313,7 +367,6 @@ export function PluginCard({ plugin }: PluginCardProps) {
313
  </tr>
314
  </thead>
315
  <tbody>
316
- {/* Path Parameters */}
317
  {plugin.parameters?.path?.map((param) => (
318
  <tr key={param.name} className="border-b border-white/5">
319
  <td className="py-3 pr-4 text-white font-mono">{param.name}</td>
@@ -333,7 +386,6 @@ export function PluginCard({ plugin }: PluginCardProps) {
333
  <td className="py-3 text-gray-400">{param.description}</td>
334
  </tr>
335
  ))}
336
- {/* Query Parameters */}
337
  {plugin.parameters?.query?.map((param) => (
338
  <tr key={param.name} className="border-b border-white/5">
339
  <td className="py-3 pr-4 text-white font-mono">{param.name}</td>
@@ -353,7 +405,6 @@ export function PluginCard({ plugin }: PluginCardProps) {
353
  <td className="py-3 text-gray-400">{param.description}</td>
354
  </tr>
355
  ))}
356
- {/* Body Parameters */}
357
  {plugin.parameters?.body?.map((param) => (
358
  <tr key={param.name} className="border-b border-white/5">
359
  <td className="py-3 pr-4 text-white font-mono">{param.name}</td>
@@ -439,7 +490,6 @@ export function PluginCard({ plugin }: PluginCardProps) {
439
  {/* Parameters Input */}
440
  {hasAnyParams ? (
441
  <div className="space-y-4 mb-4">
442
- {/* Query Parameters */}
443
  {plugin.parameters?.query?.map((param) => (
444
  <div key={param.name}>
445
  <label className="block text-sm text-gray-300 mb-2">
@@ -457,7 +507,6 @@ export function PluginCard({ plugin }: PluginCardProps) {
457
  </div>
458
  ))}
459
 
460
- {/* Body Parameters */}
461
  {plugin.parameters?.body?.map((param) => (
462
  <div key={param.name}>
463
  <label className="block text-sm text-gray-300 mb-2">
@@ -482,36 +531,51 @@ export function PluginCard({ plugin }: PluginCardProps) {
482
  {/* Execute Button */}
483
  <Button
484
  onClick={handleExecute}
485
- disabled={loading}
486
- className="w-full bg-purple-500 hover:bg-purple-600 text-white py-6 text-base font-semibold"
487
  >
488
  <Play className="w-5 h-5 mr-2" />
489
- {loading ? "Executing..." : "Execute"}
490
  </Button>
491
 
492
  {/* Response Display */}
493
  {response && (
494
  <div className="mt-6 space-y-4">
495
- {/* Request URL */}
496
- <div>
497
- <div className="flex items-center justify-between mb-2">
498
- <span className="text-sm text-gray-400">Request URL</span>
499
- <button
500
- onClick={copyRequestUrl}
501
- className="text-gray-400 hover:text-white transition-colors p-1"
502
- title="Copy Request URL"
503
- >
504
- {copiedRequestUrl ? (
505
- <Check className="w-4 h-4 text-green-400" />
506
- ) : (
507
- <Copy className="w-4 h-4" />
508
- )}
509
- </button>
510
  </div>
511
- <div className="bg-black/50 border border-white/10 rounded p-3 overflow-x-auto">
512
- <code className="text-xs text-purple-300 break-all">{requestUrl}</code>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
  </div>
514
- </div>
515
 
516
  {/* Response Status */}
517
  <div className="flex items-center justify-between">
@@ -539,7 +603,7 @@ export function PluginCard({ plugin }: PluginCardProps) {
539
  </div>
540
  )}
541
 
542
- {/* Response Body with Syntax Highlighting */}
543
  <div>
544
  <h5 className="text-sm text-gray-400 mb-2">Response Body</h5>
545
  <CodeBlock
 
6
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
7
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
8
  import { PluginMetadata } from "@/client/hooks/usePlugin";
9
+ import { Play, ChevronDown, ChevronUp, Copy, Check, AlertTriangle, XCircle } from "lucide-react";
10
  import { CodeBlock } from "@/components/CodeBlock";
11
  import { getApiUrl } from "@/lib/api-url";
12
 
 
32
  const [copiedUrl, setCopiedUrl] = useState(false);
33
  const [copiedRequestUrl, setCopiedRequestUrl] = useState(false);
34
 
35
+ const isDisabled = plugin.disabled;
36
+ const isDeprecated = plugin.deprecated;
37
+
38
  const handleParamChange = (paramName: string, value: string) => {
39
  setParamValues((prev) => ({ ...prev, [paramName]: value }));
40
  };
41
 
42
  const handleExecute = async () => {
43
+ if (isDisabled) {
44
+ setResponse({
45
+ status: 503,
46
+ statusText: "Service Unavailable",
47
+ data: {
48
+ success: false,
49
+ message: "Plugin is disabled",
50
+ reason: plugin.disabledReason || "This plugin has been disabled"
51
+ }
52
+ });
53
+ return;
54
+ }
55
+
56
  setLoading(true);
57
 
58
  try {
 
139
  <Select
140
  value={paramValues[param.name] || ""}
141
  onValueChange={(value) => handleParamChange(param.name, value)}
142
+ disabled={isDisabled}
143
  >
144
+ <SelectTrigger className="bg-black/50 border-white/10 text-white focus:border-purple-500 disabled:opacity-50">
145
  <SelectValue placeholder={`Select ${param.name}...`} />
146
  </SelectTrigger>
147
  <SelectContent className="bg-zinc-900 border-white/10">
 
164
  placeholder={param.example?.toString() || param.description}
165
  value={paramValues[param.name] || ""}
166
  onChange={(e) => handleParamChange(param.name, e.target.value)}
167
+ disabled={isDisabled}
168
+ className="bg-black/50 border-white/10 text-white focus:border-purple-500 disabled:opacity-50"
169
  />
170
  );
171
  }
 
228
  };
229
 
230
  return (
231
+ <Card className={`bg-white/[0.02] border-white/10 overflow-hidden w-full ${isDisabled ? 'opacity-60' : ''}`}>
232
  {/* Collapsible Header */}
233
  <div
234
  className="p-4 border-b border-white/10 cursor-pointer hover:bg-white/[0.02] transition-colors"
 
239
  {plugin.method}
240
  </Badge>
241
  <code className="text-sm text-purple-400 font-mono flex-1 min-w-0 break-all">{plugin.endpoint}</code>
242
+
243
+ {/* Status Badges */}
244
+ {isDisabled && (
245
+ <Badge className="bg-red-500/20 text-red-400 border-red-500/50 border flex items-center gap-1 flex-shrink-0">
246
+ <XCircle className="w-3 h-3" />
247
+ Disabled
248
+ </Badge>
249
+ )}
250
+ {isDeprecated && !isDisabled && (
251
+ <Badge className="bg-yellow-500/20 text-yellow-400 border-yellow-500/50 border flex items-center gap-1 flex-shrink-0">
252
+ <AlertTriangle className="w-3 h-3" />
253
+ Deprecated
254
+ </Badge>
255
+ )}
256
+
257
  <div className="flex items-center gap-1 flex-shrink-0">
258
  <button
259
  onClick={(e) => {
 
290
  <h3 className="text-xl font-bold text-white mb-2">{plugin.name}</h3>
291
  <p className="text-gray-400 text-sm leading-relaxed">{plugin.description || "No description provided"}</p>
292
 
293
+ {/* Disabled/Deprecated Warnings */}
294
+ {isDisabled && plugin.disabledReason && (
295
+ <div className="mt-3 p-3 bg-red-500/10 border border-red-500/30 rounded-lg flex items-start gap-2">
296
+ <XCircle className="w-5 h-5 text-red-400 flex-shrink-0 mt-0.5" />
297
+ <div>
298
+ <p className="text-sm font-semibold text-red-400">Plugin Disabled</p>
299
+ <p className="text-xs text-red-300 mt-1">{plugin.disabledReason}</p>
300
+ </div>
301
+ </div>
302
+ )}
303
+
304
+ {isDeprecated && !isDisabled && plugin.deprecatedReason && (
305
+ <div className="mt-3 p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-lg flex items-start gap-2">
306
+ <AlertTriangle className="w-5 h-5 text-yellow-400 flex-shrink-0 mt-0.5" />
307
+ <div>
308
+ <p className="text-sm font-semibold text-yellow-400">Plugin Deprecated</p>
309
+ <p className="text-xs text-yellow-300 mt-1">{plugin.deprecatedReason}</p>
310
+ </div>
311
+ </div>
312
+ )}
313
+
314
  {/* Tags */}
315
  {plugin.tags && plugin.tags.length > 0 && (
316
  <div className="flex flex-wrap gap-2 mt-3">
 
367
  </tr>
368
  </thead>
369
  <tbody>
 
370
  {plugin.parameters?.path?.map((param) => (
371
  <tr key={param.name} className="border-b border-white/5">
372
  <td className="py-3 pr-4 text-white font-mono">{param.name}</td>
 
386
  <td className="py-3 text-gray-400">{param.description}</td>
387
  </tr>
388
  ))}
 
389
  {plugin.parameters?.query?.map((param) => (
390
  <tr key={param.name} className="border-b border-white/5">
391
  <td className="py-3 pr-4 text-white font-mono">{param.name}</td>
 
405
  <td className="py-3 text-gray-400">{param.description}</td>
406
  </tr>
407
  ))}
 
408
  {plugin.parameters?.body?.map((param) => (
409
  <tr key={param.name} className="border-b border-white/5">
410
  <td className="py-3 pr-4 text-white font-mono">{param.name}</td>
 
490
  {/* Parameters Input */}
491
  {hasAnyParams ? (
492
  <div className="space-y-4 mb-4">
 
493
  {plugin.parameters?.query?.map((param) => (
494
  <div key={param.name}>
495
  <label className="block text-sm text-gray-300 mb-2">
 
507
  </div>
508
  ))}
509
 
 
510
  {plugin.parameters?.body?.map((param) => (
511
  <div key={param.name}>
512
  <label className="block text-sm text-gray-300 mb-2">
 
531
  {/* Execute Button */}
532
  <Button
533
  onClick={handleExecute}
534
+ disabled={loading || isDisabled}
535
+ className="w-full bg-purple-500 hover:bg-purple-600 text-white py-6 text-base font-semibold disabled:opacity-50 disabled:cursor-not-allowed"
536
  >
537
  <Play className="w-5 h-5 mr-2" />
538
+ {loading ? "Executing..." : isDisabled ? "Plugin Disabled" : "Execute"}
539
  </Button>
540
 
541
  {/* Response Display */}
542
  {response && (
543
  <div className="mt-6 space-y-4">
544
+ {/* Deprecation Warning in Response */}
545
+ {isDeprecated && responseHeaders['x-plugin-deprecated'] && (
546
+ <div className="p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-lg flex items-start gap-2">
547
+ <AlertTriangle className="w-5 h-5 text-yellow-400 flex-shrink-0 mt-0.5" />
548
+ <div>
549
+ <p className="text-sm font-semibold text-yellow-400">Deprecation Warning</p>
550
+ <p className="text-xs text-yellow-300 mt-1">
551
+ {responseHeaders['x-deprecation-reason'] || 'This plugin is deprecated'}
552
+ </p>
553
+ </div>
 
 
 
 
 
554
  </div>
555
+ )}
556
+
557
+ {/* Request URL */}
558
+ {requestUrl && (
559
+ <div>
560
+ <div className="flex items-center justify-between mb-2">
561
+ <span className="text-sm text-gray-400">Request URL</span>
562
+ <button
563
+ onClick={copyRequestUrl}
564
+ className="text-gray-400 hover:text-white transition-colors p-1"
565
+ title="Copy Request URL"
566
+ >
567
+ {copiedRequestUrl ? (
568
+ <Check className="w-4 h-4 text-green-400" />
569
+ ) : (
570
+ <Copy className="w-4 h-4" />
571
+ )}
572
+ </button>
573
+ </div>
574
+ <div className="bg-black/50 border border-white/10 rounded p-3 overflow-x-auto">
575
+ <code className="text-xs text-purple-300 break-all">{requestUrl}</code>
576
+ </div>
577
  </div>
578
+ )}
579
 
580
  {/* Response Status */}
581
  <div className="flex items-center justify-between">
 
603
  </div>
604
  )}
605
 
606
+ {/* Response Body */}
607
  <div>
608
  <h5 className="text-sm text-gray-400 mb-2">Response Body</h5>
609
  <CodeBlock
src/server/plugin-loader.ts CHANGED
@@ -43,7 +43,7 @@ export class PluginLoader {
43
  let reloadTimeout: NodeJS.Timeout | null = null;
44
 
45
  this.watcher = watch(this.pluginsDir, {
46
- ignored: /(^|[\/\\])\../, // ignore dotfiles
47
  persistent: true,
48
  ignoreInitial: true,
49
  awaitWriteFinish: {
@@ -87,7 +87,6 @@ export class PluginLoader {
87
  try {
88
  await this.scanDirectory(this.pluginsDir, newRouter);
89
 
90
- // If successful, replace old router with new one
91
  this.removeOldRouter();
92
  this.router = newRouter;
93
  this.app.use("/api", this.router);
@@ -109,7 +108,6 @@ export class PluginLoader {
109
  if (!this.app) return;
110
 
111
  try {
112
- // Express 5 uses app._router differently
113
  const stack = (this.app as any)._router?.stack || [];
114
 
115
  for (let i = stack.length - 1; i >= 0; i--) {
@@ -119,7 +117,6 @@ export class PluginLoader {
119
  }
120
  }
121
  } catch (error) {
122
- // if _router structure is different, just log warning
123
  console.warn("⚠️ Could not remove old router, continuing anyway...");
124
  }
125
  }
@@ -136,10 +133,6 @@ export class PluginLoader {
136
  if (stat.isDirectory()) {
137
  this.clearModuleCache(fullPath);
138
  } else if (stat.isFile() && (extname(item) === ".ts" || extname(item) === ".js")) {
139
- // In ES modules, we can't clear cache like CommonJS.
140
- // Hot Reload also doesn't seem to have any effect on API serving.
141
- // For now, Just log and mark as reload, We have to restart the server in "development" mode.
142
- // TODO: Find another way. If hot reloading doesn't work, try restarting automatically.
143
  const relativePath = relative(process.cwd(), fullPath);
144
  console.log(`♻️ Marked for reload: ${relativePath}`);
145
  }
@@ -207,6 +200,17 @@ export class PluginLoader {
207
  return;
208
  }
209
 
 
 
 
 
 
 
 
 
 
 
 
210
  const metadataValidation = this.isValidPluginMetadata(handler, fileName);
211
  const shouldShowInDocs = metadataValidation.valid;
212
 
@@ -222,7 +226,26 @@ export class PluginLoader {
222
  const primaryEndpoint = basePath ? `${basePath}/${primaryAlias}` : `/${primaryAlias}`;
223
  const method = handler.method.toLowerCase() as "get" | "post" | "put" | "delete" | "patch";
224
 
 
225
  const wrappedExec = async (req: any, res: any, next: any) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  try {
227
  await handler.exec(req, res, next);
228
  } catch (error) {
@@ -241,7 +264,9 @@ export class PluginLoader {
241
  for (const alias of handler.alias) {
242
  const endpoint = basePath ? `${basePath}/${alias}` : `/${alias}`;
243
  router[method](endpoint, wrappedExec);
244
- console.log(`✓ [${handler.method}] ${endpoint} -> ${handler.name || 'unnamed'}`);
 
 
245
  }
246
 
247
  if (shouldShowInDocs) {
@@ -260,7 +285,11 @@ export class PluginLoader {
260
  headers: [],
261
  path: []
262
  },
263
- responses: handler.responses || {}
 
 
 
 
264
  };
265
 
266
  this.pluginRegistry[primaryEndpoint] = { handler, metadata };
 
43
  let reloadTimeout: NodeJS.Timeout | null = null;
44
 
45
  this.watcher = watch(this.pluginsDir, {
46
+ ignored: /(^|[\/\\])\../,
47
  persistent: true,
48
  ignoreInitial: true,
49
  awaitWriteFinish: {
 
87
  try {
88
  await this.scanDirectory(this.pluginsDir, newRouter);
89
 
 
90
  this.removeOldRouter();
91
  this.router = newRouter;
92
  this.app.use("/api", this.router);
 
108
  if (!this.app) return;
109
 
110
  try {
 
111
  const stack = (this.app as any)._router?.stack || [];
112
 
113
  for (let i = stack.length - 1; i >= 0; i--) {
 
117
  }
118
  }
119
  } catch (error) {
 
120
  console.warn("⚠️ Could not remove old router, continuing anyway...");
121
  }
122
  }
 
133
  if (stat.isDirectory()) {
134
  this.clearModuleCache(fullPath);
135
  } else if (stat.isFile() && (extname(item) === ".ts" || extname(item) === ".js")) {
 
 
 
 
136
  const relativePath = relative(process.cwd(), fullPath);
137
  console.log(`♻️ Marked for reload: ${relativePath}`);
138
  }
 
200
  return;
201
  }
202
 
203
+ if (handler.disabled) {
204
+ const reason = handler.disabledReason || "This plugin has been disabled";
205
+ console.log(`🚫 Plugin '${handler.name}' is disabled: ${reason}`);
206
+ // Still register it but with disabled flag
207
+ }
208
+
209
+ if (handler.deprecated) {
210
+ const reason = handler.deprecatedReason || "This plugin is deprecated and may be removed in future versions";
211
+ console.warn(`⚠️ Plugin '${handler.name}' is deprecated: ${reason}`);
212
+ }
213
+
214
  const metadataValidation = this.isValidPluginMetadata(handler, fileName);
215
  const shouldShowInDocs = metadataValidation.valid;
216
 
 
226
  const primaryEndpoint = basePath ? `${basePath}/${primaryAlias}` : `/${primaryAlias}`;
227
  const method = handler.method.toLowerCase() as "get" | "post" | "put" | "delete" | "patch";
228
 
229
+ // Wrap exec function to handle disabled/deprecated plugins
230
  const wrappedExec = async (req: any, res: any, next: any) => {
231
+ // If plugin is disabled, return error response
232
+ if (handler.disabled) {
233
+ const reason = handler.disabledReason || "This plugin has been disabled";
234
+ return res.status(503).json({
235
+ success: false,
236
+ message: "Plugin is disabled",
237
+ reason: reason,
238
+ plugin: handler.name || 'unknown',
239
+ });
240
+ }
241
+
242
+ // If plugin is deprecated, add warning header
243
+ if (handler.deprecated) {
244
+ const reason = handler.deprecatedReason || "This plugin is deprecated and may be removed in future versions";
245
+ res.setHeader('X-Plugin-Deprecated', 'true');
246
+ res.setHeader('X-Deprecation-Reason', reason);
247
+ }
248
+
249
  try {
250
  await handler.exec(req, res, next);
251
  } catch (error) {
 
264
  for (const alias of handler.alias) {
265
  const endpoint = basePath ? `${basePath}/${alias}` : `/${alias}`;
266
  router[method](endpoint, wrappedExec);
267
+
268
+ const statusIcon = handler.disabled ? '🚫' : handler.deprecated ? '⚠️' : '✓';
269
+ console.log(`${statusIcon} [${handler.method}] ${endpoint} -> ${handler.name || 'unnamed'}`);
270
  }
271
 
272
  if (shouldShowInDocs) {
 
285
  headers: [],
286
  path: []
287
  },
288
+ responses: handler.responses || {},
289
+ disabled: handler.disabled,
290
+ deprecated: handler.deprecated,
291
+ disabledReason: handler.disabledReason,
292
+ deprecatedReason: handler.deprecatedReason
293
  };
294
 
295
  this.pluginRegistry[primaryEndpoint] = { handler, metadata };
src/server/plugins/anime/komiku_get_details.js CHANGED
@@ -9,6 +9,8 @@ const handler = {
9
  category: ["komiku"],
10
  alias: ["getDetail"],
11
  tags: ["comic"],
 
 
12
  parameters: {
13
  query: [
14
  {
 
9
  category: ["komiku"],
10
  alias: ["getDetail"],
11
  tags: ["comic"],
12
+ disabled: true,
13
+ disabledReason: "Komiku server is temporarily unavailable, Maybe this feature will not be removed until the server is back.",
14
  parameters: {
15
  query: [
16
  {
src/server/plugins/anime/komiku_get_manga.js CHANGED
@@ -9,6 +9,8 @@ const handler = {
9
  category: ["komiku"],
10
  alias: ["getLatestManga"],
11
  tags: ["comic"],
 
 
12
  responses: {
13
  200: {
14
  status: 200,
 
9
  category: ["komiku"],
10
  alias: ["getLatestManga"],
11
  tags: ["comic"],
12
+ disabled: true,
13
+ disabledReason: "Komiku server is temporarily unavailable, Maybe this feature will not be removed until the server is back.",
14
  responses: {
15
  200: {
16
  status: 200,
src/server/plugins/anime/komiku_get_manhua.js CHANGED
@@ -9,6 +9,8 @@ const handler = {
9
  category: ["komiku"],
10
  alias: ["getLatestManhua"],
11
  tags: ["comic"],
 
 
12
  responses: {
13
  200: {
14
  status: 200,
 
9
  category: ["komiku"],
10
  alias: ["getLatestManhua"],
11
  tags: ["comic"],
12
+ disabled: true,
13
+ disabledReason: "Komiku server is temporarily unavailable, Maybe this feature will not be removed until the server is back.",
14
  responses: {
15
  200: {
16
  status: 200,
src/server/plugins/anime/komiku_get_manhwa.js CHANGED
@@ -9,6 +9,8 @@ const handler = {
9
  category: ["komiku"],
10
  alias: ["getLatestManhwa"],
11
  tags: ["comic"],
 
 
12
  responses: {
13
  200: {
14
  status: 200,
 
9
  category: ["komiku"],
10
  alias: ["getLatestManhwa"],
11
  tags: ["comic"],
12
+ disabled: true,
13
+ disabledReason: "Komiku server is temporarily unavailable, Maybe this feature will not be removed until the server is back.",
14
  responses: {
15
  200: {
16
  status: 200,
src/server/plugins/anime/komiku_read_chapter.js CHANGED
@@ -9,6 +9,8 @@ const handler = {
9
  category: ["komiku"],
10
  alias: ["readChapter"],
11
  tags: ["comic"],
 
 
12
  parameters: {
13
  query: [
14
  {
 
9
  category: ["komiku"],
10
  alias: ["readChapter"],
11
  tags: ["comic"],
12
+ disabled: true,
13
+ disabledReason: "Komiku server is temporarily unavailable, Maybe this feature will not be removed until the server is back.",
14
  parameters: {
15
  query: [
16
  {
src/server/plugins/anime/komiku_search.js CHANGED
@@ -9,6 +9,8 @@ const handler = {
9
  category: ["komiku"],
10
  alias: ["search"],
11
  tags: ["comic"],
 
 
12
  parameters: {
13
  query: [
14
  {
 
9
  category: ["komiku"],
10
  alias: ["search"],
11
  tags: ["comic"],
12
+ disabled: true,
13
+ disabledReason: "Komiku server is temporarily unavailable, Maybe this feature will not be removed until the server is back.",
14
  parameters: {
15
  query: [
16
  {
src/server/types/plugin.ts CHANGED
@@ -27,17 +27,21 @@ export interface PluginParameters {
27
  export interface ApiPluginHandler {
28
  name: string;
29
  description: string;
30
- version: string;
31
  category: string[];
32
  method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
33
  alias: string[];
34
- tags?: string[];
35
  parameters?: PluginParameters;
36
  responses?: {
37
  [statusCode: number]: PluginResponse;
38
  };
39
-
40
- exec: (req: Request, res: Response, next: NextFunction) => Promise<any> | any;
 
 
 
 
41
  }
42
 
43
  export interface PluginMetadata {
@@ -53,6 +57,10 @@ export interface PluginMetadata {
53
  responses?: {
54
  [statusCode: number]: PluginResponse;
55
  };
 
 
 
 
56
  }
57
 
58
  export interface PluginRegistry {
@@ -60,13 +68,4 @@ export interface PluginRegistry {
60
  handler: ApiPluginHandler;
61
  metadata: PluginMetadata;
62
  };
63
- }
64
-
65
- export interface ApiResponse<T = any> {
66
- status: number;
67
- message?: string;
68
- author?: string;
69
- note?: string;
70
- results?: T;
71
- error?: string;
72
  }
 
27
  export interface ApiPluginHandler {
28
  name: string;
29
  description: string;
30
+ version?: string;
31
  category: string[];
32
  method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
33
  alias: string[];
34
+ tags?: string[];
35
  parameters?: PluginParameters;
36
  responses?: {
37
  [statusCode: number]: PluginResponse;
38
  };
39
+ disabled?: boolean;
40
+ deprecated?: boolean;
41
+ disabledReason?: string;
42
+ deprecatedReason?: string;
43
+
44
+ exec: (req: Request, res: Response, next: NextFunction) => Promise<void> | void;
45
  }
46
 
47
  export interface PluginMetadata {
 
57
  responses?: {
58
  [statusCode: number]: PluginResponse;
59
  };
60
+ disabled?: boolean;
61
+ deprecated?: boolean;
62
+ disabledReason?: string;
63
+ deprecatedReason?: string;
64
  }
65
 
66
  export interface PluginRegistry {
 
68
  handler: ApiPluginHandler;
69
  metadata: PluginMetadata;
70
  };
 
 
 
 
 
 
 
 
 
71
  }