@sanity/preview-url-secret
Advanced tools
Comparing version 1.6.19 to 1.6.20-canary.1
@@ -9,2 +9,9 @@ <!-- markdownlint-disable --><!-- textlint-disable --> | ||
## [1.6.20](https://github.com/sanity-io/visual-editing/compare/preview-url-secret-v1.6.19...preview-url-secret-v1.6.20) (2024-08-12) | ||
### Bug Fixes | ||
* **deps:** update dependency @sanity/client to v6.21.2 ([#1749](https://github.com/sanity-io/visual-editing/issues/1749)) ([b9efdd2](https://github.com/sanity-io/visual-editing/commit/b9efdd2a672fdef518bc22a29a25992c938ba1ef)) | ||
## [1.6.19](https://github.com/sanity-io/visual-editing/compare/preview-url-secret-v1.6.18...preview-url-secret-v1.6.19) (2024-08-02) | ||
@@ -11,0 +18,0 @@ |
@@ -1,1 +0,24 @@ | ||
const e="sanity.previewUrlSecret",t="sanity-preview-url-secret",s="2023-11-09",a="sanity-preview-secret",r="sanity-preview-pathname",i="development"===process.env.NODE_ENV,n=3600,d=`*[_type == "${e}" && secret == $secret && dateTime(_updatedAt) > dateTime(now()) - 3600][0]{\n _id,\n _updatedAt,\n secret,\n studioUrl,\n}`,p=`*[_type == "${e}" && dateTime(_updatedAt) <= dateTime(now()) - 3600]`,c="sanity.preview-url-secret";export{n as S,s as a,r as b,e as c,p as d,d as f,i,t as s,c as t,a as u};//# sourceMappingURL=constants.js.map | ||
const schemaType = "sanity.previewUrlSecret"; | ||
const schemaIdPrefix = "sanity-preview-url-secret"; | ||
const apiVersion = "2023-11-09"; | ||
const urlSearchParamPreviewSecret = "sanity-preview-secret"; | ||
const urlSearchParamPreviewPathname = "sanity-preview-pathname"; | ||
const isDev = process.env.NODE_ENV === "development"; | ||
const SECRET_TTL = 60 * 60; | ||
const fetchSecretQuery = ( | ||
/* groq */ | ||
`*[_type == "${schemaType}" && secret == $secret && dateTime(_updatedAt) > dateTime(now()) - ${SECRET_TTL}][0]{ | ||
_id, | ||
_updatedAt, | ||
secret, | ||
studioUrl, | ||
}` | ||
); | ||
const deleteExpiredSecretsQuery = ( | ||
/* groq */ | ||
`*[_type == "${schemaType}" && dateTime(_updatedAt) <= dateTime(now()) - ${SECRET_TTL}]` | ||
); | ||
const tag = "sanity.preview-url-secret"; | ||
export { SECRET_TTL, apiVersion, deleteExpiredSecretsQuery, fetchSecretQuery, isDev, schemaIdPrefix, schemaType, tag, urlSearchParamPreviewPathname, urlSearchParamPreviewSecret }; | ||
//# sourceMappingURL=constants.js.map |
@@ -1,1 +0,33 @@ | ||
import{uuid as t}from"@sanity/uuid";import{a as e,S as a,s as r,c as n,t as s,d as o}from"./_chunks-es/constants.js";async function c(c,i,p,u,l=t()){const y=c.withConfig({apiVersion:e});try{const t=new Date(Date.now()+1e3*a),e=`${r}.${l}`,o=function(){if(typeof crypto<"u"){const t=new Uint8Array(16);crypto.getRandomValues(t);let e="";for(let a=0;a<t.length;a++)e+=t[a].toString(16).padStart(2,"0");return e=btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/[=]+$/,""),e}return Math.random().toString(36).slice(2)}(),c=y.patch(e).set({secret:o,source:i,studioUrl:p,userId:u});return await y.transaction().createOrReplace({_id:e,_type:n}).patch(c).commit({tag:s}),{secret:o,expiresAt:t}}finally{await y.delete({query:o})}}export{c as createPreviewSecret};//# sourceMappingURL=create-secret.js.map | ||
import { uuid } from '@sanity/uuid'; | ||
import { apiVersion, SECRET_TTL, schemaIdPrefix, schemaType, tag, deleteExpiredSecretsQuery } from './_chunks-es/constants.js'; | ||
function generateUrlSecret() { | ||
if (typeof crypto !== "undefined") { | ||
const array = new Uint8Array(16); | ||
crypto.getRandomValues(array); | ||
let key = ""; | ||
for (let i = 0; i < array.length; i++) { | ||
key += array[i].toString(16).padStart(2, "0"); | ||
} | ||
key = btoa(key).replace(/\+/g, "-").replace(/\//g, "_").replace(/[=]+$/, ""); | ||
return key; | ||
} | ||
return Math.random().toString(36).slice(2); | ||
} | ||
async function createPreviewSecret(_client, source, studioUrl, userId, id = uuid()) { | ||
const client = _client.withConfig({ apiVersion }); | ||
try { | ||
const expiresAt = new Date(Date.now() + 1e3 * SECRET_TTL); | ||
const _id = `${schemaIdPrefix}.${id}`; | ||
const newSecret = generateUrlSecret(); | ||
const patch = client.patch(_id).set({ secret: newSecret, source, studioUrl, userId }); | ||
await client.transaction().createOrReplace({ _id, _type: schemaType }).patch(patch).commit({ tag }); | ||
return { secret: newSecret, expiresAt }; | ||
} finally { | ||
await client.delete({ query: deleteExpiredSecretsQuery }); | ||
} | ||
} | ||
export { createPreviewSecret }; | ||
//# sourceMappingURL=create-secret.js.map |
@@ -1,1 +0,49 @@ | ||
import{u as e,b as t}from"./_chunks-es/constants.js";function r(r){const{draftMode:n,previewMode:a,origin:o=(typeof location>"u"?"https://localhost":location.origin)}=r,i=(null==a?void 0:a.enable)||(null==n?void 0:n.enable);let{preview:s="/"}=r;const c=new URL(s,o),h=i?new URL(i,o):void 0;return async n=>{try{if(n.previewSearchParam){const e=new URL(n.previewSearchParam,c);e.origin===c.origin&&(s=`${e.pathname}${e.search}`)}else if(n.referrer){const e=new URL(n.referrer);e.origin===c.origin&&(s=`${e.pathname}${e.search}`)}}catch{}typeof location<"u"&&location.origin===c.origin&&n.studioBasePath&&(s.startsWith(`${n.studioBasePath}/`)||s===n.studioBasePath)&&(s=r.preview||"/");const a=new URL(s,c);if(h){const r=new URL(h),{searchParams:o}=r;return o.set(e,n.previewUrlSecret),a.pathname!==r.pathname&&o.set(t,`${a.pathname}${a.search}`),r.toString()}return a.toString()}}export{r as definePreviewUrl};//# sourceMappingURL=define-preview-url.js.map | ||
import { urlSearchParamPreviewSecret, urlSearchParamPreviewPathname } from './_chunks-es/constants.js'; | ||
function definePreviewUrl(options) { | ||
const { | ||
draftMode, | ||
previewMode, | ||
origin = typeof location === "undefined" ? "https://localhost" : location.origin | ||
} = options; | ||
const enableUrl = previewMode?.enable || draftMode?.enable; | ||
let { preview = "/" } = options; | ||
const productionUrl = new URL(preview, origin); | ||
const enablePreviewModeUrl = enableUrl ? new URL(enableUrl, origin) : void 0; | ||
return async (context) => { | ||
try { | ||
if (context.previewSearchParam) { | ||
const restoredUrl = new URL(context.previewSearchParam, productionUrl); | ||
if (restoredUrl.origin === productionUrl.origin) { | ||
preview = `${restoredUrl.pathname}${restoredUrl.search}`; | ||
} | ||
} else if (context.referrer) { | ||
const referrerUrl = new URL(context.referrer); | ||
if (referrerUrl.origin === productionUrl.origin) { | ||
preview = `${referrerUrl.pathname}${referrerUrl.search}`; | ||
} | ||
} | ||
} catch { | ||
} | ||
if (typeof location !== "undefined" && location.origin === productionUrl.origin && context.studioBasePath && (preview.startsWith(`${context.studioBasePath}/`) || preview === context.studioBasePath)) { | ||
preview = options.preview || "/"; | ||
} | ||
const previewUrl = new URL(preview, productionUrl); | ||
if (enablePreviewModeUrl) { | ||
const enablePreviewModeRequestUrl = new URL(enablePreviewModeUrl); | ||
const { searchParams } = enablePreviewModeRequestUrl; | ||
searchParams.set(urlSearchParamPreviewSecret, context.previewUrlSecret); | ||
if (previewUrl.pathname !== enablePreviewModeRequestUrl.pathname) { | ||
searchParams.set( | ||
urlSearchParamPreviewPathname, | ||
`${previewUrl.pathname}${previewUrl.search}` | ||
); | ||
} | ||
return enablePreviewModeRequestUrl.toString(); | ||
} | ||
return previewUrl.toString(); | ||
}; | ||
} | ||
export { definePreviewUrl }; | ||
//# sourceMappingURL=define-preview-url.js.map |
@@ -1,1 +0,11 @@ | ||
import{b as s}from"./_chunks-es/constants.js";function r(r){return r.searchParams.has(s)?new URL(r.searchParams.get(s),r.origin):r}export{r as getRedirectTo};//# sourceMappingURL=get-redirect-to.js.map | ||
import { urlSearchParamPreviewPathname } from './_chunks-es/constants.js'; | ||
function getRedirectTo(url) { | ||
if (url.searchParams.has(urlSearchParamPreviewPathname)) { | ||
return new URL(url.searchParams.get(urlSearchParamPreviewPathname), url.origin); | ||
} | ||
return url; | ||
} | ||
export { getRedirectTo }; | ||
//# sourceMappingURL=get-redirect-to.js.map |
@@ -1,1 +0,98 @@ | ||
import{a as e,u as t,b as r,f as i,t as s,i as o}from"./_chunks-es/constants.js";async function n(n,a,l="Cloudflare-Workers"===(e=>null==(e=globalThis.navigator)?void 0:e.userAgent)()){const c=function(t){if(!t)throw new TypeError("`client` is required");if(!t.config().token)throw new TypeError("`client` must have a `token` specified");return t.withConfig({apiVersion:e,useCdn:!1,perspective:"published",resultSourceMap:!1,stega:!1})}(n);let u;try{u=function(e){const i=new URL(e,"http://localhost"),s=i.searchParams.get(t);if(!s)throw new Error("Missing secret");let o;const n=i.searchParams.get(r);if(n){const{pathname:e,search:t,hash:r}=new URL(n,"http://localhost");o=`${e}${t}${r}`}return{secret:s,redirectTo:o}}(a)}catch(e){return o&&console.error("Failed to parse preview URL",e,{previewUrl:a,client:c}),{isValid:!1}}const{isValid:d,studioUrl:h}=await async function(e,t,r){if(typeof EdgeRuntime<"u"&&await new Promise((e=>setTimeout(e,300))),!t||!t.trim())return{isValid:!1,studioUrl:null};const o=await e.fetch(i,{secret:t},{tag:s,...r?void 0:{cache:"no-store"}});return null!=o&&o._id&&null!=o&&o._updatedAt&&null!=o&&o.secret?{isValid:t===o.secret,studioUrl:o.studioUrl}:{isValid:!1,studioUrl:null}}(c,u.secret,l),p=d?u.redirectTo:void 0;let f;if(d)try{f=new URL(h).origin}catch(e){o&&console.error("Failed to parse studioUrl",e,{previewUrl:a,studioUrl:h})}return{isValid:d,redirectTo:p,studioOrigin:f}}export{r as urlSearchParamPreviewPathname,t as urlSearchParamPreviewSecret,n as validatePreviewUrl};//# sourceMappingURL=index.js.map | ||
import { apiVersion, urlSearchParamPreviewSecret, urlSearchParamPreviewPathname, fetchSecretQuery, tag, isDev } from './_chunks-es/constants.js'; | ||
function createClientWithConfig(client) { | ||
if (!client) { | ||
throw new TypeError("`client` is required"); | ||
} | ||
if (!client.config().token) { | ||
throw new TypeError("`client` must have a `token` specified"); | ||
} | ||
return client.withConfig({ | ||
// Userland might be using an API version that's too old to use perspectives | ||
apiVersion, | ||
// We can't use the CDN, the secret is typically validated right after it's created | ||
useCdn: false, | ||
// The documents that hold secrets are never drafts | ||
perspective: "published", | ||
// Don't waste time returning a source map, we don't need it | ||
resultSourceMap: false, | ||
// @ts-expect-error - If stega is enabled, make sure it's disabled | ||
stega: false | ||
}); | ||
} | ||
function parsePreviewUrl(unsafeUrl) { | ||
const url = new URL(unsafeUrl, "http://localhost"); | ||
const secret = url.searchParams.get(urlSearchParamPreviewSecret); | ||
if (!secret) { | ||
throw new Error("Missing secret"); | ||
} | ||
let redirectTo = void 0; | ||
const unsafeRedirectTo = url.searchParams.get(urlSearchParamPreviewPathname); | ||
if (unsafeRedirectTo) { | ||
const { pathname, search, hash } = new URL(unsafeRedirectTo, "http://localhost"); | ||
redirectTo = `${pathname}${search}${hash}`; | ||
} | ||
return { secret, redirectTo }; | ||
} | ||
async function validateSecret(client, secret, disableCacheNoStore) { | ||
if (typeof EdgeRuntime !== "undefined") { | ||
await new Promise((resolve) => setTimeout(resolve, 300)); | ||
} | ||
if (!secret || !secret.trim()) { | ||
return { isValid: false, studioUrl: null }; | ||
} | ||
const result = await client.fetch( | ||
fetchSecretQuery, | ||
{ secret }, | ||
{ | ||
tag, | ||
// In CloudFlare Workers we can't pass the cache header | ||
...!disableCacheNoStore ? { cache: "no-store" } : void 0 | ||
} | ||
); | ||
if (!result?._id || !result?._updatedAt || !result?.secret) { | ||
return { isValid: false, studioUrl: null }; | ||
} | ||
return { isValid: secret === result.secret, studioUrl: result.studioUrl }; | ||
} | ||
async function validatePreviewUrl(_client, previewUrl, disableCacheNoStore = globalThis.navigator?.userAgent === "Cloudflare-Workers") { | ||
const client = createClientWithConfig(_client); | ||
let parsedPreviewUrl; | ||
try { | ||
parsedPreviewUrl = parsePreviewUrl(previewUrl); | ||
} catch (error) { | ||
if (isDev) { | ||
console.error("Failed to parse preview URL", error, { | ||
previewUrl, | ||
client | ||
}); | ||
} | ||
return { isValid: false }; | ||
} | ||
const { isValid, studioUrl } = await validateSecret( | ||
client, | ||
parsedPreviewUrl.secret, | ||
disableCacheNoStore | ||
); | ||
const redirectTo = isValid ? parsedPreviewUrl.redirectTo : void 0; | ||
let studioOrigin; | ||
if (isValid) { | ||
try { | ||
studioOrigin = new URL(studioUrl).origin; | ||
} catch (error) { | ||
if (isDev) { | ||
console.error("Failed to parse studioUrl", error, { | ||
previewUrl, | ||
studioUrl | ||
}); | ||
} | ||
} | ||
} | ||
return { isValid, redirectTo, studioOrigin }; | ||
} | ||
export { urlSearchParamPreviewPathname, urlSearchParamPreviewSecret, validatePreviewUrl }; | ||
//# sourceMappingURL=index.js.map |
@@ -1,1 +0,84 @@ | ||
import{defineType as e,definePlugin as t}from"sanity";import{c as i,S as s}from"./_chunks-es/constants.js";import{LockIcon as n,CloseCircleIcon as r,CheckmarkCircleIcon as o}from"@sanity/icons";const a=e({type:"document",icon:n,name:i,title:"@sanity/preview-url-secret",readOnly:!0,fields:[{type:"string",name:"secret",title:"Secret"},{type:"string",name:"source",title:"Source Tool"},{type:"string",name:"studioUrl",title:"Studio URL"},{type:"string",name:"userId",title:"Sanity User ID"}],preview:{select:{source:"source",studioUrl:"studioUrl",updatedAt:"_updatedAt"},prepare(e){const t=e.studioUrl?new URL(e.studioUrl,location.origin):void 0,i=new Date(e.updatedAt).getTime(),n=new Date(i+1e3*s),a=n<new Date,c=a?r:o;return{title:t?`${t.host}${t.pathname}`:e.source,subtitle:a?"Expired":`Expires in ${Math.round((n.getTime()-Date.now())/6e4)} minutes`,media:c}}}}),c=t((()=>({name:"sanity-plugin-debug-secrets",schema:{types:[a]},document:{actions:(e,t)=>t.schemaType!==i?e:e.filter((({action:e})=>"delete"===e)),inspectors:(e,t)=>t.documentType!==i?e:[],unstable_fieldActions:(e,t)=>t.schemaType.name!==i?e:[]}})));export{c as debugSecrets};//# sourceMappingURL=sanity-plugin-debug-secrets.js.map | ||
import { defineType, definePlugin } from 'sanity'; | ||
import { schemaType, SECRET_TTL } from './_chunks-es/constants.js'; | ||
import { LockIcon, CloseCircleIcon, CheckmarkCircleIcon } from '@sanity/icons'; | ||
const debugUrlSecretsType = defineType({ | ||
type: "document", | ||
icon: LockIcon, | ||
name: schemaType, | ||
title: "@sanity/preview-url-secret", | ||
readOnly: true, | ||
fields: [ | ||
{ | ||
type: "string", | ||
name: "secret", | ||
title: "Secret" | ||
}, | ||
{ | ||
type: "string", | ||
name: "source", | ||
title: "Source Tool" | ||
}, | ||
{ | ||
type: "string", | ||
name: "studioUrl", | ||
title: "Studio URL" | ||
}, | ||
{ | ||
type: "string", | ||
name: "userId", | ||
title: "Sanity User ID" | ||
} | ||
], | ||
preview: { | ||
select: { | ||
source: "source", | ||
studioUrl: "studioUrl", | ||
updatedAt: "_updatedAt" | ||
}, | ||
prepare(data) { | ||
const url = data.studioUrl ? new URL(data.studioUrl, location.origin) : void 0; | ||
const updatedAt = new Date(data.updatedAt).getTime(); | ||
const expiresAt = new Date(updatedAt + 1e3 * SECRET_TTL); | ||
const expired = expiresAt < /* @__PURE__ */ new Date(); | ||
const icon = expired ? CloseCircleIcon : CheckmarkCircleIcon; | ||
return { | ||
title: url ? `${url.host}${url.pathname}` : data.source, | ||
subtitle: expired ? "Expired" : `Expires in ${Math.round((expiresAt.getTime() - Date.now()) / (1e3 * 60))} minutes`, | ||
media: icon | ||
}; | ||
} | ||
} | ||
}); | ||
const debugSecrets = definePlugin(() => { | ||
return { | ||
name: "sanity-plugin-debug-secrets", | ||
schema: { | ||
types: [debugUrlSecretsType] | ||
}, | ||
document: { | ||
actions: (prev, context) => { | ||
if (context.schemaType !== schemaType) { | ||
return prev; | ||
} | ||
return prev.filter(({ action }) => action === "delete"); | ||
}, | ||
inspectors: (prev, context) => { | ||
if (context.documentType !== schemaType) { | ||
return prev; | ||
} | ||
return []; | ||
}, | ||
unstable_fieldActions: (prev, context) => { | ||
if (context.schemaType.name !== schemaType) { | ||
return prev; | ||
} | ||
return []; | ||
} | ||
} | ||
}; | ||
}); | ||
export { debugSecrets }; | ||
//# sourceMappingURL=sanity-plugin-debug-secrets.js.map |
@@ -1,1 +0,20 @@ | ||
import{b as s,u as e}from"./_chunks-es/constants.js";function a(a){const r=new URL(a);return r.searchParams.delete(s),r.searchParams.delete(e),r}function r(s){return s.searchParams.has(e)}function n(a,r,n){const t=new URL(a);return t.searchParams.set(e,r),t.searchParams.set(s,n),t}export{r as hasSecretSearchParams,n as setSecretSearchParams,a as withoutSecretSearchParams};//# sourceMappingURL=without-secret-search-params.js.map | ||
import { urlSearchParamPreviewPathname, urlSearchParamPreviewSecret } from './_chunks-es/constants.js'; | ||
function withoutSecretSearchParams(url) { | ||
const newUrl = new URL(url); | ||
newUrl.searchParams.delete(urlSearchParamPreviewPathname); | ||
newUrl.searchParams.delete(urlSearchParamPreviewSecret); | ||
return newUrl; | ||
} | ||
function hasSecretSearchParams(url) { | ||
return url.searchParams.has(urlSearchParamPreviewSecret); | ||
} | ||
function setSecretSearchParams(url, secret, redirectTo) { | ||
const newUrl = new URL(url); | ||
newUrl.searchParams.set(urlSearchParamPreviewSecret, secret); | ||
newUrl.searchParams.set(urlSearchParamPreviewPathname, redirectTo); | ||
return newUrl; | ||
} | ||
export { hasSecretSearchParams, setSecretSearchParams, withoutSecretSearchParams }; | ||
//# sourceMappingURL=without-secret-search-params.js.map |
{ | ||
"name": "@sanity/preview-url-secret", | ||
"version": "1.6.19", | ||
"version": "1.6.20-canary.1", | ||
"homepage": "https://github.com/sanity-io/visual-editing/tree/main/packages/preview-url-secret#readme", | ||
@@ -134,19 +134,19 @@ "bugs": { | ||
"devDependencies": { | ||
"@repo/channels": "0.4.0", | ||
"@sanity/client": "^6.21.1", | ||
"@sanity/icons": "^3.2.0", | ||
"@sanity/pkg-utils": "6.9.3", | ||
"@typescript-eslint/eslint-plugin": "^7.13.1", | ||
"@typescript-eslint/parser": "^7.13.1", | ||
"@sanity/client": "^6.21.3", | ||
"@sanity/icons": "^3.4.0", | ||
"@sanity/pkg-utils": "6.11.1", | ||
"@typescript-eslint/eslint-plugin": "^7.18.0", | ||
"@typescript-eslint/parser": "^7.18.0", | ||
"eslint": "^8.57.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"eslint-plugin-prettier": "^5.1.3", | ||
"eslint-plugin-simple-import-sort": "^12.1.0", | ||
"sanity": "^3.47.1", | ||
"typescript": "5.4.5", | ||
"vitest": "^1.6.0", | ||
"eslint-plugin-prettier": "^5.2.1", | ||
"eslint-plugin-simple-import-sort": "^12.1.1", | ||
"sanity": "^3.57.2", | ||
"typescript": "5.6.2", | ||
"vitest": "^2.0.5", | ||
"@repo/channels": "0.4.0", | ||
"@repo/package.config": "0.0.0" | ||
}, | ||
"peerDependencies": { | ||
"@sanity/client": "^6.21.1" | ||
"@sanity/client": "^6.21.3" | ||
}, | ||
@@ -161,6 +161,6 @@ "engines": { | ||
"build": "pkg build --strict --check --clean", | ||
"dev": "pkg build --strict", | ||
"lint": "eslint .", | ||
"test": "vitest --pass-with-no-tests --typecheck", | ||
"watch": "pkg watch --strict" | ||
"test": "vitest --pass-with-no-tests --typecheck" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 2 instances in 1 package
136770
1381
1