Framework updates
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
242
node_modules/axios/lib/utils.js
generated
vendored
242
node_modules/axios/lib/utils.js
generated
vendored
@@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
import bind from "./helpers/bind.js";
|
||||
import bind from './helpers/bind.js';
|
||||
|
||||
// utils is a library of generic helper functions non-specific to axios
|
||||
|
||||
@@ -36,7 +36,7 @@ const { isArray } = Array;
|
||||
*
|
||||
* @returns {boolean} True if the value is undefined, otherwise false
|
||||
*/
|
||||
const isUndefined = typeOfTest("undefined");
|
||||
const isUndefined = typeOfTest('undefined');
|
||||
|
||||
/**
|
||||
* Determine if a value is a Buffer
|
||||
@@ -63,7 +63,7 @@ function isBuffer(val) {
|
||||
*
|
||||
* @returns {boolean} True if value is an ArrayBuffer, otherwise false
|
||||
*/
|
||||
const isArrayBuffer = kindOfTest("ArrayBuffer");
|
||||
const isArrayBuffer = kindOfTest('ArrayBuffer');
|
||||
|
||||
/**
|
||||
* Determine if a value is a view on an ArrayBuffer
|
||||
@@ -74,7 +74,7 @@ const isArrayBuffer = kindOfTest("ArrayBuffer");
|
||||
*/
|
||||
function isArrayBufferView(val) {
|
||||
let result;
|
||||
if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView) {
|
||||
if (typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView) {
|
||||
result = ArrayBuffer.isView(val);
|
||||
} else {
|
||||
result = val && val.buffer && isArrayBuffer(val.buffer);
|
||||
@@ -89,7 +89,7 @@ function isArrayBufferView(val) {
|
||||
*
|
||||
* @returns {boolean} True if value is a String, otherwise false
|
||||
*/
|
||||
const isString = typeOfTest("string");
|
||||
const isString = typeOfTest('string');
|
||||
|
||||
/**
|
||||
* Determine if a value is a Function
|
||||
@@ -97,7 +97,7 @@ const isString = typeOfTest("string");
|
||||
* @param {*} val The value to test
|
||||
* @returns {boolean} True if value is a Function, otherwise false
|
||||
*/
|
||||
const isFunction = typeOfTest("function");
|
||||
const isFunction = typeOfTest('function');
|
||||
|
||||
/**
|
||||
* Determine if a value is a Number
|
||||
@@ -106,7 +106,7 @@ const isFunction = typeOfTest("function");
|
||||
*
|
||||
* @returns {boolean} True if value is a Number, otherwise false
|
||||
*/
|
||||
const isNumber = typeOfTest("number");
|
||||
const isNumber = typeOfTest('number');
|
||||
|
||||
/**
|
||||
* Determine if a value is an Object
|
||||
@@ -115,7 +115,7 @@ const isNumber = typeOfTest("number");
|
||||
*
|
||||
* @returns {boolean} True if value is an Object, otherwise false
|
||||
*/
|
||||
const isObject = (thing) => thing !== null && typeof thing === "object";
|
||||
const isObject = (thing) => thing !== null && typeof thing === 'object';
|
||||
|
||||
/**
|
||||
* Determine if a value is a Boolean
|
||||
@@ -133,7 +133,7 @@ const isBoolean = (thing) => thing === true || thing === false;
|
||||
* @returns {boolean} True if value is a plain Object, otherwise false
|
||||
*/
|
||||
const isPlainObject = (val) => {
|
||||
if (kindOf(val) !== "object") {
|
||||
if (kindOf(val) !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -161,10 +161,7 @@ const isEmptyObject = (val) => {
|
||||
}
|
||||
|
||||
try {
|
||||
return (
|
||||
Object.keys(val).length === 0 &&
|
||||
Object.getPrototypeOf(val) === Object.prototype
|
||||
);
|
||||
return Object.keys(val).length === 0 && Object.getPrototypeOf(val) === Object.prototype;
|
||||
} catch (e) {
|
||||
// Fallback for any other objects that might cause RangeError with Object.keys()
|
||||
return false;
|
||||
@@ -178,7 +175,7 @@ const isEmptyObject = (val) => {
|
||||
*
|
||||
* @returns {boolean} True if value is a Date, otherwise false
|
||||
*/
|
||||
const isDate = kindOfTest("Date");
|
||||
const isDate = kindOfTest('Date');
|
||||
|
||||
/**
|
||||
* Determine if a value is a File
|
||||
@@ -187,7 +184,32 @@ const isDate = kindOfTest("Date");
|
||||
*
|
||||
* @returns {boolean} True if value is a File, otherwise false
|
||||
*/
|
||||
const isFile = kindOfTest("File");
|
||||
const isFile = kindOfTest('File');
|
||||
|
||||
/**
|
||||
* Determine if a value is a React Native Blob
|
||||
* React Native "blob": an object with a `uri` attribute. Optionally, it can
|
||||
* also have a `name` and `type` attribute to specify filename and content type
|
||||
*
|
||||
* @see https://github.com/facebook/react-native/blob/26684cf3adf4094eb6c405d345a75bf8c7c0bf88/Libraries/Network/FormData.js#L68-L71
|
||||
*
|
||||
* @param {*} value The value to test
|
||||
*
|
||||
* @returns {boolean} True if value is a React Native Blob, otherwise false
|
||||
*/
|
||||
const isReactNativeBlob = (value) => {
|
||||
return !!(value && typeof value.uri !== 'undefined');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if environment is React Native
|
||||
* ReactNative `FormData` has a non-standard `getParts()` method
|
||||
*
|
||||
* @param {*} formData The formData to test
|
||||
*
|
||||
* @returns {boolean} True if environment is React Native, otherwise false
|
||||
*/
|
||||
const isReactNative = (formData) => formData && typeof formData.getParts !== 'undefined';
|
||||
|
||||
/**
|
||||
* Determine if a value is a Blob
|
||||
@@ -196,7 +218,7 @@ const isFile = kindOfTest("File");
|
||||
*
|
||||
* @returns {boolean} True if value is a Blob, otherwise false
|
||||
*/
|
||||
const isBlob = kindOfTest("Blob");
|
||||
const isBlob = kindOfTest('Blob');
|
||||
|
||||
/**
|
||||
* Determine if a value is a FileList
|
||||
@@ -205,7 +227,7 @@ const isBlob = kindOfTest("Blob");
|
||||
*
|
||||
* @returns {boolean} True if value is a File, otherwise false
|
||||
*/
|
||||
const isFileList = kindOfTest("FileList");
|
||||
const isFileList = kindOfTest('FileList');
|
||||
|
||||
/**
|
||||
* Determine if a value is a Stream
|
||||
@@ -223,17 +245,27 @@ const isStream = (val) => isObject(val) && isFunction(val.pipe);
|
||||
*
|
||||
* @returns {boolean} True if value is an FormData, otherwise false
|
||||
*/
|
||||
function getGlobal() {
|
||||
if (typeof globalThis !== 'undefined') return globalThis;
|
||||
if (typeof self !== 'undefined') return self;
|
||||
if (typeof window !== 'undefined') return window;
|
||||
if (typeof global !== 'undefined') return global;
|
||||
return {};
|
||||
}
|
||||
|
||||
const G = getGlobal();
|
||||
const FormDataCtor = typeof G.FormData !== 'undefined' ? G.FormData : undefined;
|
||||
|
||||
const isFormData = (thing) => {
|
||||
let kind;
|
||||
return (
|
||||
thing &&
|
||||
((typeof FormData === "function" && thing instanceof FormData) ||
|
||||
(isFunction(thing.append) &&
|
||||
((kind = kindOf(thing)) === "formdata" ||
|
||||
// detect form-data instance
|
||||
(kind === "object" &&
|
||||
isFunction(thing.toString) &&
|
||||
thing.toString() === "[object FormData]"))))
|
||||
return thing && (
|
||||
(FormDataCtor && thing instanceof FormDataCtor) || (
|
||||
isFunction(thing.append) && (
|
||||
(kind = kindOf(thing)) === 'formdata' ||
|
||||
// detect form-data instance
|
||||
(kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]')
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -244,13 +276,13 @@ const isFormData = (thing) => {
|
||||
*
|
||||
* @returns {boolean} True if value is a URLSearchParams object, otherwise false
|
||||
*/
|
||||
const isURLSearchParams = kindOfTest("URLSearchParams");
|
||||
const isURLSearchParams = kindOfTest('URLSearchParams');
|
||||
|
||||
const [isReadableStream, isRequest, isResponse, isHeaders] = [
|
||||
"ReadableStream",
|
||||
"Request",
|
||||
"Response",
|
||||
"Headers",
|
||||
'ReadableStream',
|
||||
'Request',
|
||||
'Response',
|
||||
'Headers',
|
||||
].map(kindOfTest);
|
||||
|
||||
/**
|
||||
@@ -260,9 +292,9 @@ const [isReadableStream, isRequest, isResponse, isHeaders] = [
|
||||
*
|
||||
* @returns {String} The String freed of excess whitespace
|
||||
*/
|
||||
const trim = (str) =>
|
||||
str.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
|
||||
|
||||
const trim = (str) => {
|
||||
return str.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
||||
};
|
||||
/**
|
||||
* Iterate over an Array or an Object invoking a function for each item.
|
||||
*
|
||||
@@ -281,7 +313,7 @@ const trim = (str) =>
|
||||
*/
|
||||
function forEach(obj, fn, { allOwnKeys = false } = {}) {
|
||||
// Don't bother if no value provided
|
||||
if (obj === null || typeof obj === "undefined") {
|
||||
if (obj === null || typeof obj === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -289,7 +321,7 @@ function forEach(obj, fn, { allOwnKeys = false } = {}) {
|
||||
let l;
|
||||
|
||||
// Force an array if not already something iterable
|
||||
if (typeof obj !== "object") {
|
||||
if (typeof obj !== 'object') {
|
||||
/*eslint no-param-reassign:0*/
|
||||
obj = [obj];
|
||||
}
|
||||
@@ -306,9 +338,7 @@ function forEach(obj, fn, { allOwnKeys = false } = {}) {
|
||||
}
|
||||
|
||||
// Iterate over object keys
|
||||
const keys = allOwnKeys
|
||||
? Object.getOwnPropertyNames(obj)
|
||||
: Object.keys(obj);
|
||||
const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);
|
||||
const len = keys.length;
|
||||
let key;
|
||||
|
||||
@@ -319,6 +349,14 @@ function forEach(obj, fn, { allOwnKeys = false } = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a key in an object, case-insensitive, returning the actual key name.
|
||||
* Returns null if the object is a Buffer or if no match is found.
|
||||
*
|
||||
* @param {Object} obj - The object to search.
|
||||
* @param {string} key - The key to find (case-insensitive).
|
||||
* @returns {?string} The actual key name if found, otherwise null.
|
||||
*/
|
||||
function findKey(obj, key) {
|
||||
if (isBuffer(obj)) {
|
||||
return null;
|
||||
@@ -339,16 +377,11 @@ function findKey(obj, key) {
|
||||
|
||||
const _global = (() => {
|
||||
/*eslint no-undef:0*/
|
||||
if (typeof globalThis !== "undefined") return globalThis;
|
||||
return typeof self !== "undefined"
|
||||
? self
|
||||
: typeof window !== "undefined"
|
||||
? window
|
||||
: global;
|
||||
if (typeof globalThis !== 'undefined') return globalThis;
|
||||
return typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : global;
|
||||
})();
|
||||
|
||||
const isContextDefined = (context) =>
|
||||
!isUndefined(context) && context !== _global;
|
||||
const isContextDefined = (context) => !isUndefined(context) && context !== _global;
|
||||
|
||||
/**
|
||||
* Accepts varargs expecting each argument to be an object, then
|
||||
@@ -373,7 +406,7 @@ function merge(/* obj1, obj2, obj3, ... */) {
|
||||
const result = {};
|
||||
const assignValue = (val, key) => {
|
||||
// Skip dangerous property names to prevent prototype pollution
|
||||
if (key === "__proto__" || key === "constructor" || key === "prototype") {
|
||||
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -426,7 +459,7 @@ const extend = (a, b, thisArg, { allOwnKeys } = {}) => {
|
||||
});
|
||||
}
|
||||
},
|
||||
{ allOwnKeys },
|
||||
{ allOwnKeys }
|
||||
);
|
||||
return a;
|
||||
};
|
||||
@@ -455,17 +488,14 @@ const stripBOM = (content) => {
|
||||
* @returns {void}
|
||||
*/
|
||||
const inherits = (constructor, superConstructor, props, descriptors) => {
|
||||
constructor.prototype = Object.create(
|
||||
superConstructor.prototype,
|
||||
descriptors,
|
||||
);
|
||||
Object.defineProperty(constructor.prototype, "constructor", {
|
||||
constructor.prototype = Object.create(superConstructor.prototype, descriptors);
|
||||
Object.defineProperty(constructor.prototype, 'constructor', {
|
||||
value: constructor,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
});
|
||||
Object.defineProperty(constructor, "super", {
|
||||
Object.defineProperty(constructor, 'super', {
|
||||
value: superConstructor.prototype,
|
||||
});
|
||||
props && Object.assign(constructor.prototype, props);
|
||||
@@ -495,20 +525,13 @@ const toFlatObject = (sourceObj, destObj, filter, propFilter) => {
|
||||
i = props.length;
|
||||
while (i-- > 0) {
|
||||
prop = props[i];
|
||||
if (
|
||||
(!propFilter || propFilter(prop, sourceObj, destObj)) &&
|
||||
!merged[prop]
|
||||
) {
|
||||
if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) {
|
||||
destObj[prop] = sourceObj[prop];
|
||||
merged[prop] = true;
|
||||
}
|
||||
}
|
||||
sourceObj = filter !== false && getPrototypeOf(sourceObj);
|
||||
} while (
|
||||
sourceObj &&
|
||||
(!filter || filter(sourceObj, destObj)) &&
|
||||
sourceObj !== Object.prototype
|
||||
);
|
||||
} while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);
|
||||
|
||||
return destObj;
|
||||
};
|
||||
@@ -565,7 +588,7 @@ const isTypedArray = ((TypedArray) => {
|
||||
return (thing) => {
|
||||
return TypedArray && thing instanceof TypedArray;
|
||||
};
|
||||
})(typeof Uint8Array !== "undefined" && getPrototypeOf(Uint8Array));
|
||||
})(typeof Uint8Array !== 'undefined' && getPrototypeOf(Uint8Array));
|
||||
|
||||
/**
|
||||
* For each entry in the object, call the function with the key and value.
|
||||
@@ -608,14 +631,12 @@ const matchAll = (regExp, str) => {
|
||||
};
|
||||
|
||||
/* Checking if the kindOfTest function returns true when passed an HTMLFormElement. */
|
||||
const isHTMLForm = kindOfTest("HTMLFormElement");
|
||||
const isHTMLForm = kindOfTest('HTMLFormElement');
|
||||
|
||||
const toCamelCase = (str) => {
|
||||
return str
|
||||
.toLowerCase()
|
||||
.replace(/[-_\s]([a-z\d])(\w*)/g, function replacer(m, p1, p2) {
|
||||
return p1.toUpperCase() + p2;
|
||||
});
|
||||
return str.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g, function replacer(m, p1, p2) {
|
||||
return p1.toUpperCase() + p2;
|
||||
});
|
||||
};
|
||||
|
||||
/* Creating a function that will check if an object has a property. */
|
||||
@@ -632,7 +653,7 @@ const hasOwnProperty = (
|
||||
*
|
||||
* @returns {boolean} True if value is a RegExp object, otherwise false
|
||||
*/
|
||||
const isRegExp = kindOfTest("RegExp");
|
||||
const isRegExp = kindOfTest('RegExp');
|
||||
|
||||
const reduceDescriptors = (obj, reducer) => {
|
||||
const descriptors = Object.getOwnPropertyDescriptors(obj);
|
||||
@@ -656,10 +677,7 @@ const reduceDescriptors = (obj, reducer) => {
|
||||
const freezeMethods = (obj) => {
|
||||
reduceDescriptors(obj, (descriptor, name) => {
|
||||
// skip restricted props in strict mode
|
||||
if (
|
||||
isFunction(obj) &&
|
||||
["arguments", "caller", "callee"].indexOf(name) !== -1
|
||||
) {
|
||||
if (isFunction(obj) && ['arguments', 'caller', 'callee'].indexOf(name) !== -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -669,7 +687,7 @@ const freezeMethods = (obj) => {
|
||||
|
||||
descriptor.enumerable = false;
|
||||
|
||||
if ("writable" in descriptor) {
|
||||
if ('writable' in descriptor) {
|
||||
descriptor.writable = false;
|
||||
return;
|
||||
}
|
||||
@@ -682,6 +700,14 @@ const freezeMethods = (obj) => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts an array or a delimited string into an object set with values as keys and true as values.
|
||||
* Useful for fast membership checks.
|
||||
*
|
||||
* @param {Array|string} arrayOrString - The array or string to convert.
|
||||
* @param {string} delimiter - The delimiter to use if input is a string.
|
||||
* @returns {Object} An object with keys from the array or string, values set to true.
|
||||
*/
|
||||
const toObjectSet = (arrayOrString, delimiter) => {
|
||||
const obj = {};
|
||||
|
||||
@@ -691,9 +717,7 @@ const toObjectSet = (arrayOrString, delimiter) => {
|
||||
});
|
||||
};
|
||||
|
||||
isArray(arrayOrString)
|
||||
? define(arrayOrString)
|
||||
: define(String(arrayOrString).split(delimiter));
|
||||
isArray(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter));
|
||||
|
||||
return obj;
|
||||
};
|
||||
@@ -701,9 +725,7 @@ const toObjectSet = (arrayOrString, delimiter) => {
|
||||
const noop = () => {};
|
||||
|
||||
const toFiniteNumber = (value, defaultValue) => {
|
||||
return value != null && Number.isFinite((value = +value))
|
||||
? value
|
||||
: defaultValue;
|
||||
return value != null && Number.isFinite((value = +value)) ? value : defaultValue;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -717,11 +739,17 @@ function isSpecCompliantForm(thing) {
|
||||
return !!(
|
||||
thing &&
|
||||
isFunction(thing.append) &&
|
||||
thing[toStringTag] === "FormData" &&
|
||||
thing[toStringTag] === 'FormData' &&
|
||||
thing[iterator]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively converts an object to a JSON-compatible object, handling circular references and Buffers.
|
||||
*
|
||||
* @param {Object} obj - The object to convert.
|
||||
* @returns {Object} The JSON-compatible object.
|
||||
*/
|
||||
const toJSONObject = (obj) => {
|
||||
const stack = new Array(10);
|
||||
|
||||
@@ -736,7 +764,7 @@ const toJSONObject = (obj) => {
|
||||
return source;
|
||||
}
|
||||
|
||||
if (!("toJSON" in source)) {
|
||||
if (!('toJSON' in source)) {
|
||||
stack[i] = source;
|
||||
const target = isArray(source) ? [] : {};
|
||||
|
||||
@@ -757,8 +785,20 @@ const toJSONObject = (obj) => {
|
||||
return visit(obj, 0);
|
||||
};
|
||||
|
||||
const isAsyncFn = kindOfTest("AsyncFunction");
|
||||
/**
|
||||
* Determines if a value is an async function.
|
||||
*
|
||||
* @param {*} thing - The value to test.
|
||||
* @returns {boolean} True if value is an async function, otherwise false.
|
||||
*/
|
||||
const isAsyncFn = kindOfTest('AsyncFunction');
|
||||
|
||||
/**
|
||||
* Determines if a value is thenable (has then and catch methods).
|
||||
*
|
||||
* @param {*} thing - The value to test.
|
||||
* @returns {boolean} True if value is thenable, otherwise false.
|
||||
*/
|
||||
const isThenable = (thing) =>
|
||||
thing &&
|
||||
(isObject(thing) || isFunction(thing)) &&
|
||||
@@ -768,6 +808,14 @@ const isThenable = (thing) =>
|
||||
// original code
|
||||
// https://github.com/DigitalBrainJS/AxiosPromise/blob/16deab13710ec09779922131f3fa5954320f83ab/lib/utils.js#L11-L34
|
||||
|
||||
/**
|
||||
* Provides a cross-platform setImmediate implementation.
|
||||
* Uses native setImmediate if available, otherwise falls back to postMessage or setTimeout.
|
||||
*
|
||||
* @param {boolean} setImmediateSupported - Whether setImmediate is supported.
|
||||
* @param {boolean} postMessageSupported - Whether postMessage is supported.
|
||||
* @returns {Function} A function to schedule a callback asynchronously.
|
||||
*/
|
||||
const _setImmediate = ((setImmediateSupported, postMessageSupported) => {
|
||||
if (setImmediateSupported) {
|
||||
return setImmediate;
|
||||
@@ -776,27 +824,33 @@ const _setImmediate = ((setImmediateSupported, postMessageSupported) => {
|
||||
return postMessageSupported
|
||||
? ((token, callbacks) => {
|
||||
_global.addEventListener(
|
||||
"message",
|
||||
'message',
|
||||
({ source, data }) => {
|
||||
if (source === _global && data === token) {
|
||||
callbacks.length && callbacks.shift()();
|
||||
}
|
||||
},
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
return (cb) => {
|
||||
callbacks.push(cb);
|
||||
_global.postMessage(token, "*");
|
||||
_global.postMessage(token, '*');
|
||||
};
|
||||
})(`axios@${Math.random()}`, [])
|
||||
: (cb) => setTimeout(cb);
|
||||
})(typeof setImmediate === "function", isFunction(_global.postMessage));
|
||||
})(typeof setImmediate === 'function', isFunction(_global.postMessage));
|
||||
|
||||
/**
|
||||
* Schedules a microtask or asynchronous callback as soon as possible.
|
||||
* Uses queueMicrotask if available, otherwise falls back to process.nextTick or _setImmediate.
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
const asap =
|
||||
typeof queueMicrotask !== "undefined"
|
||||
typeof queueMicrotask !== 'undefined'
|
||||
? queueMicrotask.bind(_global)
|
||||
: (typeof process !== "undefined" && process.nextTick) || _setImmediate;
|
||||
: (typeof process !== 'undefined' && process.nextTick) || _setImmediate;
|
||||
|
||||
// *********************
|
||||
|
||||
@@ -821,6 +875,8 @@ export default {
|
||||
isUndefined,
|
||||
isDate,
|
||||
isFile,
|
||||
isReactNativeBlob,
|
||||
isReactNative,
|
||||
isBlob,
|
||||
isRegExp,
|
||||
isFunction,
|
||||
|
||||
Reference in New Issue
Block a user