@vercel/edge
Advanced tools
Comparing version 1.1.4 to 1.2.0
@@ -1,223 +0,14 @@ | ||
interface ModifiedRequest { | ||
/** | ||
* If set, overwrites the incoming headers to the origin request. | ||
* | ||
* This is useful when you want to pass data between a Middleware and a | ||
* Serverless or Edge Function. | ||
* | ||
* @example | ||
* <caption>Add a `x-user-id` header and remove the `Authorization` header</caption> | ||
* | ||
* ```ts | ||
* import { rewrite } from '@vercel/edge'; | ||
* export default async function middleware(request: Request): Promise<Response> { | ||
* const newHeaders = new Headers(request.headers); | ||
* newHeaders.set('x-user-id', 'user_123'); | ||
* newHeaders.delete('authorization'); | ||
* return rewrite(request.url, { | ||
* request: { headers: newHeaders } | ||
* }) | ||
* } | ||
* ``` | ||
*/ | ||
headers?: Headers; | ||
} | ||
interface ExtraResponseInit extends Omit<ResponseInit, 'headers'> { | ||
/** | ||
* These headers will be sent to the user response | ||
* along with the response headers from the origin. | ||
*/ | ||
headers?: HeadersInit; | ||
/** | ||
* Fields to rewrite for the upstream request. | ||
*/ | ||
request?: ModifiedRequest; | ||
} | ||
/** | ||
* Returns a response that rewrites the request to a different URL. | ||
* | ||
* @param destination new URL to rewrite the request to | ||
* @param init Additional options for the response | ||
* | ||
* | ||
* @example | ||
* <caption>Rewrite all feature-flagged requests from `/:path*` to `/experimental/:path*`</caption> | ||
* | ||
* ```ts | ||
* import { rewrite, next } from '@vercel/edge'; | ||
* | ||
* export default async function middleware(req: Request) { | ||
* const flagged = await getFlag(req, 'isExperimental'); | ||
* if (flagged) { | ||
* const url = new URL(req.url); | ||
* url.pathname = `/experimental{url.pathname}`; | ||
* return rewrite(url); | ||
* } | ||
* | ||
* return next(); | ||
* } | ||
* ``` | ||
* | ||
* @example | ||
* <caption>JWT authentication for `/api/:path*` requests</caption> | ||
* | ||
* ```ts | ||
* import { rewrite, next } from '@vercel/edge'; | ||
* | ||
* export default function middleware(req: Request) { | ||
* const auth = checkJwt(req.headers.get('Authorization')); | ||
* if (!checkJwt) { | ||
* return rewrite(new URL('/api/error-unauthorized', req.url)); | ||
* } | ||
* const url = new URL(req.url); | ||
* url.searchParams.set('_userId', auth.userId); | ||
* return rewrite(url); | ||
* } | ||
* | ||
* export const config = { matcher: '/api/users/:path*' }; | ||
* ``` | ||
*/ | ||
declare function rewrite(destination: string | URL, init?: ExtraResponseInit): Response; | ||
/** | ||
* Returns a Response that instructs the system to continue processing the request. | ||
* | ||
* @param init Additional options for the response | ||
* | ||
* @example | ||
* <caption>No-op middleware</caption> | ||
* | ||
* ```ts | ||
* import { next } from '@vercel/edge'; | ||
* | ||
* export default function middleware(_req: Request) { | ||
* return next(); | ||
* } | ||
* ``` | ||
* | ||
* @example | ||
* <caption>Add response headers to all requests</caption> | ||
* | ||
* ```ts | ||
* import { next } from '@vercel/edge'; | ||
* | ||
* export default function middleware(_req: Request) { | ||
* return next({ | ||
* headers: { 'x-from-middleware': 'true' }, | ||
* }) | ||
* } | ||
* ``` | ||
*/ | ||
declare function next(init?: ExtraResponseInit): Response; | ||
export * from '@vercel/functions/headers'; | ||
export { ExtraResponseInit, ModifiedRequest, next, rewrite } from '@vercel/functions/middleware'; | ||
/** | ||
* City of the original client IP as calculated by Vercel Proxy. | ||
*/ | ||
declare const CITY_HEADER_NAME = "x-vercel-ip-city"; | ||
/** | ||
* Country of the original client IP as calculated by Vercel Proxy. | ||
*/ | ||
declare const COUNTRY_HEADER_NAME = "x-vercel-ip-country"; | ||
/** | ||
* Client IP as calculated by Vercel Proxy. | ||
*/ | ||
declare const IP_HEADER_NAME = "x-real-ip"; | ||
/** | ||
* Latitude of the original client IP as calculated by Vercel Proxy. | ||
*/ | ||
declare const LATITUDE_HEADER_NAME = "x-vercel-ip-latitude"; | ||
/** | ||
* Longitude of the original client IP as calculated by Vercel Proxy. | ||
*/ | ||
declare const LONGITUDE_HEADER_NAME = "x-vercel-ip-longitude"; | ||
/** | ||
* Country region of the original client IP calculated by Vercel Proxy. | ||
* | ||
* See [docs](https://vercel.com/docs/concepts/edge-network/headers#x-vercel-ip-country-region). | ||
*/ | ||
declare const REGION_HEADER_NAME = "x-vercel-ip-country-region"; | ||
/** | ||
* Postal code of the original client IP calculated by Vercel Proxy. | ||
*/ | ||
declare const POSTAL_CODE_HEADER_NAME = "x-vercel-ip-postal-code"; | ||
/** | ||
* The request ID for each request generated by Vercel Proxy. | ||
*/ | ||
declare const REQUEST_ID_HEADER_NAME = "x-vercel-id"; | ||
/** | ||
* Unicode characters for emoji flags start at this number, and run up to 127469. | ||
*/ | ||
declare const EMOJI_FLAG_UNICODE_STARTING_POSITION = 127397; | ||
/** | ||
* We define a new type so this function can be reused with | ||
* the global `Request`, `node-fetch` and other types. | ||
*/ | ||
interface Request { | ||
headers: { | ||
get(name: string): string | null; | ||
}; | ||
/* eslint-disable no-var */ | ||
declare global { | ||
// must be `var` to work | ||
var process: { | ||
env: Record<string, string>; | ||
}; | ||
} | ||
/** | ||
* The location information of a given request. | ||
*/ | ||
interface Geo { | ||
/** The city that the request originated from. */ | ||
city?: string; | ||
/** The country that the request originated from. */ | ||
country?: string; | ||
/** The flag emoji for the country the request originated from. */ | ||
flag?: string; | ||
/** The [Vercel Edge Network region](https://vercel.com/docs/concepts/edge-network/regions) that received the request. */ | ||
region?: string; | ||
/** The region part of the ISO 3166-2 code of the client IP. | ||
* See [docs](https://vercel.com/docs/concepts/edge-network/headers#x-vercel-ip-country-region). | ||
*/ | ||
countryRegion?: string; | ||
/** The latitude of the client. */ | ||
latitude?: string; | ||
/** The longitude of the client. */ | ||
longitude?: string; | ||
/** The postal code of the client. */ | ||
postalCode?: string; | ||
} | ||
/** | ||
* Returns the IP address of the request from the headers. | ||
* | ||
* @see {@link IP_HEADER_NAME} | ||
* @param request The incoming request object which provides the IP | ||
*/ | ||
declare function ipAddress(request: Request): string | undefined; | ||
/** | ||
* Returns the location information for the incoming request. | ||
* | ||
* @see {@link CITY_HEADER_NAME} | ||
* @see {@link COUNTRY_HEADER_NAME} | ||
* @see {@link REGION_HEADER_NAME} | ||
* @see {@link LATITUDE_HEADER_NAME} | ||
* @see {@link LONGITUDE_HEADER_NAME} | ||
* @see {@link POSTAL_CODE_HEADER_NAME} | ||
* @param request The incoming request object which provides the geolocation data | ||
*/ | ||
declare function geolocation(request: Request): Geo; | ||
/** | ||
* Builds a response object from a serializable JavaScript object: | ||
* - sets the 'Content-Type' response header to 'application/json' | ||
* - sets the response body from provided data | ||
* | ||
* @see {@link https://fetch.spec.whatwg.org/#dom-response-json} | ||
* @param data serialized data | ||
* @param init optional custom response status, statusText and headers | ||
* | ||
* @example | ||
* <caption>Building a JSON response</caption> | ||
* | ||
* ```ts | ||
* import { json } from '@vercel/edge'; | ||
* | ||
* const response = json({ notification: { success: true, content: 'worked' } }, { headers: {'x-custom': '1' }}) | ||
* ``` | ||
*/ | ||
declare function json(data: any, init?: ResponseInit): Response; | ||
/** | ||
* An extension to the standard `Request` object that is passed to every Edge Function. | ||
@@ -274,11 +65,2 @@ * | ||
/* eslint-disable no-var */ | ||
declare global { | ||
// must be `var` to work | ||
var process: { | ||
env: Record<string, string>; | ||
}; | ||
} | ||
export { CITY_HEADER_NAME, COUNTRY_HEADER_NAME, EMOJI_FLAG_UNICODE_STARTING_POSITION, ExtraResponseInit, Geo, IP_HEADER_NAME, LATITUDE_HEADER_NAME, LONGITUDE_HEADER_NAME, ModifiedRequest, POSTAL_CODE_HEADER_NAME, REGION_HEADER_NAME, REQUEST_ID_HEADER_NAME, RequestContext, geolocation, ipAddress, json, next, rewrite }; | ||
export { RequestContext }; |
"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) => { | ||
@@ -18,126 +23,179 @@ for (var name in all) | ||
}; | ||
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default")); | ||
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, { | ||
CITY_HEADER_NAME: () => CITY_HEADER_NAME, | ||
COUNTRY_HEADER_NAME: () => COUNTRY_HEADER_NAME, | ||
EMOJI_FLAG_UNICODE_STARTING_POSITION: () => EMOJI_FLAG_UNICODE_STARTING_POSITION, | ||
IP_HEADER_NAME: () => IP_HEADER_NAME, | ||
LATITUDE_HEADER_NAME: () => LATITUDE_HEADER_NAME, | ||
LONGITUDE_HEADER_NAME: () => LONGITUDE_HEADER_NAME, | ||
POSTAL_CODE_HEADER_NAME: () => POSTAL_CODE_HEADER_NAME, | ||
REGION_HEADER_NAME: () => REGION_HEADER_NAME, | ||
REQUEST_ID_HEADER_NAME: () => REQUEST_ID_HEADER_NAME, | ||
geolocation: () => geolocation, | ||
ipAddress: () => ipAddress, | ||
json: () => json, | ||
next: () => next, | ||
rewrite: () => rewrite | ||
// ../functions/headers.js | ||
var require_headers = __commonJS({ | ||
"../functions/headers.js"(exports, module2) { | ||
"use strict"; | ||
var __defProp2 = Object.defineProperty; | ||
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames2 = Object.getOwnPropertyNames; | ||
var __hasOwnProp2 = Object.prototype.hasOwnProperty; | ||
var __export2 = (target, all) => { | ||
for (var name in all) | ||
__defProp2(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
var __copyProps2 = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames2(from)) | ||
if (!__hasOwnProp2.call(to, key) && key !== except) | ||
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable }); | ||
} | ||
return to; | ||
}; | ||
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod); | ||
var headers_exports = {}; | ||
__export2(headers_exports, { | ||
CITY_HEADER_NAME: () => CITY_HEADER_NAME, | ||
COUNTRY_HEADER_NAME: () => COUNTRY_HEADER_NAME, | ||
EMOJI_FLAG_UNICODE_STARTING_POSITION: () => EMOJI_FLAG_UNICODE_STARTING_POSITION, | ||
IP_HEADER_NAME: () => IP_HEADER_NAME, | ||
LATITUDE_HEADER_NAME: () => LATITUDE_HEADER_NAME, | ||
LONGITUDE_HEADER_NAME: () => LONGITUDE_HEADER_NAME, | ||
POSTAL_CODE_HEADER_NAME: () => POSTAL_CODE_HEADER_NAME, | ||
REGION_HEADER_NAME: () => REGION_HEADER_NAME, | ||
REQUEST_ID_HEADER_NAME: () => REQUEST_ID_HEADER_NAME, | ||
geolocation: () => geolocation, | ||
ipAddress: () => ipAddress | ||
}); | ||
module2.exports = __toCommonJS2(headers_exports); | ||
var CITY_HEADER_NAME = "x-vercel-ip-city"; | ||
var COUNTRY_HEADER_NAME = "x-vercel-ip-country"; | ||
var IP_HEADER_NAME = "x-real-ip"; | ||
var LATITUDE_HEADER_NAME = "x-vercel-ip-latitude"; | ||
var LONGITUDE_HEADER_NAME = "x-vercel-ip-longitude"; | ||
var REGION_HEADER_NAME = "x-vercel-ip-country-region"; | ||
var POSTAL_CODE_HEADER_NAME = "x-vercel-ip-postal-code"; | ||
var REQUEST_ID_HEADER_NAME = "x-vercel-id"; | ||
var EMOJI_FLAG_UNICODE_STARTING_POSITION = 127397; | ||
function getHeader(headers, key) { | ||
return headers.get(key) ?? void 0; | ||
} | ||
function getHeaderWithDecode(request, key) { | ||
const header = getHeader(request.headers, key); | ||
return header ? decodeURIComponent(header) : void 0; | ||
} | ||
function getFlag(countryCode) { | ||
const regex = new RegExp("^[A-Z]{2}$").test(countryCode); | ||
if (!countryCode || !regex) | ||
return void 0; | ||
return String.fromCodePoint( | ||
...countryCode.split("").map((char) => EMOJI_FLAG_UNICODE_STARTING_POSITION + char.charCodeAt(0)) | ||
); | ||
} | ||
function ipAddress(input) { | ||
const headers = "headers" in input ? input.headers : input; | ||
return getHeader(headers, IP_HEADER_NAME); | ||
} | ||
function getRegionFromRequestId(requestId) { | ||
if (!requestId) { | ||
return "dev1"; | ||
} | ||
return requestId.split(":")[0]; | ||
} | ||
function geolocation(request) { | ||
return { | ||
// city name may be encoded to support multi-byte characters | ||
city: getHeaderWithDecode(request, CITY_HEADER_NAME), | ||
country: getHeader(request.headers, COUNTRY_HEADER_NAME), | ||
flag: getFlag(getHeader(request.headers, COUNTRY_HEADER_NAME)), | ||
countryRegion: getHeader(request.headers, REGION_HEADER_NAME), | ||
region: getRegionFromRequestId( | ||
getHeader(request.headers, REQUEST_ID_HEADER_NAME) | ||
), | ||
latitude: getHeader(request.headers, LATITUDE_HEADER_NAME), | ||
longitude: getHeader(request.headers, LONGITUDE_HEADER_NAME), | ||
postalCode: getHeader(request.headers, POSTAL_CODE_HEADER_NAME) | ||
}; | ||
} | ||
} | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
// src/middleware-helpers.ts | ||
function handleMiddlewareField(init, headers) { | ||
if (init?.request?.headers) { | ||
if (!(init.request.headers instanceof Headers)) { | ||
throw new Error("request.headers must be an instance of Headers"); | ||
// ../functions/middleware.js | ||
var require_middleware = __commonJS({ | ||
"../functions/middleware.js"(exports, module2) { | ||
"use strict"; | ||
var __defProp2 = Object.defineProperty; | ||
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropNames2 = Object.getOwnPropertyNames; | ||
var __hasOwnProp2 = Object.prototype.hasOwnProperty; | ||
var __export2 = (target, all) => { | ||
for (var name in all) | ||
__defProp2(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
var __copyProps2 = (to, from, except, desc) => { | ||
if (from && typeof from === "object" || typeof from === "function") { | ||
for (let key of __getOwnPropNames2(from)) | ||
if (!__hasOwnProp2.call(to, key) && key !== except) | ||
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable }); | ||
} | ||
return to; | ||
}; | ||
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod); | ||
var middleware_exports = {}; | ||
__export2(middleware_exports, { | ||
next: () => next2, | ||
rewrite: () => rewrite2 | ||
}); | ||
module2.exports = __toCommonJS2(middleware_exports); | ||
function handleMiddlewareField(init, headers) { | ||
if (init?.request?.headers) { | ||
if (!(init.request.headers instanceof Headers)) { | ||
throw new Error("request.headers must be an instance of Headers"); | ||
} | ||
const keys = []; | ||
for (const [key, value] of init.request.headers) { | ||
headers.set("x-middleware-request-" + key, value); | ||
keys.push(key); | ||
} | ||
headers.set("x-middleware-override-headers", keys.join(",")); | ||
} | ||
} | ||
const keys = []; | ||
for (const [key, value] of init.request.headers) { | ||
headers.set("x-middleware-request-" + key, value); | ||
keys.push(key); | ||
function rewrite2(destination, init) { | ||
const headers = new Headers(init?.headers ?? {}); | ||
headers.set("x-middleware-rewrite", String(destination)); | ||
handleMiddlewareField(init, headers); | ||
return new Response(null, { | ||
...init, | ||
headers | ||
}); | ||
} | ||
headers.set("x-middleware-override-headers", keys.join(",")); | ||
function next2(init) { | ||
const headers = new Headers(init?.headers ?? {}); | ||
headers.set("x-middleware-next", "1"); | ||
handleMiddlewareField(init, headers); | ||
return new Response(null, { | ||
...init, | ||
headers | ||
}); | ||
} | ||
} | ||
} | ||
function rewrite(destination, init) { | ||
const headers = new Headers(init?.headers ?? {}); | ||
headers.set("x-middleware-rewrite", String(destination)); | ||
handleMiddlewareField(init, headers); | ||
return new Response(null, { | ||
...init, | ||
headers | ||
}); | ||
} | ||
function next(init) { | ||
const headers = new Headers(init?.headers ?? {}); | ||
headers.set("x-middleware-next", "1"); | ||
handleMiddlewareField(init, headers); | ||
return new Response(null, { | ||
...init, | ||
headers | ||
}); | ||
} | ||
}); | ||
// src/edge-headers.ts | ||
var CITY_HEADER_NAME = "x-vercel-ip-city"; | ||
var COUNTRY_HEADER_NAME = "x-vercel-ip-country"; | ||
var IP_HEADER_NAME = "x-real-ip"; | ||
var LATITUDE_HEADER_NAME = "x-vercel-ip-latitude"; | ||
var LONGITUDE_HEADER_NAME = "x-vercel-ip-longitude"; | ||
var REGION_HEADER_NAME = "x-vercel-ip-country-region"; | ||
var POSTAL_CODE_HEADER_NAME = "x-vercel-ip-postal-code"; | ||
var REQUEST_ID_HEADER_NAME = "x-vercel-id"; | ||
var EMOJI_FLAG_UNICODE_STARTING_POSITION = 127397; | ||
function getHeader(request, key) { | ||
return request.headers.get(key) ?? void 0; | ||
} | ||
function getFlag(countryCode) { | ||
const regex = new RegExp("^[A-Z]{2}$").test(countryCode); | ||
if (!countryCode || !regex) | ||
return void 0; | ||
return String.fromCodePoint( | ||
...countryCode.split("").map((char) => EMOJI_FLAG_UNICODE_STARTING_POSITION + char.charCodeAt(0)) | ||
); | ||
} | ||
function ipAddress(request) { | ||
console.warn( | ||
"This method will be removed in the next major version. Use `import { ipAddress } from @vercel/functions` instead." | ||
); | ||
return getHeader(request, IP_HEADER_NAME); | ||
} | ||
function getRegionFromRequestId(requestId) { | ||
if (!requestId) { | ||
return "dev1"; | ||
} | ||
return requestId.split(":")[0]; | ||
} | ||
function geolocation(request) { | ||
console.warn( | ||
"This method will be removed in the next major version. Use `import { geolocation } from @vercel/functions` instead." | ||
); | ||
return { | ||
city: getHeader(request, CITY_HEADER_NAME), | ||
country: getHeader(request, COUNTRY_HEADER_NAME), | ||
flag: getFlag(getHeader(request, COUNTRY_HEADER_NAME)), | ||
countryRegion: getHeader(request, REGION_HEADER_NAME), | ||
region: getRegionFromRequestId(getHeader(request, REQUEST_ID_HEADER_NAME)), | ||
latitude: getHeader(request, LATITUDE_HEADER_NAME), | ||
longitude: getHeader(request, LONGITUDE_HEADER_NAME), | ||
postalCode: getHeader(request, POSTAL_CODE_HEADER_NAME) | ||
}; | ||
} | ||
// src/response.ts | ||
function json(data, init) { | ||
return Response.json(data, init); | ||
} | ||
// src/index.ts | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
ExtraResponseInit: () => import_middleware.ExtraResponseInit, | ||
ModifiedRequest: () => import_middleware.ModifiedRequest, | ||
next: () => import_middleware.next, | ||
rewrite: () => import_middleware.rewrite | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
__reExport(src_exports, __toESM(require_headers()), module.exports); | ||
var import_middleware = __toESM(require_middleware()); | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
CITY_HEADER_NAME, | ||
COUNTRY_HEADER_NAME, | ||
EMOJI_FLAG_UNICODE_STARTING_POSITION, | ||
IP_HEADER_NAME, | ||
LATITUDE_HEADER_NAME, | ||
LONGITUDE_HEADER_NAME, | ||
POSTAL_CODE_HEADER_NAME, | ||
REGION_HEADER_NAME, | ||
REQUEST_ID_HEADER_NAME, | ||
geolocation, | ||
ipAddress, | ||
json, | ||
ExtraResponseInit, | ||
ModifiedRequest, | ||
next, | ||
rewrite | ||
}); |
{ | ||
"name": "@vercel/edge", | ||
"version": "1.1.4", | ||
"version": "1.2.0", | ||
"license": "Apache-2.0", | ||
@@ -26,3 +26,4 @@ "main": "dist/index.js", | ||
"typedoc-plugin-mdn-links": "3.0.3", | ||
"typescript": "4.9.5" | ||
"typescript": "4.9.5", | ||
"@vercel/functions": "1.5.2" | ||
}, | ||
@@ -29,0 +30,0 @@ "scripts": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
33320
10
455
1