mirror of
https://github.com/mountain-loop/yaak.git
synced 2025-12-05 19:17:44 -06:00
Better plugin development experience (#118)
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
src-tauri/vendored/**/* linguist-generated=true
|
||||
src-tauri/gen/schemas/**/* linguist-generated=true
|
||||
@@ -22,12 +22,6 @@ npm -v
|
||||
rustc --version
|
||||
```
|
||||
|
||||
Clone the [plugins repository](https://github.com/yaakapp/plugins) to your machine:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/yaakapp/plugins.git /path/to/your/plugins-directory
|
||||
```
|
||||
|
||||
Install the NPM dependencies:
|
||||
|
||||
```shell
|
||||
@@ -40,6 +34,8 @@ Run the `bootstrap` command to do some initial setup:
|
||||
npm run bootstrap
|
||||
```
|
||||
|
||||
_NOTE: Run with `YAAK_PLUGINS_DIR=<Path to yaakapp/plugins>` to re-build bundled plugins_
|
||||
|
||||
## Run the App
|
||||
|
||||
After bootstrapping, start the app in development mode:
|
||||
@@ -48,6 +44,8 @@ After bootstrapping, start the app in development mode:
|
||||
npm start
|
||||
```
|
||||
|
||||
_NOTE: If working on bundled plugins, run with `YAAK_PLUGINS_DIR=<Path to yaakapp/plugins>`_
|
||||
|
||||
## SQLite Migrations
|
||||
|
||||
New migrations can be created from the `src-tauri/` directory:
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { HttpRequest } from "./models";
|
||||
import type { HttpResponse } from "./models";
|
||||
import type { Workspace } from "./models";
|
||||
|
||||
export type BootRequest = { dir: string, };
|
||||
export type BootRequest = { dir: string, watch: boolean, };
|
||||
|
||||
export type BootResponse = { name: string, version: string, capabilities: Array<string>, };
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { InternalEvent } from '@yaakapp/api';
|
||||
import { BootRequest, InternalEvent } from '@yaakapp-internal/plugin';
|
||||
import path from 'node:path';
|
||||
import { Worker } from 'node:worker_threads';
|
||||
import { EventChannel } from './EventChannel';
|
||||
import { PluginWorkerData } from './index.worker';
|
||||
|
||||
export class PluginHandle {
|
||||
#worker: Worker;
|
||||
|
||||
constructor(
|
||||
readonly pluginDir: string,
|
||||
readonly pluginRefId: string,
|
||||
readonly bootRequest: BootRequest,
|
||||
readonly events: EventChannel,
|
||||
) {
|
||||
this.#worker = this.#createWorker();
|
||||
@@ -24,28 +25,32 @@ export class PluginHandle {
|
||||
|
||||
#createWorker(): Worker {
|
||||
const workerPath = process.env.YAAK_WORKER_PATH ?? path.join(__dirname, 'index.worker.cjs');
|
||||
const workerData: PluginWorkerData = {
|
||||
pluginRefId: this.pluginRefId,
|
||||
bootRequest: this.bootRequest,
|
||||
};
|
||||
const worker = new Worker(workerPath, {
|
||||
workerData: { pluginDir: this.pluginDir, pluginRefId: this.pluginRefId },
|
||||
workerData,
|
||||
});
|
||||
|
||||
worker.on('message', (e) => this.events.emit(e));
|
||||
worker.on('error', this.#handleError.bind(this));
|
||||
worker.on('exit', this.#handleExit.bind(this));
|
||||
|
||||
console.log('Created plugin worker for ', this.pluginDir);
|
||||
console.log('Created plugin worker for ', this.bootRequest.dir);
|
||||
|
||||
return worker;
|
||||
}
|
||||
|
||||
async #handleError(err: Error) {
|
||||
console.error('Plugin errored', this.pluginDir, err);
|
||||
console.error('Plugin errored', this.bootRequest.dir, err);
|
||||
}
|
||||
|
||||
async #handleExit(code: number) {
|
||||
if (code === 0) {
|
||||
console.log('Plugin exited successfully', this.pluginDir);
|
||||
console.log('Plugin exited successfully', this.bootRequest.dir);
|
||||
} else {
|
||||
console.log('Plugin exited with status', code, this.pluginDir);
|
||||
console.log('Plugin exited with status', code, this.bootRequest.dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ const plugins: Record<string, PluginHandle> = {};
|
||||
const pluginEvent: InternalEvent = JSON.parse(e.event);
|
||||
// Handle special event to bootstrap plugin
|
||||
if (pluginEvent.payload.type === 'boot_request') {
|
||||
const plugin = new PluginHandle(pluginEvent.payload.dir, pluginEvent.pluginRefId, events);
|
||||
const plugin = new PluginHandle(pluginEvent.pluginRefId, pluginEvent.payload, events);
|
||||
plugins[pluginEvent.pluginRefId] = plugin;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
BootRequest,
|
||||
Context,
|
||||
FindHttpResponsesResponse,
|
||||
GetHttpRequestByIdResponse,
|
||||
@@ -14,13 +15,21 @@ import { HttpRequestActionPlugin } from '@yaakapp/api/lib/plugins/HttpRequestAct
|
||||
import { TemplateFunctionPlugin } from '@yaakapp/api/lib/plugins/TemplateFunctionPlugin';
|
||||
import interceptStdout from 'intercept-stdout';
|
||||
import * as console from 'node:console';
|
||||
import { Stats, readFileSync, statSync, watch } from 'node:fs';
|
||||
import { readFileSync, Stats, statSync, watch } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import * as util from 'node:util';
|
||||
import { parentPort, workerData } from 'node:worker_threads';
|
||||
|
||||
export interface PluginWorkerData {
|
||||
bootRequest: BootRequest;
|
||||
pluginRefId: string;
|
||||
}
|
||||
|
||||
async function initialize() {
|
||||
const { pluginDir, pluginRefId } = workerData;
|
||||
const {
|
||||
bootRequest: { dir: pluginDir, watch: enableWatch },
|
||||
pluginRefId,
|
||||
}: PluginWorkerData = workerData;
|
||||
const pathPkg = path.join(pluginDir, 'package.json');
|
||||
|
||||
const pathMod = path.posix.join(pluginDir, 'build', 'index.js');
|
||||
@@ -102,8 +111,10 @@ async function initialize() {
|
||||
return sendPayload({ type: 'reload_response' }, null);
|
||||
};
|
||||
|
||||
watchFile(pathMod, cb);
|
||||
watchFile(pathPkg, cb);
|
||||
if (enableWatch) {
|
||||
watchFile(pathMod, cb);
|
||||
watchFile(pathPkg, cb);
|
||||
}
|
||||
|
||||
const ctx: Context = {
|
||||
clipboard: {
|
||||
|
||||
@@ -3,8 +3,8 @@ const path = require('node:path');
|
||||
const { execSync } = require('node:child_process');
|
||||
const pluginsDir = process.env.YAAK_PLUGINS_DIR;
|
||||
if (!pluginsDir) {
|
||||
console.log('YAAK_PLUGINS_DIR is not set');
|
||||
process.exit(1);
|
||||
console.log('Skipping bundled plugins build because YAAK_PLUGINS_DIR is not set');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Installing Yaak plugins dependencies', pluginsDir);
|
||||
|
||||
3
src-tauri/.gitignore
vendored
3
src-tauri/.gitignore
vendored
@@ -2,4 +2,5 @@
|
||||
# will have compiled files and executables
|
||||
target/
|
||||
|
||||
vendored
|
||||
vendored/*
|
||||
!vendored/plugins
|
||||
|
||||
@@ -1183,7 +1183,7 @@ async fn cmd_install_plugin(
|
||||
w: WebviewWindow,
|
||||
) -> Result<Plugin, String> {
|
||||
plugin_manager
|
||||
.add_plugin_by_dir(&directory)
|
||||
.add_plugin_by_dir(&directory, true)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
@@ -1511,13 +1511,12 @@ async fn cmd_plugin_info(
|
||||
plugin_manager: State<'_, PluginManager>,
|
||||
) -> Result<BootResponse, String> {
|
||||
let plugin = get_plugin(&w, id).await.map_err(|e| e.to_string())?;
|
||||
plugin_manager
|
||||
Ok(plugin_manager
|
||||
.get_plugin_by_dir(plugin.directory.as_str())
|
||||
.await
|
||||
.ok_or("Failed to find plugin info".to_string())?
|
||||
.ok_or("Failed to find plugin for info".to_string())?
|
||||
.info()
|
||||
.await
|
||||
.ok_or("Failed to find plugin".to_string())
|
||||
.await)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
98
src-tauri/vendored/plugins/exporter-curl/build/index.js
generated
Normal file
98
src-tauri/vendored/plugins/exporter-curl/build/index.js
generated
Normal file
@@ -0,0 +1,98 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/index.ts
|
||||
var src_exports = {};
|
||||
__export(src_exports, {
|
||||
plugin: () => plugin,
|
||||
pluginHookExport: () => pluginHookExport
|
||||
});
|
||||
module.exports = __toCommonJS(src_exports);
|
||||
var NEWLINE = "\\\n ";
|
||||
var plugin = {
|
||||
httpRequestActions: [{
|
||||
key: "export-curl",
|
||||
label: "Copy as Curl",
|
||||
icon: "copy",
|
||||
async onSelect(ctx, args) {
|
||||
const rendered_request = await ctx.httpRequest.render({ httpRequest: args.httpRequest, purpose: "preview" });
|
||||
const data = await pluginHookExport(ctx, rendered_request);
|
||||
ctx.clipboard.copyText(data);
|
||||
ctx.toast.show({ message: "Curl copied to clipboard", icon: "copy" });
|
||||
}
|
||||
}]
|
||||
};
|
||||
async function pluginHookExport(_ctx, request) {
|
||||
const xs = ["curl"];
|
||||
if (request.method) xs.push("-X", request.method);
|
||||
if (request.url) xs.push(quote(request.url));
|
||||
xs.push(NEWLINE);
|
||||
for (const p of (request.urlParameters ?? []).filter(onlyEnabled)) {
|
||||
xs.push("--url-query", quote(`${p.name}=${p.value}`));
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
for (const h of (request.headers ?? []).filter(onlyEnabled)) {
|
||||
xs.push("--header", quote(`${h.name}: ${h.value}`));
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
if (Array.isArray(request.body?.form)) {
|
||||
const flag = request.bodyType === "multipart/form-data" ? "--form" : "--data";
|
||||
for (const p of (request.body?.form ?? []).filter(onlyEnabled)) {
|
||||
if (p.file) {
|
||||
let v = `${p.name}=@${p.file}`;
|
||||
v += p.contentType ? `;type=${p.contentType}` : "";
|
||||
xs.push(flag, v);
|
||||
} else {
|
||||
xs.push(flag, quote(`${p.name}=${p.value}`));
|
||||
}
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
} else if (typeof request.body?.text === "string") {
|
||||
xs.push("--data-raw", `$${quote(request.body.text)}`);
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
if (request.authenticationType === "basic" || request.authenticationType === "digest") {
|
||||
if (request.authenticationType === "digest") xs.push("--digest");
|
||||
xs.push(
|
||||
"--user",
|
||||
quote(`${request.authentication?.username ?? ""}:${request.authentication?.password ?? ""}`)
|
||||
);
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
if (request.authenticationType === "bearer") {
|
||||
xs.push("--header", quote(`Authorization: Bearer ${request.authentication?.token ?? ""}`));
|
||||
xs.push(NEWLINE);
|
||||
}
|
||||
if (xs[xs.length - 1] === NEWLINE) {
|
||||
xs.splice(xs.length - 1, 1);
|
||||
}
|
||||
return xs.join(" ");
|
||||
}
|
||||
function quote(arg) {
|
||||
const escaped = arg.replace(/'/g, "\\'");
|
||||
return `'${escaped}'`;
|
||||
}
|
||||
function onlyEnabled(v) {
|
||||
return v.enabled !== false && !!v.name;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
plugin,
|
||||
pluginHookExport
|
||||
});
|
||||
17
src-tauri/vendored/plugins/exporter-curl/package.json
generated
Normal file
17
src-tauri/vendored/plugins/exporter-curl/package.json
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "exporter-curl",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@yaakapp/api": "^0.2.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.14.9",
|
||||
"typescript": "^5.5.2",
|
||||
"vitest": "^1.4.0",
|
||||
"@yaakapp/cli": "^0.0.42"
|
||||
}
|
||||
}
|
||||
510
src-tauri/vendored/plugins/filter-jsonpath/build/index.js
generated
Normal file
510
src-tauri/vendored/plugins/filter-jsonpath/build/index.js
generated
Normal file
@@ -0,0 +1,510 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/index.ts
|
||||
var src_exports = {};
|
||||
__export(src_exports, {
|
||||
pluginHookResponseFilter: () => pluginHookResponseFilter
|
||||
});
|
||||
module.exports = __toCommonJS(src_exports);
|
||||
|
||||
// ../../node_modules/jsonpath-plus/dist/index-node-esm.js
|
||||
var import_vm = __toESM(require("vm"), 1);
|
||||
var {
|
||||
hasOwnProperty: hasOwnProp
|
||||
} = Object.prototype;
|
||||
function push(arr, item) {
|
||||
arr = arr.slice();
|
||||
arr.push(item);
|
||||
return arr;
|
||||
}
|
||||
function unshift(item, arr) {
|
||||
arr = arr.slice();
|
||||
arr.unshift(item);
|
||||
return arr;
|
||||
}
|
||||
var NewError = class extends Error {
|
||||
/**
|
||||
* @param {AnyResult} value The evaluated scalar value
|
||||
*/
|
||||
constructor(value) {
|
||||
super('JSONPath should not be called with "new" (it prevents return of (unwrapped) scalar values)');
|
||||
this.avoidNew = true;
|
||||
this.value = value;
|
||||
this.name = "NewError";
|
||||
}
|
||||
};
|
||||
function JSONPath(opts, expr, obj, callback, otherTypeCallback) {
|
||||
if (!(this instanceof JSONPath)) {
|
||||
try {
|
||||
return new JSONPath(opts, expr, obj, callback, otherTypeCallback);
|
||||
} catch (e) {
|
||||
if (!e.avoidNew) {
|
||||
throw e;
|
||||
}
|
||||
return e.value;
|
||||
}
|
||||
}
|
||||
if (typeof opts === "string") {
|
||||
otherTypeCallback = callback;
|
||||
callback = obj;
|
||||
obj = expr;
|
||||
expr = opts;
|
||||
opts = null;
|
||||
}
|
||||
const optObj = opts && typeof opts === "object";
|
||||
opts = opts || {};
|
||||
this.json = opts.json || obj;
|
||||
this.path = opts.path || expr;
|
||||
this.resultType = opts.resultType || "value";
|
||||
this.flatten = opts.flatten || false;
|
||||
this.wrap = hasOwnProp.call(opts, "wrap") ? opts.wrap : true;
|
||||
this.sandbox = opts.sandbox || {};
|
||||
this.eval = opts.eval === void 0 ? "safe" : opts.eval;
|
||||
this.ignoreEvalErrors = typeof opts.ignoreEvalErrors === "undefined" ? false : opts.ignoreEvalErrors;
|
||||
this.parent = opts.parent || null;
|
||||
this.parentProperty = opts.parentProperty || null;
|
||||
this.callback = opts.callback || callback || null;
|
||||
this.otherTypeCallback = opts.otherTypeCallback || otherTypeCallback || function() {
|
||||
throw new TypeError("You must supply an otherTypeCallback callback option with the @other() operator.");
|
||||
};
|
||||
if (opts.autostart !== false) {
|
||||
const args = {
|
||||
path: optObj ? opts.path : expr
|
||||
};
|
||||
if (!optObj) {
|
||||
args.json = obj;
|
||||
} else if ("json" in opts) {
|
||||
args.json = opts.json;
|
||||
}
|
||||
const ret = this.evaluate(args);
|
||||
if (!ret || typeof ret !== "object") {
|
||||
throw new NewError(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
JSONPath.prototype.evaluate = function(expr, json, callback, otherTypeCallback) {
|
||||
let currParent = this.parent, currParentProperty = this.parentProperty;
|
||||
let {
|
||||
flatten,
|
||||
wrap
|
||||
} = this;
|
||||
this.currResultType = this.resultType;
|
||||
this.currEval = this.eval;
|
||||
this.currSandbox = this.sandbox;
|
||||
callback = callback || this.callback;
|
||||
this.currOtherTypeCallback = otherTypeCallback || this.otherTypeCallback;
|
||||
json = json || this.json;
|
||||
expr = expr || this.path;
|
||||
if (expr && typeof expr === "object" && !Array.isArray(expr)) {
|
||||
if (!expr.path && expr.path !== "") {
|
||||
throw new TypeError('You must supply a "path" property when providing an object argument to JSONPath.evaluate().');
|
||||
}
|
||||
if (!hasOwnProp.call(expr, "json")) {
|
||||
throw new TypeError('You must supply a "json" property when providing an object argument to JSONPath.evaluate().');
|
||||
}
|
||||
({
|
||||
json
|
||||
} = expr);
|
||||
flatten = hasOwnProp.call(expr, "flatten") ? expr.flatten : flatten;
|
||||
this.currResultType = hasOwnProp.call(expr, "resultType") ? expr.resultType : this.currResultType;
|
||||
this.currSandbox = hasOwnProp.call(expr, "sandbox") ? expr.sandbox : this.currSandbox;
|
||||
wrap = hasOwnProp.call(expr, "wrap") ? expr.wrap : wrap;
|
||||
this.currEval = hasOwnProp.call(expr, "eval") ? expr.eval : this.currEval;
|
||||
callback = hasOwnProp.call(expr, "callback") ? expr.callback : callback;
|
||||
this.currOtherTypeCallback = hasOwnProp.call(expr, "otherTypeCallback") ? expr.otherTypeCallback : this.currOtherTypeCallback;
|
||||
currParent = hasOwnProp.call(expr, "parent") ? expr.parent : currParent;
|
||||
currParentProperty = hasOwnProp.call(expr, "parentProperty") ? expr.parentProperty : currParentProperty;
|
||||
expr = expr.path;
|
||||
}
|
||||
currParent = currParent || null;
|
||||
currParentProperty = currParentProperty || null;
|
||||
if (Array.isArray(expr)) {
|
||||
expr = JSONPath.toPathString(expr);
|
||||
}
|
||||
if (!expr && expr !== "" || !json) {
|
||||
return void 0;
|
||||
}
|
||||
const exprList = JSONPath.toPathArray(expr);
|
||||
if (exprList[0] === "$" && exprList.length > 1) {
|
||||
exprList.shift();
|
||||
}
|
||||
this._hasParentSelector = null;
|
||||
const result = this._trace(exprList, json, ["$"], currParent, currParentProperty, callback).filter(function(ea) {
|
||||
return ea && !ea.isParentSelector;
|
||||
});
|
||||
if (!result.length) {
|
||||
return wrap ? [] : void 0;
|
||||
}
|
||||
if (!wrap && result.length === 1 && !result[0].hasArrExpr) {
|
||||
return this._getPreferredOutput(result[0]);
|
||||
}
|
||||
return result.reduce((rslt, ea) => {
|
||||
const valOrPath = this._getPreferredOutput(ea);
|
||||
if (flatten && Array.isArray(valOrPath)) {
|
||||
rslt = rslt.concat(valOrPath);
|
||||
} else {
|
||||
rslt.push(valOrPath);
|
||||
}
|
||||
return rslt;
|
||||
}, []);
|
||||
};
|
||||
JSONPath.prototype._getPreferredOutput = function(ea) {
|
||||
const resultType = this.currResultType;
|
||||
switch (resultType) {
|
||||
case "all": {
|
||||
const path = Array.isArray(ea.path) ? ea.path : JSONPath.toPathArray(ea.path);
|
||||
ea.pointer = JSONPath.toPointer(path);
|
||||
ea.path = typeof ea.path === "string" ? ea.path : JSONPath.toPathString(ea.path);
|
||||
return ea;
|
||||
}
|
||||
case "value":
|
||||
case "parent":
|
||||
case "parentProperty":
|
||||
return ea[resultType];
|
||||
case "path":
|
||||
return JSONPath.toPathString(ea[resultType]);
|
||||
case "pointer":
|
||||
return JSONPath.toPointer(ea.path);
|
||||
default:
|
||||
throw new TypeError("Unknown result type");
|
||||
}
|
||||
};
|
||||
JSONPath.prototype._handleCallback = function(fullRetObj, callback, type) {
|
||||
if (callback) {
|
||||
const preferredOutput = this._getPreferredOutput(fullRetObj);
|
||||
fullRetObj.path = typeof fullRetObj.path === "string" ? fullRetObj.path : JSONPath.toPathString(fullRetObj.path);
|
||||
callback(preferredOutput, type, fullRetObj);
|
||||
}
|
||||
};
|
||||
JSONPath.prototype._trace = function(expr, val, path, parent, parentPropName, callback, hasArrExpr, literalPriority) {
|
||||
let retObj;
|
||||
if (!expr.length) {
|
||||
retObj = {
|
||||
path,
|
||||
value: val,
|
||||
parent,
|
||||
parentProperty: parentPropName,
|
||||
hasArrExpr
|
||||
};
|
||||
this._handleCallback(retObj, callback, "value");
|
||||
return retObj;
|
||||
}
|
||||
const loc = expr[0], x = expr.slice(1);
|
||||
const ret = [];
|
||||
function addRet(elems) {
|
||||
if (Array.isArray(elems)) {
|
||||
elems.forEach((t) => {
|
||||
ret.push(t);
|
||||
});
|
||||
} else {
|
||||
ret.push(elems);
|
||||
}
|
||||
}
|
||||
if ((typeof loc !== "string" || literalPriority) && val && hasOwnProp.call(val, loc)) {
|
||||
addRet(this._trace(x, val[loc], push(path, loc), val, loc, callback, hasArrExpr));
|
||||
} else if (loc === "*") {
|
||||
this._walk(val, (m) => {
|
||||
addRet(this._trace(x, val[m], push(path, m), val, m, callback, true, true));
|
||||
});
|
||||
} else if (loc === "..") {
|
||||
addRet(this._trace(x, val, path, parent, parentPropName, callback, hasArrExpr));
|
||||
this._walk(val, (m) => {
|
||||
if (typeof val[m] === "object") {
|
||||
addRet(this._trace(expr.slice(), val[m], push(path, m), val, m, callback, true));
|
||||
}
|
||||
});
|
||||
} else if (loc === "^") {
|
||||
this._hasParentSelector = true;
|
||||
return {
|
||||
path: path.slice(0, -1),
|
||||
expr: x,
|
||||
isParentSelector: true
|
||||
};
|
||||
} else if (loc === "~") {
|
||||
retObj = {
|
||||
path: push(path, loc),
|
||||
value: parentPropName,
|
||||
parent,
|
||||
parentProperty: null
|
||||
};
|
||||
this._handleCallback(retObj, callback, "property");
|
||||
return retObj;
|
||||
} else if (loc === "$") {
|
||||
addRet(this._trace(x, val, path, null, null, callback, hasArrExpr));
|
||||
} else if (/^(-?\d*):(-?\d*):?(\d*)$/u.test(loc)) {
|
||||
addRet(this._slice(loc, x, val, path, parent, parentPropName, callback));
|
||||
} else if (loc.indexOf("?(") === 0) {
|
||||
if (this.currEval === false) {
|
||||
throw new Error("Eval [?(expr)] prevented in JSONPath expression.");
|
||||
}
|
||||
const safeLoc = loc.replace(/^\?\((.*?)\)$/u, "$1");
|
||||
const nested = /@.?([^?]*)[['](\??\(.*?\))(?!.\)\])[\]']/gu.exec(safeLoc);
|
||||
if (nested) {
|
||||
this._walk(val, (m) => {
|
||||
const npath = [nested[2]];
|
||||
const nvalue = nested[1] ? val[m][nested[1]] : val[m];
|
||||
const filterResults = this._trace(npath, nvalue, path, parent, parentPropName, callback, true);
|
||||
if (filterResults.length > 0) {
|
||||
addRet(this._trace(x, val[m], push(path, m), val, m, callback, true));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._walk(val, (m) => {
|
||||
if (this._eval(safeLoc, val[m], m, path, parent, parentPropName)) {
|
||||
addRet(this._trace(x, val[m], push(path, m), val, m, callback, true));
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (loc[0] === "(") {
|
||||
if (this.currEval === false) {
|
||||
throw new Error("Eval [(expr)] prevented in JSONPath expression.");
|
||||
}
|
||||
addRet(this._trace(unshift(this._eval(loc, val, path[path.length - 1], path.slice(0, -1), parent, parentPropName), x), val, path, parent, parentPropName, callback, hasArrExpr));
|
||||
} else if (loc[0] === "@") {
|
||||
let addType = false;
|
||||
const valueType = loc.slice(1, -2);
|
||||
switch (valueType) {
|
||||
case "scalar":
|
||||
if (!val || !["object", "function"].includes(typeof val)) {
|
||||
addType = true;
|
||||
}
|
||||
break;
|
||||
case "boolean":
|
||||
case "string":
|
||||
case "undefined":
|
||||
case "function":
|
||||
if (typeof val === valueType) {
|
||||
addType = true;
|
||||
}
|
||||
break;
|
||||
case "integer":
|
||||
if (Number.isFinite(val) && !(val % 1)) {
|
||||
addType = true;
|
||||
}
|
||||
break;
|
||||
case "number":
|
||||
if (Number.isFinite(val)) {
|
||||
addType = true;
|
||||
}
|
||||
break;
|
||||
case "nonFinite":
|
||||
if (typeof val === "number" && !Number.isFinite(val)) {
|
||||
addType = true;
|
||||
}
|
||||
break;
|
||||
case "object":
|
||||
if (val && typeof val === valueType) {
|
||||
addType = true;
|
||||
}
|
||||
break;
|
||||
case "array":
|
||||
if (Array.isArray(val)) {
|
||||
addType = true;
|
||||
}
|
||||
break;
|
||||
case "other":
|
||||
addType = this.currOtherTypeCallback(val, path, parent, parentPropName);
|
||||
break;
|
||||
case "null":
|
||||
if (val === null) {
|
||||
addType = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new TypeError("Unknown value type " + valueType);
|
||||
}
|
||||
if (addType) {
|
||||
retObj = {
|
||||
path,
|
||||
value: val,
|
||||
parent,
|
||||
parentProperty: parentPropName
|
||||
};
|
||||
this._handleCallback(retObj, callback, "value");
|
||||
return retObj;
|
||||
}
|
||||
} else if (loc[0] === "`" && val && hasOwnProp.call(val, loc.slice(1))) {
|
||||
const locProp = loc.slice(1);
|
||||
addRet(this._trace(x, val[locProp], push(path, locProp), val, locProp, callback, hasArrExpr, true));
|
||||
} else if (loc.includes(",")) {
|
||||
const parts = loc.split(",");
|
||||
for (const part of parts) {
|
||||
addRet(this._trace(unshift(part, x), val, path, parent, parentPropName, callback, true));
|
||||
}
|
||||
} else if (!literalPriority && val && hasOwnProp.call(val, loc)) {
|
||||
addRet(this._trace(x, val[loc], push(path, loc), val, loc, callback, hasArrExpr, true));
|
||||
}
|
||||
if (this._hasParentSelector) {
|
||||
for (let t = 0; t < ret.length; t++) {
|
||||
const rett = ret[t];
|
||||
if (rett && rett.isParentSelector) {
|
||||
const tmp = this._trace(rett.expr, val, rett.path, parent, parentPropName, callback, hasArrExpr);
|
||||
if (Array.isArray(tmp)) {
|
||||
ret[t] = tmp[0];
|
||||
const tl = tmp.length;
|
||||
for (let tt = 1; tt < tl; tt++) {
|
||||
t++;
|
||||
ret.splice(t, 0, tmp[tt]);
|
||||
}
|
||||
} else {
|
||||
ret[t] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
JSONPath.prototype._walk = function(val, f) {
|
||||
if (Array.isArray(val)) {
|
||||
const n = val.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
f(i);
|
||||
}
|
||||
} else if (val && typeof val === "object") {
|
||||
Object.keys(val).forEach((m) => {
|
||||
f(m);
|
||||
});
|
||||
}
|
||||
};
|
||||
JSONPath.prototype._slice = function(loc, expr, val, path, parent, parentPropName, callback) {
|
||||
if (!Array.isArray(val)) {
|
||||
return void 0;
|
||||
}
|
||||
const len = val.length, parts = loc.split(":"), step = parts[2] && Number.parseInt(parts[2]) || 1;
|
||||
let start = parts[0] && Number.parseInt(parts[0]) || 0, end = parts[1] && Number.parseInt(parts[1]) || len;
|
||||
start = start < 0 ? Math.max(0, start + len) : Math.min(len, start);
|
||||
end = end < 0 ? Math.max(0, end + len) : Math.min(len, end);
|
||||
const ret = [];
|
||||
for (let i = start; i < end; i += step) {
|
||||
const tmp = this._trace(unshift(i, expr), val, path, parent, parentPropName, callback, true);
|
||||
tmp.forEach((t) => {
|
||||
ret.push(t);
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
JSONPath.prototype._eval = function(code, _v, _vname, path, parent, parentPropName) {
|
||||
this.currSandbox._$_parentProperty = parentPropName;
|
||||
this.currSandbox._$_parent = parent;
|
||||
this.currSandbox._$_property = _vname;
|
||||
this.currSandbox._$_root = this.json;
|
||||
this.currSandbox._$_v = _v;
|
||||
const containsPath = code.includes("@path");
|
||||
if (containsPath) {
|
||||
this.currSandbox._$_path = JSONPath.toPathString(path.concat([_vname]));
|
||||
}
|
||||
const scriptCacheKey = this.currEval + "Script:" + code;
|
||||
if (!JSONPath.cache[scriptCacheKey]) {
|
||||
let script = code.replace(/@parentProperty/gu, "_$_parentProperty").replace(/@parent/gu, "_$_parent").replace(/@property/gu, "_$_property").replace(/@root/gu, "_$_root").replace(/@([.\s)[])/gu, "_$_v$1");
|
||||
if (containsPath) {
|
||||
script = script.replace(/@path/gu, "_$_path");
|
||||
}
|
||||
if (this.currEval === "safe" || this.currEval === true || this.currEval === void 0) {
|
||||
JSONPath.cache[scriptCacheKey] = new this.safeVm.Script(script);
|
||||
} else if (this.currEval === "native") {
|
||||
JSONPath.cache[scriptCacheKey] = new this.vm.Script(script);
|
||||
} else if (typeof this.currEval === "function" && this.currEval.prototype && hasOwnProp.call(this.currEval.prototype, "runInNewContext")) {
|
||||
const CurrEval = this.currEval;
|
||||
JSONPath.cache[scriptCacheKey] = new CurrEval(script);
|
||||
} else if (typeof this.currEval === "function") {
|
||||
JSONPath.cache[scriptCacheKey] = {
|
||||
runInNewContext: (context) => this.currEval(script, context)
|
||||
};
|
||||
} else {
|
||||
throw new TypeError(`Unknown "eval" property "${this.currEval}"`);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return JSONPath.cache[scriptCacheKey].runInNewContext(this.currSandbox);
|
||||
} catch (e) {
|
||||
if (this.ignoreEvalErrors) {
|
||||
return false;
|
||||
}
|
||||
throw new Error("jsonPath: " + e.message + ": " + code);
|
||||
}
|
||||
};
|
||||
JSONPath.cache = {};
|
||||
JSONPath.toPathString = function(pathArr) {
|
||||
const x = pathArr, n = x.length;
|
||||
let p = "$";
|
||||
for (let i = 1; i < n; i++) {
|
||||
if (!/^(~|\^|@.*?\(\))$/u.test(x[i])) {
|
||||
p += /^[0-9*]+$/u.test(x[i]) ? "[" + x[i] + "]" : "['" + x[i] + "']";
|
||||
}
|
||||
}
|
||||
return p;
|
||||
};
|
||||
JSONPath.toPointer = function(pointer) {
|
||||
const x = pointer, n = x.length;
|
||||
let p = "";
|
||||
for (let i = 1; i < n; i++) {
|
||||
if (!/^(~|\^|@.*?\(\))$/u.test(x[i])) {
|
||||
p += "/" + x[i].toString().replace(/~/gu, "~0").replace(/\//gu, "~1");
|
||||
}
|
||||
}
|
||||
return p;
|
||||
};
|
||||
JSONPath.toPathArray = function(expr) {
|
||||
const {
|
||||
cache
|
||||
} = JSONPath;
|
||||
if (cache[expr]) {
|
||||
return cache[expr].concat();
|
||||
}
|
||||
const subx = [];
|
||||
const normalized = expr.replace(/@(?:null|boolean|number|string|integer|undefined|nonFinite|scalar|array|object|function|other)\(\)/gu, ";$&;").replace(/[['](\??\(.*?\))[\]'](?!.\])/gu, function($0, $1) {
|
||||
return "[#" + (subx.push($1) - 1) + "]";
|
||||
}).replace(/\[['"]([^'\]]*)['"]\]/gu, function($0, prop) {
|
||||
return "['" + prop.replace(/\./gu, "%@%").replace(/~/gu, "%%@@%%") + "']";
|
||||
}).replace(/~/gu, ";~;").replace(/['"]?\.['"]?(?![^[]*\])|\[['"]?/gu, ";").replace(/%@%/gu, ".").replace(/%%@@%%/gu, "~").replace(/(?:;)?(\^+)(?:;)?/gu, function($0, ups) {
|
||||
return ";" + ups.split("").join(";") + ";";
|
||||
}).replace(/;;;|;;/gu, ";..;").replace(/;$|'?\]|'$/gu, "");
|
||||
const exprList = normalized.split(";").map(function(exp) {
|
||||
const match = exp.match(/#(\d+)/u);
|
||||
return !match || !match[1] ? exp : subx[match[1]];
|
||||
});
|
||||
cache[expr] = exprList;
|
||||
return cache[expr].concat();
|
||||
};
|
||||
JSONPath.prototype.vm = import_vm.default;
|
||||
JSONPath.prototype.safeVm = import_vm.default;
|
||||
var SafeScript = import_vm.default.Script;
|
||||
|
||||
// src/index.ts
|
||||
function pluginHookResponseFilter(_ctx, args) {
|
||||
const parsed = JSON.parse(args.body);
|
||||
const filtered = JSONPath({ path: args.filter, json: parsed });
|
||||
return JSON.stringify(filtered, null, 2);
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
pluginHookResponseFilter
|
||||
});
|
||||
17
src-tauri/vendored/plugins/filter-jsonpath/package.json
generated
Normal file
17
src-tauri/vendored/plugins/filter-jsonpath/package.json
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "filter-jsonpath",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonpath-plus": "^9.0.0",
|
||||
"@yaakapp/api": "^0.2.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@yaakapp/cli": "^0.0.42",
|
||||
"@types/node": "^20.14.9",
|
||||
"typescript": "^5.5.2"
|
||||
}
|
||||
}
|
||||
8366
src-tauri/vendored/plugins/filter-xpath/build/index.js
generated
Normal file
8366
src-tauri/vendored/plugins/filter-xpath/build/index.js
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
src-tauri/vendored/plugins/filter-xpath/package.json
generated
Normal file
18
src-tauri/vendored/plugins/filter-xpath/package.json
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "filter-xpath",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@yaakapp/api": "^0.2.9",
|
||||
"@xmldom/xmldom": "^0.8.10",
|
||||
"xpath": "^0.0.34"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@yaakapp/cli": "^0.0.42",
|
||||
"@types/node": "^20.14.9",
|
||||
"typescript": "^5.5.2"
|
||||
}
|
||||
}
|
||||
560
src-tauri/vendored/plugins/importer-curl/build/index.js
generated
Normal file
560
src-tauri/vendored/plugins/importer-curl/build/index.js
generated
Normal file
@@ -0,0 +1,560 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __commonJS = (cb, mod) => function __require() {
|
||||
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
||||
};
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// ../../node_modules/shell-quote/quote.js
|
||||
var require_quote = __commonJS({
|
||||
"../../node_modules/shell-quote/quote.js"(exports2, module2) {
|
||||
"use strict";
|
||||
module2.exports = function quote(xs) {
|
||||
return xs.map(function(s) {
|
||||
if (s && typeof s === "object") {
|
||||
return s.op.replace(/(.)/g, "\\$1");
|
||||
}
|
||||
if (/["\s]/.test(s) && !/'/.test(s)) {
|
||||
return "'" + s.replace(/(['\\])/g, "\\$1") + "'";
|
||||
}
|
||||
if (/["'\s]/.test(s)) {
|
||||
return '"' + s.replace(/(["\\$`!])/g, "\\$1") + '"';
|
||||
}
|
||||
return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, "$1\\$2");
|
||||
}).join(" ");
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// ../../node_modules/shell-quote/parse.js
|
||||
var require_parse = __commonJS({
|
||||
"../../node_modules/shell-quote/parse.js"(exports2, module2) {
|
||||
"use strict";
|
||||
var CONTROL = "(?:" + [
|
||||
"\\|\\|",
|
||||
"\\&\\&",
|
||||
";;",
|
||||
"\\|\\&",
|
||||
"\\<\\(",
|
||||
"\\<\\<\\<",
|
||||
">>",
|
||||
">\\&",
|
||||
"<\\&",
|
||||
"[&;()|<>]"
|
||||
].join("|") + ")";
|
||||
var controlRE = new RegExp("^" + CONTROL + "$");
|
||||
var META = "|&;()<> \\t";
|
||||
var SINGLE_QUOTE = '"((\\\\"|[^"])*?)"';
|
||||
var DOUBLE_QUOTE = "'((\\\\'|[^'])*?)'";
|
||||
var hash = /^#$/;
|
||||
var SQ = "'";
|
||||
var DQ = '"';
|
||||
var DS = "$";
|
||||
var TOKEN = "";
|
||||
var mult = 4294967296;
|
||||
for (i = 0; i < 4; i++) {
|
||||
TOKEN += (mult * Math.random()).toString(16);
|
||||
}
|
||||
var i;
|
||||
var startsWithToken = new RegExp("^" + TOKEN);
|
||||
function matchAll(s, r) {
|
||||
var origIndex = r.lastIndex;
|
||||
var matches = [];
|
||||
var matchObj;
|
||||
while (matchObj = r.exec(s)) {
|
||||
matches.push(matchObj);
|
||||
if (r.lastIndex === matchObj.index) {
|
||||
r.lastIndex += 1;
|
||||
}
|
||||
}
|
||||
r.lastIndex = origIndex;
|
||||
return matches;
|
||||
}
|
||||
function getVar(env, pre, key) {
|
||||
var r = typeof env === "function" ? env(key) : env[key];
|
||||
if (typeof r === "undefined" && key != "") {
|
||||
r = "";
|
||||
} else if (typeof r === "undefined") {
|
||||
r = "$";
|
||||
}
|
||||
if (typeof r === "object") {
|
||||
return pre + TOKEN + JSON.stringify(r) + TOKEN;
|
||||
}
|
||||
return pre + r;
|
||||
}
|
||||
function parseInternal(string, env, opts) {
|
||||
if (!opts) {
|
||||
opts = {};
|
||||
}
|
||||
var BS = opts.escape || "\\";
|
||||
var BAREWORD = "(\\" + BS + `['"` + META + `]|[^\\s'"` + META + "])+";
|
||||
var chunker = new RegExp([
|
||||
"(" + CONTROL + ")",
|
||||
// control chars
|
||||
"(" + BAREWORD + "|" + SINGLE_QUOTE + "|" + DOUBLE_QUOTE + ")+"
|
||||
].join("|"), "g");
|
||||
var matches = matchAll(string, chunker);
|
||||
if (matches.length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (!env) {
|
||||
env = {};
|
||||
}
|
||||
var commented = false;
|
||||
return matches.map(function(match) {
|
||||
var s = match[0];
|
||||
if (!s || commented) {
|
||||
return void 0;
|
||||
}
|
||||
if (controlRE.test(s)) {
|
||||
return { op: s };
|
||||
}
|
||||
var quote = false;
|
||||
var esc = false;
|
||||
var out = "";
|
||||
var isGlob = false;
|
||||
var i2;
|
||||
function parseEnvVar() {
|
||||
i2 += 1;
|
||||
var varend;
|
||||
var varname;
|
||||
var char = s.charAt(i2);
|
||||
if (char === "{") {
|
||||
i2 += 1;
|
||||
if (s.charAt(i2) === "}") {
|
||||
throw new Error("Bad substitution: " + s.slice(i2 - 2, i2 + 1));
|
||||
}
|
||||
varend = s.indexOf("}", i2);
|
||||
if (varend < 0) {
|
||||
throw new Error("Bad substitution: " + s.slice(i2));
|
||||
}
|
||||
varname = s.slice(i2, varend);
|
||||
i2 = varend;
|
||||
} else if (/[*@#?$!_-]/.test(char)) {
|
||||
varname = char;
|
||||
i2 += 1;
|
||||
} else {
|
||||
var slicedFromI = s.slice(i2);
|
||||
varend = slicedFromI.match(/[^\w\d_]/);
|
||||
if (!varend) {
|
||||
varname = slicedFromI;
|
||||
i2 = s.length;
|
||||
} else {
|
||||
varname = slicedFromI.slice(0, varend.index);
|
||||
i2 += varend.index - 1;
|
||||
}
|
||||
}
|
||||
return getVar(env, "", varname);
|
||||
}
|
||||
for (i2 = 0; i2 < s.length; i2++) {
|
||||
var c = s.charAt(i2);
|
||||
isGlob = isGlob || !quote && (c === "*" || c === "?");
|
||||
if (esc) {
|
||||
out += c;
|
||||
esc = false;
|
||||
} else if (quote) {
|
||||
if (c === quote) {
|
||||
quote = false;
|
||||
} else if (quote == SQ) {
|
||||
out += c;
|
||||
} else {
|
||||
if (c === BS) {
|
||||
i2 += 1;
|
||||
c = s.charAt(i2);
|
||||
if (c === DQ || c === BS || c === DS) {
|
||||
out += c;
|
||||
} else {
|
||||
out += BS + c;
|
||||
}
|
||||
} else if (c === DS) {
|
||||
out += parseEnvVar();
|
||||
} else {
|
||||
out += c;
|
||||
}
|
||||
}
|
||||
} else if (c === DQ || c === SQ) {
|
||||
quote = c;
|
||||
} else if (controlRE.test(c)) {
|
||||
return { op: s };
|
||||
} else if (hash.test(c)) {
|
||||
commented = true;
|
||||
var commentObj = { comment: string.slice(match.index + i2 + 1) };
|
||||
if (out.length) {
|
||||
return [out, commentObj];
|
||||
}
|
||||
return [commentObj];
|
||||
} else if (c === BS) {
|
||||
esc = true;
|
||||
} else if (c === DS) {
|
||||
out += parseEnvVar();
|
||||
} else {
|
||||
out += c;
|
||||
}
|
||||
}
|
||||
if (isGlob) {
|
||||
return { op: "glob", pattern: out };
|
||||
}
|
||||
return out;
|
||||
}).reduce(function(prev, arg) {
|
||||
return typeof arg === "undefined" ? prev : prev.concat(arg);
|
||||
}, []);
|
||||
}
|
||||
module2.exports = function parse2(s, env, opts) {
|
||||
var mapped = parseInternal(s, env, opts);
|
||||
if (typeof env !== "function") {
|
||||
return mapped;
|
||||
}
|
||||
return mapped.reduce(function(acc, s2) {
|
||||
if (typeof s2 === "object") {
|
||||
return acc.concat(s2);
|
||||
}
|
||||
var xs = s2.split(RegExp("(" + TOKEN + ".*?" + TOKEN + ")", "g"));
|
||||
if (xs.length === 1) {
|
||||
return acc.concat(xs[0]);
|
||||
}
|
||||
return acc.concat(xs.filter(Boolean).map(function(x) {
|
||||
if (startsWithToken.test(x)) {
|
||||
return JSON.parse(x.split(TOKEN)[1]);
|
||||
}
|
||||
return x;
|
||||
}));
|
||||
}, []);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// ../../node_modules/shell-quote/index.js
|
||||
var require_shell_quote = __commonJS({
|
||||
"../../node_modules/shell-quote/index.js"(exports2) {
|
||||
"use strict";
|
||||
exports2.quote = require_quote();
|
||||
exports2.parse = require_parse();
|
||||
}
|
||||
});
|
||||
|
||||
// src/index.ts
|
||||
var src_exports = {};
|
||||
__export(src_exports, {
|
||||
pluginHookImport: () => pluginHookImport
|
||||
});
|
||||
module.exports = __toCommonJS(src_exports);
|
||||
var import_shell_quote = __toESM(require_shell_quote());
|
||||
var DATA_FLAGS = ["d", "data", "data-raw", "data-urlencode", "data-binary", "data-ascii"];
|
||||
var SUPPORTED_ARGS = [
|
||||
["url"],
|
||||
// Specify the URL explicitly
|
||||
["user", "u"],
|
||||
// Authentication
|
||||
["digest"],
|
||||
// Apply auth as digest
|
||||
["header", "H"],
|
||||
["cookie", "b"],
|
||||
["get", "G"],
|
||||
// Put the post data in the URL
|
||||
["d", "data"],
|
||||
// Add url encoded data
|
||||
["data-raw"],
|
||||
["data-urlencode"],
|
||||
["data-binary"],
|
||||
["data-ascii"],
|
||||
["form", "F"],
|
||||
// Add multipart data
|
||||
["request", "X"],
|
||||
// Request method
|
||||
DATA_FLAGS
|
||||
].flatMap((v) => v);
|
||||
function pluginHookImport(ctx, rawData) {
|
||||
if (!rawData.match(/^\s*curl /)) {
|
||||
return null;
|
||||
}
|
||||
const commands = [];
|
||||
const normalizedData = rawData.replace(/\ncurl/g, "; curl");
|
||||
let currentCommand = [];
|
||||
const parsed = (0, import_shell_quote.parse)(normalizedData);
|
||||
const normalizedParseEntries = parsed.flatMap((entry) => {
|
||||
if (typeof entry === "string" && entry.startsWith("-") && !entry.startsWith("--") && entry.length > 2) {
|
||||
return [entry.slice(0, 2), entry.slice(2)];
|
||||
}
|
||||
return entry;
|
||||
});
|
||||
for (const parseEntry of normalizedParseEntries) {
|
||||
if (typeof parseEntry === "string") {
|
||||
if (parseEntry.startsWith("$")) {
|
||||
currentCommand.push(parseEntry.slice(1));
|
||||
} else {
|
||||
currentCommand.push(parseEntry);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ("comment" in parseEntry) {
|
||||
continue;
|
||||
}
|
||||
const { op } = parseEntry;
|
||||
if (op === ";") {
|
||||
commands.push(currentCommand);
|
||||
currentCommand = [];
|
||||
continue;
|
||||
}
|
||||
if (op?.startsWith("$")) {
|
||||
const str = op.slice(2, op.length - 1).replace(/\\'/g, "'");
|
||||
currentCommand.push(str);
|
||||
continue;
|
||||
}
|
||||
if (op === "glob") {
|
||||
currentCommand.push(parseEntry.pattern);
|
||||
}
|
||||
}
|
||||
commands.push(currentCommand);
|
||||
const workspace = {
|
||||
model: "workspace",
|
||||
id: generateId("workspace"),
|
||||
name: "Curl Import"
|
||||
};
|
||||
const requests = commands.filter((command) => command[0] === "curl").map((v) => importCommand(v, workspace.id));
|
||||
return {
|
||||
resources: {
|
||||
httpRequests: requests,
|
||||
workspaces: [workspace]
|
||||
}
|
||||
};
|
||||
}
|
||||
function importCommand(parseEntries, workspaceId) {
|
||||
const pairsByName = {};
|
||||
const singletons = [];
|
||||
for (let i = 1; i < parseEntries.length; i++) {
|
||||
let parseEntry = parseEntries[i];
|
||||
if (typeof parseEntry === "string") {
|
||||
parseEntry = parseEntry.trim();
|
||||
}
|
||||
if (typeof parseEntry === "string" && parseEntry.match(/^-{1,2}[\w-]+/)) {
|
||||
const isSingleDash = parseEntry[0] === "-" && parseEntry[1] !== "-";
|
||||
let name = parseEntry.replace(/^-{1,2}/, "");
|
||||
if (!SUPPORTED_ARGS.includes(name)) {
|
||||
continue;
|
||||
}
|
||||
let value;
|
||||
const nextEntry = parseEntries[i + 1];
|
||||
if (isSingleDash && name.length > 1) {
|
||||
value = name.slice(1);
|
||||
name = name.slice(0, 1);
|
||||
} else if (typeof nextEntry === "string" && !nextEntry.startsWith("-")) {
|
||||
value = nextEntry;
|
||||
i++;
|
||||
} else {
|
||||
value = true;
|
||||
}
|
||||
pairsByName[name] = pairsByName[name] || [];
|
||||
pairsByName[name].push(value);
|
||||
} else if (parseEntry) {
|
||||
singletons.push(parseEntry);
|
||||
}
|
||||
}
|
||||
let urlParameters;
|
||||
let url;
|
||||
const urlArg = getPairValue(pairsByName, singletons[0] || "", ["url"]);
|
||||
const [baseUrl, search] = splitOnce(urlArg, "?");
|
||||
urlParameters = search?.split("&").map((p) => {
|
||||
const v = splitOnce(p, "=");
|
||||
return { name: decodeURIComponent(v[0] ?? ""), value: decodeURIComponent(v[1] ?? ""), enabled: true };
|
||||
}) ?? [];
|
||||
url = baseUrl ?? urlArg;
|
||||
const [username, password] = getPairValue(pairsByName, "", ["u", "user"]).split(/:(.*)$/);
|
||||
const isDigest = getPairValue(pairsByName, false, ["digest"]);
|
||||
const authenticationType = username ? isDigest ? "digest" : "basic" : null;
|
||||
const authentication = username ? {
|
||||
username: username.trim(),
|
||||
password: (password ?? "").trim()
|
||||
} : {};
|
||||
const headers = [
|
||||
...pairsByName["header"] || [],
|
||||
...pairsByName["H"] || []
|
||||
].map((header) => {
|
||||
const [name, value] = header.split(/:(.*)$/);
|
||||
if (!value) {
|
||||
return {
|
||||
name: (name ?? "").trim().replace(/;$/, ""),
|
||||
value: "",
|
||||
enabled: true
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: (name ?? "").trim(),
|
||||
value: value.trim(),
|
||||
enabled: true
|
||||
};
|
||||
});
|
||||
const cookieHeaderValue = [
|
||||
...pairsByName["cookie"] || [],
|
||||
...pairsByName["b"] || []
|
||||
].map((str) => {
|
||||
const name = str.split("=", 1)[0];
|
||||
const value = str.replace(`${name}=`, "");
|
||||
return `${name}=${value}`;
|
||||
}).join("; ");
|
||||
const existingCookieHeader = headers.find((header) => header.name.toLowerCase() === "cookie");
|
||||
if (cookieHeaderValue && existingCookieHeader) {
|
||||
existingCookieHeader.value += `; ${cookieHeaderValue}`;
|
||||
} else if (cookieHeaderValue) {
|
||||
headers.push({
|
||||
name: "Cookie",
|
||||
value: cookieHeaderValue,
|
||||
enabled: true
|
||||
});
|
||||
}
|
||||
const dataParameters = pairsToDataParameters(pairsByName);
|
||||
const contentTypeHeader = headers.find((header) => header.name.toLowerCase() === "content-type");
|
||||
const mimeType = contentTypeHeader ? contentTypeHeader.value.split(";")[0] : null;
|
||||
const formDataParams = [
|
||||
...pairsByName["form"] || [],
|
||||
...pairsByName["F"] || []
|
||||
].map((str) => {
|
||||
const parts = str.split("=");
|
||||
const name = parts[0] ?? "";
|
||||
const value = parts[1] ?? "";
|
||||
const item = {
|
||||
name,
|
||||
enabled: true
|
||||
};
|
||||
if (value.indexOf("@") === 0) {
|
||||
item["file"] = value.slice(1);
|
||||
} else {
|
||||
item["value"] = value;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
let body = {};
|
||||
let bodyType = null;
|
||||
const bodyAsGET = getPairValue(pairsByName, false, ["G", "get"]);
|
||||
if (dataParameters.length > 0 && bodyAsGET) {
|
||||
urlParameters.push(...dataParameters);
|
||||
} else if (dataParameters.length > 0 && (mimeType == null || mimeType === "application/x-www-form-urlencoded")) {
|
||||
bodyType = mimeType ?? "application/x-www-form-urlencoded";
|
||||
body = {
|
||||
form: dataParameters.map((parameter) => ({
|
||||
...parameter,
|
||||
name: decodeURIComponent(parameter.name || ""),
|
||||
value: decodeURIComponent(parameter.value || "")
|
||||
}))
|
||||
};
|
||||
headers.push({
|
||||
name: "Content-Type",
|
||||
value: "application/x-www-form-urlencoded",
|
||||
enabled: true
|
||||
});
|
||||
} else if (dataParameters.length > 0) {
|
||||
bodyType = mimeType === "application/json" || mimeType === "text/xml" || mimeType === "text/plain" ? mimeType : "other";
|
||||
body = {
|
||||
text: dataParameters.map(({ name, value }) => name && value ? `${name}=${value}` : name || value).join("&")
|
||||
};
|
||||
} else if (formDataParams.length) {
|
||||
bodyType = mimeType ?? "multipart/form-data";
|
||||
body = {
|
||||
form: formDataParams
|
||||
};
|
||||
if (mimeType == null) {
|
||||
headers.push({
|
||||
name: "Content-Type",
|
||||
value: "multipart/form-data",
|
||||
enabled: true
|
||||
});
|
||||
}
|
||||
}
|
||||
let method = getPairValue(pairsByName, "", ["X", "request"]).toUpperCase();
|
||||
if (method === "" && body) {
|
||||
method = "text" in body || "form" in body ? "POST" : "GET";
|
||||
}
|
||||
const request = {
|
||||
id: generateId("http_request"),
|
||||
model: "http_request",
|
||||
workspaceId,
|
||||
name: "",
|
||||
urlParameters,
|
||||
url,
|
||||
method,
|
||||
headers,
|
||||
authentication,
|
||||
authenticationType,
|
||||
body,
|
||||
bodyType,
|
||||
folderId: null,
|
||||
sortPriority: 0
|
||||
};
|
||||
return request;
|
||||
}
|
||||
function pairsToDataParameters(keyedPairs) {
|
||||
let dataParameters = [];
|
||||
for (const flagName of DATA_FLAGS) {
|
||||
const pairs = keyedPairs[flagName];
|
||||
if (!pairs || pairs.length === 0) {
|
||||
continue;
|
||||
}
|
||||
for (const p of pairs) {
|
||||
if (typeof p !== "string") continue;
|
||||
const [name, value] = p.split("=");
|
||||
if (p.startsWith("@")) {
|
||||
dataParameters.push({
|
||||
name: name ?? "",
|
||||
value: "",
|
||||
filePath: p.slice(1),
|
||||
enabled: true
|
||||
});
|
||||
} else {
|
||||
dataParameters.push({
|
||||
name: name ?? "",
|
||||
value: flagName === "data-urlencode" ? encodeURIComponent(value ?? "") : value ?? "",
|
||||
enabled: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataParameters;
|
||||
}
|
||||
var getPairValue = (pairsByName, defaultValue, names) => {
|
||||
for (const name of names) {
|
||||
if (pairsByName[name] && pairsByName[name].length) {
|
||||
return pairsByName[name][0];
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
};
|
||||
function splitOnce(str, sep) {
|
||||
const index = str.indexOf(sep);
|
||||
if (index > -1) {
|
||||
return [str.slice(0, index), str.slice(index + 1)];
|
||||
}
|
||||
return [str];
|
||||
}
|
||||
var idCount = {};
|
||||
function generateId(model) {
|
||||
idCount[model] = (idCount[model] ?? -1) + 1;
|
||||
return `GENERATE_ID::${model.toUpperCase()}_${idCount[model]}`;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
pluginHookImport
|
||||
});
|
||||
19
src-tauri/vendored/plugins/importer-curl/package.json
generated
Normal file
19
src-tauri/vendored/plugins/importer-curl/package.json
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "importer-curl",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@yaakapp/api": "^0.2.9",
|
||||
"shell-quote": "^1.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@yaakapp/cli": "^0.0.42",
|
||||
"@types/node": "^20.14.9",
|
||||
"@types/shell-quote": "^1.7.5",
|
||||
"typescript": "^5.5.2",
|
||||
"vitest": "^1.4.0"
|
||||
}
|
||||
}
|
||||
7438
src-tauri/vendored/plugins/importer-insomnia/build/index.js
generated
Normal file
7438
src-tauri/vendored/plugins/importer-insomnia/build/index.js
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
src-tauri/vendored/plugins/importer-insomnia/package.json
generated
Normal file
17
src-tauri/vendored/plugins/importer-insomnia/package.json
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "importer-insomnia",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@yaakapp/api": "^0.2.9",
|
||||
"yaml": "^2.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@yaakapp/cli": "^0.0.42",
|
||||
"@types/node": "^20.14.9",
|
||||
"typescript": "^5.5.2"
|
||||
}
|
||||
}
|
||||
146233
src-tauri/vendored/plugins/importer-openapi/build/index.js
generated
Normal file
146233
src-tauri/vendored/plugins/importer-openapi/build/index.js
generated
Normal file
File diff suppressed because one or more lines are too long
19
src-tauri/vendored/plugins/importer-openapi/package.json
generated
Normal file
19
src-tauri/vendored/plugins/importer-openapi/package.json
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "importer-openapi",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@yaakapp/api": "^0.2.9",
|
||||
"openapi-to-postmanv2": "^4.23.1",
|
||||
"yaml": "^2.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@yaakapp/cli": "^0.0.42",
|
||||
"@types/node": "^20.14.9",
|
||||
"@types/openapi-to-postmanv2": "^3.2.4",
|
||||
"typescript": "^5.5.2"
|
||||
}
|
||||
}
|
||||
301
src-tauri/vendored/plugins/importer-postman/build/index.js
generated
Normal file
301
src-tauri/vendored/plugins/importer-postman/build/index.js
generated
Normal file
@@ -0,0 +1,301 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/index.ts
|
||||
var src_exports = {};
|
||||
__export(src_exports, {
|
||||
pluginHookImport: () => pluginHookImport
|
||||
});
|
||||
module.exports = __toCommonJS(src_exports);
|
||||
var POSTMAN_2_1_0_SCHEMA = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json";
|
||||
var POSTMAN_2_0_0_SCHEMA = "https://schema.getpostman.com/json/collection/v2.0.0/collection.json";
|
||||
var VALID_SCHEMAS = [POSTMAN_2_0_0_SCHEMA, POSTMAN_2_1_0_SCHEMA];
|
||||
function pluginHookImport(_ctx, contents) {
|
||||
const root = parseJSONToRecord(contents);
|
||||
if (root == null) return;
|
||||
const info = toRecord(root.info);
|
||||
const isValidSchema = VALID_SCHEMAS.includes(info.schema);
|
||||
if (!isValidSchema || !Array.isArray(root.item)) {
|
||||
return;
|
||||
}
|
||||
const globalAuth = importAuth(root.auth);
|
||||
const exportResources = {
|
||||
workspaces: [],
|
||||
environments: [],
|
||||
httpRequests: [],
|
||||
folders: []
|
||||
};
|
||||
const workspace = {
|
||||
model: "workspace",
|
||||
id: generateId("workspace"),
|
||||
name: info.name || "Postman Import",
|
||||
description: info.description?.content ?? info.description ?? "",
|
||||
variables: root.variable?.map((v) => ({
|
||||
name: v.key,
|
||||
value: v.value
|
||||
})) ?? []
|
||||
};
|
||||
exportResources.workspaces.push(workspace);
|
||||
const importItem = (v, folderId = null) => {
|
||||
if (typeof v.name === "string" && Array.isArray(v.item)) {
|
||||
const folder = {
|
||||
model: "folder",
|
||||
workspaceId: workspace.id,
|
||||
id: generateId("folder"),
|
||||
name: v.name,
|
||||
folderId
|
||||
};
|
||||
exportResources.folders.push(folder);
|
||||
for (const child of v.item) {
|
||||
importItem(child, folder.id);
|
||||
}
|
||||
} else if (typeof v.name === "string" && "request" in v) {
|
||||
const r = toRecord(v.request);
|
||||
const bodyPatch = importBody(r.body);
|
||||
const requestAuthPath = importAuth(r.auth);
|
||||
const authPatch = requestAuthPath.authenticationType == null ? globalAuth : requestAuthPath;
|
||||
const headers = toArray(r.header).map((h) => {
|
||||
return {
|
||||
name: h.key,
|
||||
value: h.value,
|
||||
enabled: !h.disabled
|
||||
};
|
||||
});
|
||||
for (const bodyPatchHeader of bodyPatch.headers) {
|
||||
const existingHeader = headers.find((h) => h.name.toLowerCase() === bodyPatchHeader.name.toLowerCase());
|
||||
if (existingHeader) {
|
||||
continue;
|
||||
}
|
||||
headers.push(bodyPatchHeader);
|
||||
}
|
||||
const { url, urlParameters } = convertUrl(r.url);
|
||||
const request = {
|
||||
model: "http_request",
|
||||
id: generateId("http_request"),
|
||||
workspaceId: workspace.id,
|
||||
folderId,
|
||||
name: v.name,
|
||||
method: r.method || "GET",
|
||||
url,
|
||||
urlParameters,
|
||||
body: bodyPatch.body,
|
||||
bodyType: bodyPatch.bodyType,
|
||||
authentication: authPatch.authentication,
|
||||
authenticationType: authPatch.authenticationType,
|
||||
headers
|
||||
};
|
||||
exportResources.httpRequests.push(request);
|
||||
} else {
|
||||
console.log("Unknown item", v, folderId);
|
||||
}
|
||||
};
|
||||
for (const item of root.item) {
|
||||
importItem(item);
|
||||
}
|
||||
return { resources: convertTemplateSyntax(exportResources) };
|
||||
}
|
||||
function convertUrl(url) {
|
||||
if (typeof url === "string") {
|
||||
return { url, urlParameters: [] };
|
||||
}
|
||||
url = toRecord(url);
|
||||
let v = "";
|
||||
if ("protocol" in url && typeof url.protocol === "string") {
|
||||
v += `${url.protocol}://`;
|
||||
}
|
||||
if ("host" in url) {
|
||||
v += `${Array.isArray(url.host) ? url.host.join(".") : url.host}`;
|
||||
}
|
||||
if ("port" in url && typeof url.port === "string") {
|
||||
v += `:${url.port}`;
|
||||
}
|
||||
if ("path" in url && Array.isArray(url.path) && url.path.length > 0) {
|
||||
v += `/${Array.isArray(url.path) ? url.path.join("/") : url.path}`;
|
||||
}
|
||||
const params = [];
|
||||
if ("query" in url && Array.isArray(url.query) && url.query.length > 0) {
|
||||
for (const query of url.query) {
|
||||
params.push({
|
||||
name: query.key ?? "",
|
||||
value: query.value ?? "",
|
||||
enabled: !query.disabled
|
||||
});
|
||||
}
|
||||
}
|
||||
if ("variable" in url && Array.isArray(url.variable) && url.variable.length > 0) {
|
||||
for (const v2 of url.variable) {
|
||||
params.push({
|
||||
name: ":" + (v2.key ?? ""),
|
||||
value: v2.value ?? "",
|
||||
enabled: !v2.disabled
|
||||
});
|
||||
}
|
||||
}
|
||||
if ("hash" in url && typeof url.hash === "string") {
|
||||
v += `#${url.hash}`;
|
||||
}
|
||||
return { url: v, urlParameters: params };
|
||||
}
|
||||
function importAuth(rawAuth) {
|
||||
const auth = toRecord(rawAuth);
|
||||
if ("basic" in auth) {
|
||||
return {
|
||||
authenticationType: "basic",
|
||||
authentication: {
|
||||
username: auth.basic.username || "",
|
||||
password: auth.basic.password || ""
|
||||
}
|
||||
};
|
||||
} else if ("bearer" in auth) {
|
||||
return {
|
||||
authenticationType: "bearer",
|
||||
authentication: {
|
||||
token: auth.bearer.token || ""
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return { authenticationType: null, authentication: {} };
|
||||
}
|
||||
}
|
||||
function importBody(rawBody) {
|
||||
const body = toRecord(rawBody);
|
||||
if (body.mode === "graphql") {
|
||||
return {
|
||||
headers: [
|
||||
{
|
||||
name: "Content-Type",
|
||||
value: "application/json",
|
||||
enabled: true
|
||||
}
|
||||
],
|
||||
bodyType: "graphql",
|
||||
body: {
|
||||
text: JSON.stringify(
|
||||
{ query: body.graphql.query, variables: parseJSONToRecord(body.graphql.variables) },
|
||||
null,
|
||||
2
|
||||
)
|
||||
}
|
||||
};
|
||||
} else if (body.mode === "urlencoded") {
|
||||
return {
|
||||
headers: [
|
||||
{
|
||||
name: "Content-Type",
|
||||
value: "application/x-www-form-urlencoded",
|
||||
enabled: true
|
||||
}
|
||||
],
|
||||
bodyType: "application/x-www-form-urlencoded",
|
||||
body: {
|
||||
form: toArray(body.urlencoded).map((f) => ({
|
||||
enabled: !f.disabled,
|
||||
name: f.key ?? "",
|
||||
value: f.value ?? ""
|
||||
}))
|
||||
}
|
||||
};
|
||||
} else if (body.mode === "formdata") {
|
||||
return {
|
||||
headers: [
|
||||
{
|
||||
name: "Content-Type",
|
||||
value: "multipart/form-data",
|
||||
enabled: true
|
||||
}
|
||||
],
|
||||
bodyType: "multipart/form-data",
|
||||
body: {
|
||||
form: toArray(body.formdata).map(
|
||||
(f) => f.src != null ? {
|
||||
enabled: !f.disabled,
|
||||
contentType: f.contentType ?? null,
|
||||
name: f.key ?? "",
|
||||
file: f.src ?? ""
|
||||
} : {
|
||||
enabled: !f.disabled,
|
||||
name: f.key ?? "",
|
||||
value: f.value ?? ""
|
||||
}
|
||||
)
|
||||
}
|
||||
};
|
||||
} else if (body.mode === "raw") {
|
||||
return {
|
||||
headers: [
|
||||
{
|
||||
name: "Content-Type",
|
||||
value: body.options?.raw?.language === "json" ? "application/json" : "",
|
||||
enabled: true
|
||||
}
|
||||
],
|
||||
bodyType: body.options?.raw?.language === "json" ? "application/json" : "other",
|
||||
body: {
|
||||
text: body.raw ?? ""
|
||||
}
|
||||
};
|
||||
} else if (body.mode === "file") {
|
||||
return {
|
||||
headers: [],
|
||||
bodyType: "binary",
|
||||
body: {
|
||||
filePath: body.file?.src
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return { headers: [], bodyType: null, body: {} };
|
||||
}
|
||||
}
|
||||
function parseJSONToRecord(jsonStr) {
|
||||
try {
|
||||
return toRecord(JSON.parse(jsonStr));
|
||||
} catch (err) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function toRecord(value) {
|
||||
if (Object.prototype.toString.call(value) === "[object Object]") return value;
|
||||
else return {};
|
||||
}
|
||||
function toArray(value) {
|
||||
if (Object.prototype.toString.call(value) === "[object Array]") return value;
|
||||
else return [];
|
||||
}
|
||||
function convertTemplateSyntax(obj) {
|
||||
if (typeof obj === "string") {
|
||||
return obj.replace(/{{\s*(_\.)?([^}]+)\s*}}/g, "${[$2]}");
|
||||
} else if (Array.isArray(obj) && obj != null) {
|
||||
return obj.map(convertTemplateSyntax);
|
||||
} else if (typeof obj === "object" && obj != null) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj).map(([k, v]) => [k, convertTemplateSyntax(v)])
|
||||
);
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
var idCount = {};
|
||||
function generateId(model) {
|
||||
idCount[model] = (idCount[model] ?? -1) + 1;
|
||||
return `GENERATE_ID::${model.toUpperCase()}_${idCount[model]}`;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
pluginHookImport
|
||||
});
|
||||
19
src-tauri/vendored/plugins/importer-postman/package.json
generated
Normal file
19
src-tauri/vendored/plugins/importer-postman/package.json
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "importer-postman",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"main": "./build/index.js",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@yaakapp/api": "^0.2.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@yaakapp/cli": "^0.0.42",
|
||||
"@types/node": "^20.14.9",
|
||||
"esbuild": "^0.21.5",
|
||||
"typescript": "^5.5.2",
|
||||
"vitest": "^1.4.0"
|
||||
}
|
||||
}
|
||||
52
src-tauri/vendored/plugins/importer-yaak/build/index.js
generated
Normal file
52
src-tauri/vendored/plugins/importer-yaak/build/index.js
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/index.ts
|
||||
var src_exports = {};
|
||||
__export(src_exports, {
|
||||
pluginHookImport: () => pluginHookImport
|
||||
});
|
||||
module.exports = __toCommonJS(src_exports);
|
||||
function pluginHookImport(_ctx, contents) {
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(contents);
|
||||
} catch (err) {
|
||||
return void 0;
|
||||
}
|
||||
if (!isJSObject(parsed)) {
|
||||
return void 0;
|
||||
}
|
||||
const isYaakExport = "yaakSchema" in parsed;
|
||||
if (!isYaakExport) {
|
||||
return;
|
||||
}
|
||||
if ("requests" in parsed.resources) {
|
||||
parsed.resources.httpRequests = parsed.resources.requests;
|
||||
delete parsed.resources["requests"];
|
||||
}
|
||||
return { resources: parsed.resources };
|
||||
}
|
||||
function isJSObject(obj) {
|
||||
return Object.prototype.toString.call(obj) === "[object Object]";
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
pluginHookImport
|
||||
});
|
||||
17
src-tauri/vendored/plugins/importer-yaak/package.json
generated
Normal file
17
src-tauri/vendored/plugins/importer-yaak/package.json
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "importer-yaak",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@yaakapp/api": "^0.2.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@yaakapp/cli": "^0.0.42",
|
||||
"@types/node": "^20.14.9",
|
||||
"esbuild": "^0.21.5",
|
||||
"typescript": "^5.5.2"
|
||||
}
|
||||
}
|
||||
8913
src-tauri/vendored/plugins/template-function-response/build/index.js
generated
Normal file
8913
src-tauri/vendored/plugins/template-function-response/build/index.js
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
src-tauri/vendored/plugins/template-function-response/package.json
generated
Normal file
21
src-tauri/vendored/plugins/template-function-response/package.json
generated
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "template-function-response",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build": "yaakcli build ./src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@yaakapp/api": "^0.2.9",
|
||||
"jsonpath-plus": "^9.0.0",
|
||||
"xpath": "^0.0.34",
|
||||
"@xmldom/xmldom": "^0.8.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@yaakapp/cli": "^0.0.42",
|
||||
"@types/jsonpath": "^0.2.4",
|
||||
"@types/node": "^20.14.9",
|
||||
"typescript": "^5.5.2",
|
||||
"vitest": "^1.4.0"
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,6 @@ impl Builder {
|
||||
create_dir_all(app_path.clone()).expect("Problem creating App directory!");
|
||||
|
||||
let db_file_path = app_path.join("db.sqlite");
|
||||
info!("Opening SQLite DB at {db_file_path:?}");
|
||||
|
||||
{
|
||||
let db_file_path = db_file_path.clone();
|
||||
@@ -66,7 +65,7 @@ impl Builder {
|
||||
async fn must_migrate_db<R: Runtime>(app_handle: &AppHandle<R>, path: &PathBuf) {
|
||||
let app_data_dir = app_handle.path().app_data_dir().unwrap();
|
||||
let sqlite_file_path = app_data_dir.join("db.sqlite");
|
||||
|
||||
|
||||
info!("Creating database file at {:?}", sqlite_file_path);
|
||||
File::options()
|
||||
.write(true)
|
||||
@@ -76,7 +75,7 @@ async fn must_migrate_db<R: Runtime>(app_handle: &AppHandle<R>, path: &PathBuf)
|
||||
|
||||
let p_string = sqlite_file_path.to_string_lossy().replace(' ', "%20");
|
||||
let url = format!("sqlite://{}?mode=rwc", p_string);
|
||||
|
||||
|
||||
info!("Connecting to database at {}", url);
|
||||
let opts = SqliteConnectOptions::from_str(path.to_string_lossy().to_string().as_str()).unwrap();
|
||||
let pool = SqlitePool::connect_with(opts)
|
||||
@@ -86,11 +85,11 @@ async fn must_migrate_db<R: Runtime>(app_handle: &AppHandle<R>, path: &PathBuf)
|
||||
.path()
|
||||
.resolve("migrations", BaseDirectory::Resource)
|
||||
.expect("failed to resolve resource");
|
||||
|
||||
|
||||
info!("Running database migrations from: {}", p.to_string_lossy());
|
||||
let mut m = Migrator::new(p).await.expect("Failed to load migrations");
|
||||
m.set_ignore_missing(true); // So we can roll back versions and not crash
|
||||
m.run(&pool).await.expect("Failed to run migrations");
|
||||
|
||||
|
||||
info!("Database migrations complete");
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { HttpRequest } from "./models";
|
||||
import type { HttpResponse } from "./models";
|
||||
import type { Workspace } from "./models";
|
||||
|
||||
export type BootRequest = { dir: string, };
|
||||
export type BootRequest = { dir: string, watch: boolean, };
|
||||
|
||||
export type BootResponse = { name: string, version: string, capabilities: Array<string>, };
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ pub enum InternalEventPayload {
|
||||
#[ts(export, export_to="events.ts")]
|
||||
pub struct BootRequest {
|
||||
pub dir: String,
|
||||
pub watch: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::server::plugin_runtime::plugin_runtime_server::PluginRuntimeServer;
|
||||
use crate::server::PluginRuntimeServerImpl;
|
||||
use log::{info, warn};
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
@@ -32,6 +33,12 @@ pub struct PluginManager {
|
||||
server: Arc<PluginRuntimeServerImpl>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct PluginCandidate {
|
||||
dir: String,
|
||||
watch: bool,
|
||||
}
|
||||
|
||||
impl PluginManager {
|
||||
pub fn new<R: Runtime>(app_handle: AppHandle<R>) -> PluginManager {
|
||||
let (events_tx, mut events_rx) = mpsc::channel(128);
|
||||
@@ -123,24 +130,45 @@ impl PluginManager {
|
||||
plugin_manager
|
||||
}
|
||||
|
||||
pub async fn list_plugin_dirs<R: Runtime>(&self, app_handle: &AppHandle<R>) -> Vec<String> {
|
||||
let plugins_dir = app_handle
|
||||
async fn list_plugin_dirs<R: Runtime>(
|
||||
&self,
|
||||
app_handle: &AppHandle<R>,
|
||||
) -> Vec<PluginCandidate> {
|
||||
let bundled_plugins_dir = &app_handle
|
||||
.path()
|
||||
.resolve("vendored/plugins", BaseDirectory::Resource)
|
||||
.expect("failed to resolve plugin directory resource");
|
||||
|
||||
let bundled_plugin_dirs = read_plugins_dir(&plugins_dir)
|
||||
let plugins_dir = match env::var("YAAK_PLUGINS_DIR") {
|
||||
Ok(d) => &PathBuf::from(d),
|
||||
Err(_) => bundled_plugins_dir,
|
||||
};
|
||||
|
||||
info!("Loading bundled plugins from {plugins_dir:?}");
|
||||
|
||||
let bundled_plugin_dirs: Vec<PluginCandidate> = read_plugins_dir(&plugins_dir)
|
||||
.await
|
||||
.expect(format!("Failed to read plugins dir: {:?}", plugins_dir).as_str());
|
||||
.expect(format!("Failed to read plugins dir: {:?}", plugins_dir).as_str())
|
||||
.iter()
|
||||
.map(|d| {
|
||||
let is_vendored = plugins_dir.starts_with(bundled_plugins_dir);
|
||||
PluginCandidate {
|
||||
dir: d.into(),
|
||||
watch: !is_vendored,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let plugins = list_plugins(app_handle).await.unwrap_or_default();
|
||||
let installed_plugin_dirs = plugins
|
||||
let installed_plugin_dirs: Vec<PluginCandidate> = plugins
|
||||
.iter()
|
||||
.map(|p| p.directory.to_owned())
|
||||
.collect::<Vec<String>>();
|
||||
.map(|p| PluginCandidate {
|
||||
dir: p.directory.to_owned(),
|
||||
watch: true,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let plugin_dirs = [bundled_plugin_dirs, installed_plugin_dirs].concat();
|
||||
plugin_dirs
|
||||
[bundled_plugin_dirs, installed_plugin_dirs].concat()
|
||||
}
|
||||
|
||||
pub async fn uninstall(&self, dir: &str) -> Result<()> {
|
||||
@@ -152,12 +180,11 @@ impl PluginManager {
|
||||
}
|
||||
|
||||
async fn remove_plugin(&self, plugin: &PluginHandle) -> Result<()> {
|
||||
let mut plugins = self.plugins.lock().await;
|
||||
|
||||
// Terminate the plugin
|
||||
plugin.terminate().await?;
|
||||
|
||||
// Remove the plugin from the list
|
||||
let mut plugins = self.plugins.lock().await;
|
||||
let pos = plugins.iter().position(|p| p.ref_id == plugin.ref_id);
|
||||
if let Some(pos) = pos {
|
||||
plugins.remove(pos);
|
||||
@@ -166,26 +193,22 @@ impl PluginManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn add_plugin_by_dir(&self, dir: &str) -> Result<()> {
|
||||
pub async fn add_plugin_by_dir(&self, dir: &str, watch: bool) -> Result<()> {
|
||||
info!("Adding plugin by dir {dir}");
|
||||
let maybe_tx = self.server.app_to_plugin_events_tx.lock().await;
|
||||
let tx = match &*maybe_tx {
|
||||
None => return Err(ClientNotInitializedErr),
|
||||
Some(tx) => tx,
|
||||
};
|
||||
let ph = PluginHandle::new(dir, tx.clone());
|
||||
self.plugins.lock().await.push(ph.clone());
|
||||
let plugin = self
|
||||
.get_plugin_by_dir(dir)
|
||||
.await
|
||||
.ok_or(PluginNotFoundErr(dir.to_string()))?;
|
||||
let plugin_handle = PluginHandle::new(dir, tx.clone());
|
||||
|
||||
// Boot the plugin
|
||||
let event = self
|
||||
.send_to_plugin_and_wait(
|
||||
&plugin,
|
||||
&plugin_handle,
|
||||
&InternalEventPayload::BootRequest(BootRequest {
|
||||
dir: dir.to_string(),
|
||||
watch,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
@@ -195,7 +218,10 @@ impl PluginManager {
|
||||
_ => return Err(UnknownEventErr),
|
||||
};
|
||||
|
||||
plugin.set_boot_response(&resp).await;
|
||||
plugin_handle.set_boot_response(&resp).await;
|
||||
|
||||
// Add the new plugin after it boots
|
||||
self.plugins.lock().await.push(plugin_handle.clone());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -204,18 +230,30 @@ impl PluginManager {
|
||||
&self,
|
||||
app_handle: &AppHandle<R>,
|
||||
) -> Result<()> {
|
||||
for dir in self.list_plugin_dirs(app_handle).await {
|
||||
let dirs = self.list_plugin_dirs(app_handle).await;
|
||||
for d in dirs.clone() {
|
||||
// First remove the plugin if it exists
|
||||
if let Some(plugin) = self.get_plugin_by_dir(dir.as_str()).await {
|
||||
if let Some(plugin) = self.get_plugin_by_dir(d.dir.as_str()).await {
|
||||
if let Err(e) = self.remove_plugin(&plugin).await {
|
||||
warn!("Failed to remove plugin {dir} {e:?}");
|
||||
warn!("Failed to remove plugin {} {e:?}", d.dir);
|
||||
}
|
||||
}
|
||||
if let Err(e) = self.add_plugin_by_dir(dir.as_str()).await {
|
||||
warn!("Failed to add plugin {dir} {e:?}");
|
||||
if let Err(e) = self.add_plugin_by_dir(d.dir.as_str(), d.watch).await {
|
||||
warn!("Failed to add plugin {} {e:?}", d.dir);
|
||||
}
|
||||
}
|
||||
|
||||
info!(
|
||||
"Initialized all plugins:\n - {}",
|
||||
self.plugins
|
||||
.lock()
|
||||
.await
|
||||
.iter()
|
||||
.map(|p| p.dir.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n - "),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -271,7 +309,7 @@ impl PluginManager {
|
||||
|
||||
pub async fn get_plugin_by_name(&self, name: &str) -> Option<PluginHandle> {
|
||||
for plugin in self.plugins.lock().await.iter().cloned() {
|
||||
let info = plugin.info().await?;
|
||||
let info = plugin.info().await;
|
||||
if info.name == name {
|
||||
return Some(plugin);
|
||||
}
|
||||
@@ -446,8 +484,7 @@ impl PluginManager {
|
||||
.get_plugin_by_ref_id(ref_id.as_str())
|
||||
.await
|
||||
.ok_or(PluginNotFoundErr(ref_id))?;
|
||||
let info = plugin.info().await.unwrap();
|
||||
Ok((resp, info.name))
|
||||
Ok((resp, plugin.info().await.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ pub struct PluginHandle {
|
||||
pub ref_id: String,
|
||||
pub dir: String,
|
||||
pub(crate) to_plugin_tx: Arc<Mutex<mpsc::Sender<tonic::Result<EventStreamEvent>>>>,
|
||||
pub(crate) boot_resp: Arc<Mutex<Option<BootResponse>>>,
|
||||
pub(crate) boot_resp: Arc<Mutex<BootResponse>>,
|
||||
}
|
||||
|
||||
impl PluginHandle {
|
||||
@@ -22,11 +22,11 @@ impl PluginHandle {
|
||||
ref_id: ref_id.clone(),
|
||||
dir: dir.to_string(),
|
||||
to_plugin_tx: Arc::new(Mutex::new(tx)),
|
||||
boot_resp: Arc::new(Mutex::new(None)),
|
||||
boot_resp: Arc::new(Mutex::new(BootResponse::default())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn info(&self) -> Option<BootResponse> {
|
||||
pub async fn info(&self) -> BootResponse {
|
||||
let resp = &*self.boot_resp.lock().await;
|
||||
resp.clone()
|
||||
}
|
||||
@@ -72,6 +72,6 @@ impl PluginHandle {
|
||||
|
||||
pub async fn set_boot_response(&self, resp: &BootResponse) {
|
||||
let mut boot_resp = self.boot_resp.lock().await;
|
||||
*boot_resp = Some(resp.clone());
|
||||
*boot_resp = resp.clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ export function useHttpRequestActions() {
|
||||
|
||||
const httpRequestActions = useQuery({
|
||||
queryKey: ['http_request_actions', pluginsKey],
|
||||
refetchOnWindowFocus: false,
|
||||
queryFn: async () => {
|
||||
const responses = (await invokeCmd(
|
||||
'cmd_http_request_actions',
|
||||
|
||||
Reference in New Issue
Block a user