kempo 4.6.0 → 4.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/components/tableControls/ExtensionDetails.js +1 -1
- package/dist/admin/components/tableControls/ExtensionDetails.js.map +1 -1
- package/dist/admin/extensions/browse/index.page.html +4 -1
- package/dist/admin/extensions/index.page.html +1 -0
- package/dist/kempo/api/extensions/POST.js +1 -1
- package/dist/kempo/api/extensions/POST.js.map +1 -1
- package/dist/kempo/api/extensions/known/GET.js +1 -1
- package/dist/kempo/api/extensions/known/GET.js.map +1 -1
- package/dist/kempo/api/extensions/rating/PUT.js +1 -1
- package/dist/kempo/api/extensions/rating/PUT.js.map +1 -1
- package/package.json +1 -1
- package/server/utils/extensions/{getMarketplaceClient.js → getSiteMarketplaceClient.js} +2 -2
- package/server/utils/extensions/installFromCatalog.js +1 -1
- package/server/utils/extensions/installPackage.js +1 -1
- package/server/utils/extensions/{catalogClient.js → marketplaceClient.js} +6 -3
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../AdminTableControl.js";import{html as n}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class t extends e{connectedCallback(){super.connectedCallback(),this.hasAttribute("title")||(this.title="
|
|
1
|
+
import e from"../AdminTableControl.js";import{html as n}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class t extends e{connectedCallback(){super.connectedCallback(),this.hasAttribute("title")||(this.title="View in Store")}handleAction(){this.record&&(window.location.href=`/admin/extensions/details/?name=${encodeURIComponent(this.record.name)}`)}render(){return n`<k-icon name="storefront"></k-icon>`}}customElements.define("admin-extension-details",t);
|
|
2
2
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\tableControls\ExtensionDetails.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\admin\\components\\tableControls\\ExtensionDetails.js","names":["AdminTableControl","html","ExtensionDetails","connectedCallback","super","this","hasAttribute","title","handleAction","record","window","location","href","encodeURIComponent","name","render","customElements","define"],"sources":["0"],"sourcesContent":["import AdminTableControl from '../AdminTableControl.js';\nimport { html } from '/kempo-ui/lit-all.min.js';\nimport '/kempo-ui/components/Icon.js';\n\n/*\n Opens the
|
|
1
|
+
{"version":3,"file":"src\\admin\\components\\tableControls\\ExtensionDetails.js","names":["AdminTableControl","html","ExtensionDetails","connectedCallback","super","this","hasAttribute","title","handleAction","record","window","location","href","encodeURIComponent","name","render","customElements","define"],"sources":["0"],"sourcesContent":["import AdminTableControl from '../AdminTableControl.js';\nimport { html } from '/kempo-ui/lit-all.min.js';\nimport '/kempo-ui/components/Icon.js';\n\n/*\n Opens the marketplace page for a row's extension: its README, what it requires and adds, its rating (which\n can be changed from there once it is installed). The page shows whatever the marketplace knows; for an\n extension it does not list it says so.\n*/\nexport default class ExtensionDetails extends AdminTableControl {\n connectedCallback(){\n super.connectedCallback();\n if(!this.hasAttribute('title')) this.title = 'View in Store';\n }\n\n handleAction(){\n if(!this.record) return;\n window.location.href = `/admin/extensions/details/?name=${encodeURIComponent(this.record.name)}`;\n }\n\n render(){ return html`<k-icon name=\"storefront\"></k-icon>`; }\n}\n\ncustomElements.define('admin-extension-details', ExtensionDetails);\n"],"mappings":"OAAOA,MAAuB,yCACrBC,MAAY,iCACd,8CAOQ,MAAMC,UAAyBF,EAC5C,iBAAAG,GACEC,MAAMD,oBACFE,KAAKC,aAAa,WAAUD,KAAKE,MAAQ,gBAC/C,CAEA,YAAAC,GACMH,KAAKI,SACTC,OAAOC,SAASC,KAAO,mCAAmCC,mBAAmBR,KAAKI,OAAOK,QAC3F,CAEA,MAAAC,GAAU,OAAOd,CAAI,qCAAuC,EAG9De,eAAeC,OAAO,0BAA2Bf","ignoreList":[]}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
</a>
|
|
16
16
|
</div>
|
|
17
17
|
<h1>Browse Extensions</h1>
|
|
18
|
-
<p class="tc-muted">Extensions from the Kempo marketplace. Pick one to see what it does and what it needs before installing it.</p>
|
|
18
|
+
<p class="tc-muted">Extensions from the Kempo marketplace that are not installed here yet. Pick one to see what it does and what it needs before installing it. Installed ones are on the <a href="/admin/extensions">Extensions</a> page, with a store button to see their page.</p>
|
|
19
19
|
|
|
20
20
|
<div class="row mb">
|
|
21
21
|
<div class="col mr">
|
|
@@ -95,6 +95,9 @@
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
cards.replaceChildren(...data.items.map(card));
|
|
98
|
+
empty.textContent = search.value.trim()
|
|
99
|
+
? 'No extensions match that search.'
|
|
100
|
+
: 'Everything in the marketplace is already installed on this site.';
|
|
98
101
|
empty.hidden = data.total > 0;
|
|
99
102
|
pagination.totalItems = data.total;
|
|
100
103
|
pagination.page = page;
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
<h2>Installed Extensions</h2>
|
|
25
25
|
<k-table id="installedTable" enable-pages page-size="25" placeholder="No extensions are currently installed.">
|
|
26
|
+
<admin-extension-details slot="after"></admin-extension-details>
|
|
26
27
|
<admin-toggle-extension slot="after"></admin-toggle-extension>
|
|
27
28
|
<admin-uninstall-extension slot="after"></admin-uninstall-extension>
|
|
28
29
|
<div class="d-f full" style="align-items: center;">
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../../../../server/utils/permissions/currentUserHasPermission.js";export default async(s,t)=>{const i=s.cookies.session_token,[n,r]=await e(i,"system:extensions:install");if(n)return t.status(n.code).json({error:n.msg});if(!r)return t.status(403).json({error:"Insufficient permissions"});const{name:a,withDependencies:o}=s.body||{},{default:l}=await(import("../../../../server/utils/extensions/
|
|
1
|
+
import e from"../../../../server/utils/permissions/currentUserHasPermission.js";export default async(s,t)=>{const i=s.cookies.session_token,[n,r]=await e(i,"system:extensions:install");if(n)return t.status(n.code).json({error:n.msg});if(!r)return t.status(403).json({error:"Insufficient permissions"});const{name:a,withDependencies:o}=s.body||{},{default:l}=await(import("../../../../server/utils/extensions/getSiteMarketplaceClient.js")),{default:u}=await(import("../../../../server/utils/extensions/getSiteInstallId.js")),{default:d}=await(import("../../../../server/utils/extensions/installFromCatalog.js")),[,m]=await u(),[c,f]=await d({name:a,withDependencies:!0===o,client:await l(),installId:m});if(c)return t.status(c.code).json({error:c.msg,needs:c.needs,installed:c.installed});t.json(f)};
|
|
2
2
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\kempo\api\extensions\POST.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\kempo\\api\\extensions\\POST.js","names":["currentUserHasPermission","async","request","response","token","cookies","session_token","permError","hasPermission","status","code","json","error","msg","name","withDependencies","body","default","
|
|
1
|
+
{"version":3,"file":"src\\kempo\\api\\extensions\\POST.js","names":["currentUserHasPermission","async","request","response","token","cookies","session_token","permError","hasPermission","status","code","json","error","msg","name","withDependencies","body","default","getSiteMarketplaceClient","getSiteInstallId","installFromCatalog","installId","data","client","needs","installed"],"sources":["0"],"sourcesContent":["import currentUserHasPermission from '../../../../server/utils/permissions/currentUserHasPermission.js';\n\n/*\n POST /kempo/api/extensions { name, withDependencies? }\n\n Installs an extension. One that is not in node_modules yet is downloaded first, but only if the\n marketplace lists it: this route never runs `npm install` for a name the caller made up. With\n `withDependencies`, the extensions it needs are installed first, in order; the admin shows that list\n for approval before sending it.\n*/\nexport default async (request, response) => {\n const token = request.cookies.session_token;\n const [permError, hasPermission] = await currentUserHasPermission(token, 'system:extensions:install');\n\n if(permError){\n return response.status(permError.code).json({ error: permError.msg });\n }\n\n if(!hasPermission){\n return response.status(403).json({ error: 'Insufficient permissions' });\n }\n\n const { name, withDependencies } = request.body || {};\n\n const { default: getSiteMarketplaceClient } = await import('../../../../server/utils/extensions/getSiteMarketplaceClient.js');\n const { default: getSiteInstallId } = await import('../../../../server/utils/extensions/getSiteInstallId.js');\n const { default: installFromCatalog } = await import('../../../../server/utils/extensions/installFromCatalog.js');\n\n const [, installId] = await getSiteInstallId();\n const [error, data] = await installFromCatalog({\n name,\n withDependencies: withDependencies === true,\n client: await getSiteMarketplaceClient(),\n installId,\n });\n\n if(error){\n return response.status(error.code).json({ error: error.msg, needs: error.needs, installed: error.installed });\n }\n\n response.json(data);\n};\n"],"mappings":"OAAOA,MAA8B,kFAUtBC,MAAOC,EAASC,KAC7B,MAAMC,EAAQF,EAAQG,QAAQC,eACvBC,EAAWC,SAAuBR,EAAyBI,EAAO,6BAEzE,GAAGG,EACD,OAAOJ,EAASM,OAAOF,EAAUG,MAAMC,KAAK,CAAEC,MAAOL,EAAUM,MAGjE,IAAIL,EACF,OAAOL,EAASM,OAAO,KAAKE,KAAK,CAAEC,MAAO,6BAG5C,MAAME,KAAEA,EAAIC,iBAAEA,GAAqBb,EAAQc,MAAQ,CAAC,GAE5CC,QAASC,gBAA0C,qEACnDD,QAASE,gBAAkC,6DAC3CF,QAASG,gBAAoC,+DAE9C,CAAEC,SAAmBF,KACrBP,EAAOU,SAAcF,EAAmB,CAC7CN,OACAC,kBAAuC,IAArBA,EAClBQ,aAAcL,IACdG,cAGF,GAAGT,EACD,OAAOT,EAASM,OAAOG,EAAMF,MAAMC,KAAK,CAAEC,MAAOA,EAAMC,IAAKW,MAAOZ,EAAMY,MAAOC,UAAWb,EAAMa,YAGnGtB,EAASQ,KAAKW","ignoreList":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import e from"../../../../../server/utils/permissions/currentUserHasPermission.js";import s from"../../../../../server/utils/extensions/getSiteMarketplaceClient.js";import t from"../../../../../server/utils/extensions/getSiteInstallId.js";import r from"../../../../../server/utils/extensions/getExtension.js";import n from"../../../../../server/db/index.js";import{extension as i}from"../../../../../server/db/schema.js";export default async(o,a)=>{const l=o.cookies.session_token,[m,u]=await e(l,"system:extensions:read");if(m)return a.status(m.code).json({error:m.msg});if(!u)return a.status(403).json({error:"Insufficient permissions"});const c=await s(),{name:f,search:d,sort:j,limit:p,offset:g}=o.query;if(f){const[e,s]=await c.details(f);if(e)return a.status(e.code).json({error:e.msg});const[,n]=await r({name:f});let i=null;if(n){const[,e]=await t(),[,s]=e?await c.siteRating({installId:e,extension:f}):[null,null];i=s?.rating??null}return a.json({item:s,local:n?{installed:!0,version:n.version,enabled:n.enabled}:{installed:!1},myRating:i})}let x=[];"true"!==o.query.includeInstalled&&(x=(await n.select({name:i.name}).from(i)).map(e=>e.name));const[v,w]=await c.list({search:d,sort:j,limit:p,offset:g,exclude:x});if(v)return a.status(v.code).json({error:v.msg});a.json(w)};
|
|
2
2
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\kempo\api\extensions\known\GET.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\kempo\\api\\extensions\\known\\GET.js","names":["currentUserHasPermission","
|
|
1
|
+
{"version":3,"file":"src\\kempo\\api\\extensions\\known\\GET.js","names":["currentUserHasPermission","getSiteMarketplaceClient","getSiteInstallId","getExtension","db","extension","async","request","response","token","cookies","session_token","permError","hasPermission","status","code","json","error","msg","client","name","search","sort","limit","offset","query","item","details","local","mine","installId","given","siteRating","rating","installed","version","enabled","myRating","exclude","includeInstalled","select","from","map","row","page","list"],"sources":["0"],"sourcesContent":["import currentUserHasPermission from '../../../../../server/utils/permissions/currentUserHasPermission.js';\nimport getSiteMarketplaceClient from '../../../../../server/utils/extensions/getSiteMarketplaceClient.js';\nimport getSiteInstallId from '../../../../../server/utils/extensions/getSiteInstallId.js';\nimport getExtension from '../../../../../server/utils/extensions/getExtension.js';\nimport db from '../../../../../server/db/index.js';\nimport { extension } from '../../../../../server/db/schema.js';\n\n/*\n The extension marketplace, through this site's server (the browser never calls it directly).\n\n GET /kempo/api/extensions/known?search=&sort=&limit=&offset= a page of cards, without what is\n installed here (includeInstalled=true\n lists everything)\n GET /kempo/api/extensions/known?name=<name> one extension in full, plus whether\n it is installed here and this site's\n own rating of it\n*/\nexport default async (request, response) => {\n const token = request.cookies.session_token;\n const [permError, hasPermission] = await currentUserHasPermission(token, 'system:extensions:read');\n\n if(permError){\n return response.status(permError.code).json({ error: permError.msg });\n }\n\n if(!hasPermission){\n return response.status(403).json({ error: 'Insufficient permissions' });\n }\n\n const client = await getSiteMarketplaceClient();\n const { name, search, sort, limit, offset } = request.query;\n\n if(name){\n const [error, item] = await client.details(name);\n if(error){\n return response.status(error.code).json({ error: error.msg });\n }\n\n const [, local] = await getExtension({ name });\n let mine = null;\n if(local){\n const [, installId] = await getSiteInstallId();\n const [, given] = installId ? await client.siteRating({ installId, extension: name }) : [null, null];\n mine = given?.rating ?? null;\n }\n\n return response.json({\n item,\n local: local ? { installed: true, version: local.version, enabled: local.enabled } : { installed: false },\n myRating: mine,\n });\n }\n\n /*\n What is already installed is not offered again: the Browse page is for finding something to add,\n and an installed extension's own page is reached from the Installed table. `includeInstalled=true`\n lists everything.\n */\n let exclude = [];\n if(request.query.includeInstalled !== 'true'){\n exclude = (await db.select({ name: extension.name }).from(extension)).map(row => row.name);\n }\n\n const [error, page] = await client.list({ search, sort, limit, offset, exclude });\n if(error){\n return response.status(error.code).json({ error: error.msg });\n }\n\n response.json(page);\n};\n"],"mappings":"OAAOA,MAA8B,6EAC9BC,MAA8B,4EAC9BC,MAAsB,oEACtBC,MAAkB,gEAClBC,MAAQ,wDACNC,MAAiB,oDAYXC,MAAOC,EAASC,KAC7B,MAAMC,EAAQF,EAAQG,QAAQC,eACvBC,EAAWC,SAAuBb,EAAyBS,EAAO,0BAEzE,GAAGG,EACD,OAAOJ,EAASM,OAAOF,EAAUG,MAAMC,KAAK,CAAEC,MAAOL,EAAUM,MAGjE,IAAIL,EACF,OAAOL,EAASM,OAAO,KAAKE,KAAK,CAAEC,MAAO,6BAG5C,MAAME,QAAelB,KACfmB,KAAEA,EAAIC,OAAEA,EAAMC,KAAEA,EAAIC,MAAEA,EAAKC,OAAEA,GAAWjB,EAAQkB,MAEtD,GAAGL,EAAK,CACN,MAAOH,EAAOS,SAAcP,EAAOQ,QAAQP,GAC3C,GAAGH,EACD,OAAOT,EAASM,OAAOG,EAAMF,MAAMC,KAAK,CAAEC,MAAOA,EAAMC,MAGzD,MAAO,CAAEU,SAAezB,EAAa,CAAEiB,SACvC,IAAIS,EAAO,KACX,GAAGD,EAAM,CACP,MAAO,CAAEE,SAAmB5B,KACrB,CAAE6B,GAASD,QAAkBX,EAAOa,WAAW,CAAEF,YAAWzB,UAAWe,IAAU,CAAC,KAAM,MAC/FS,EAAOE,GAAOE,QAAU,IAC1B,CAEA,OAAOzB,EAASQ,KAAK,CACnBU,OACAE,MAAOA,EAAQ,CAAEM,WAAW,EAAMC,QAASP,EAAMO,QAASC,QAASR,EAAMQ,SAAY,CAAEF,WAAW,GAClGG,SAAUR,GAEd,CAOA,IAAIS,EAAU,GACwB,SAAnC/B,EAAQkB,MAAMc,mBACfD,SAAiBlC,EAAGoC,OAAO,CAAEpB,KAAMf,EAAUe,OAAQqB,KAAKpC,IAAYqC,IAAIC,GAAOA,EAAIvB,OAGvF,MAAOH,EAAO2B,SAAczB,EAAO0B,KAAK,CAAExB,SAAQC,OAAMC,QAAOC,SAAQc,YACvE,GAAGrB,EACD,OAAOT,EAASM,OAAOG,EAAMF,MAAMC,KAAK,CAAEC,MAAOA,EAAMC,MAGzDV,EAASQ,KAAK4B","ignoreList":[]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import s from"../../../../../server/utils/permissions/currentUserHasPermission.js";import e from"../../../../../server/utils/extensions/
|
|
1
|
+
import s from"../../../../../server/utils/permissions/currentUserHasPermission.js";import e from"../../../../../server/utils/extensions/getSiteMarketplaceClient.js";import t from"../../../../../server/utils/extensions/getSiteInstallId.js";import r from"../../../../../server/utils/extensions/getExtension.js";export default async(n,o)=>{const i=n.cookies.session_token,[a,u]=await s(i,"system:extensions:install");if(a)return o.status(a.code).json({error:a.msg});if(!u)return o.status(403).json({error:"Insufficient permissions"});const{name:m,rating:l}=n.body||{};if(!Number.isInteger(l)||l<1||l>5)return o.status(400).json({error:"rating must be a whole number from 1 to 5"});const[c]=await r({name:m});if(c)return o.status(404===c.code?409:c.code).json({error:404===c.code?"Only an extension installed on this site can be rated":c.msg});const[f,d]=await t();if(f)return o.status(f.code).json({error:f.msg});const j=await e();await j.report({installId:d,extension:m});const[g,p]=await j.rate({installId:d,extension:m,value:l});if(g)return o.status(g.code).json({error:g.msg});o.json(p)};
|
|
2
2
|
//# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\kempo\api\extensions\rating\PUT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\kempo\\api\\extensions\\rating\\PUT.js","names":["currentUserHasPermission","
|
|
1
|
+
{"version":3,"file":"src\\kempo\\api\\extensions\\rating\\PUT.js","names":["currentUserHasPermission","getSiteMarketplaceClient","getSiteInstallId","getExtension","async","request","response","token","cookies","session_token","permError","hasPermission","status","code","json","error","msg","name","rating","body","Number","isInteger","localError","idError","installId","client","report","extension","data","rate","value"],"sources":["0"],"sourcesContent":["import currentUserHasPermission from '../../../../../server/utils/permissions/currentUserHasPermission.js';\nimport getSiteMarketplaceClient from '../../../../../server/utils/extensions/getSiteMarketplaceClient.js';\nimport getSiteInstallId from '../../../../../server/utils/extensions/getSiteInstallId.js';\nimport getExtension from '../../../../../server/utils/extensions/getExtension.js';\n\n/*\n PUT /kempo/api/extensions/rating { name, rating: 1-5 }\n\n This site's rating of an extension it has installed. One per extension; sending it again changes it.\n The marketplace only accepts it once the install is a minute old, and says so if it is not.\n*/\nexport default async (request, response) => {\n const token = request.cookies.session_token;\n const [permError, hasPermission] = await currentUserHasPermission(token, 'system:extensions:install');\n\n if(permError){\n return response.status(permError.code).json({ error: permError.msg });\n }\n\n if(!hasPermission){\n return response.status(403).json({ error: 'Insufficient permissions' });\n }\n\n const { name, rating } = request.body || {};\n\n if(!Number.isInteger(rating) || rating < 1 || rating > 5){\n return response.status(400).json({ error: 'rating must be a whole number from 1 to 5' });\n }\n\n const [localError] = await getExtension({ name });\n if(localError){\n return response.status(localError.code === 404 ? 409 : localError.code).json({ error: localError.code === 404 ? 'Only an extension installed on this site can be rated' : localError.msg });\n }\n\n const [idError, installId] = await getSiteInstallId();\n if(idError){\n return response.status(idError.code).json({ error: idError.msg });\n }\n\n const client = await getSiteMarketplaceClient();\n\n /*\n A site that installed before the marketplace existed was never counted. Reporting is idempotent, so\n do it now: otherwise the marketplace would refuse the rating as \"not installed\".\n */\n await client.report({ installId, extension: name });\n\n const [error, data] = await client.rate({ installId, extension: name, value: rating });\n if(error){\n return response.status(error.code).json({ error: error.msg });\n }\n\n response.json(data);\n};\n"],"mappings":"OAAOA,MAA8B,6EAC9BC,MAA8B,4EAC9BC,MAAsB,oEACtBC,MAAkB,wEAQVC,MAAOC,EAASC,KAC7B,MAAMC,EAAQF,EAAQG,QAAQC,eACvBC,EAAWC,SAAuBX,EAAyBO,EAAO,6BAEzE,GAAGG,EACD,OAAOJ,EAASM,OAAOF,EAAUG,MAAMC,KAAK,CAAEC,MAAOL,EAAUM,MAGjE,IAAIL,EACF,OAAOL,EAASM,OAAO,KAAKE,KAAK,CAAEC,MAAO,6BAG5C,MAAME,KAAEA,EAAIC,OAAEA,GAAWb,EAAQc,MAAQ,CAAC,EAE1C,IAAIC,OAAOC,UAAUH,IAAWA,EAAS,GAAKA,EAAS,EACrD,OAAOZ,EAASM,OAAO,KAAKE,KAAK,CAAEC,MAAO,8CAG5C,MAAOO,SAAoBnB,EAAa,CAAEc,SAC1C,GAAGK,EACD,OAAOhB,EAASM,OAA2B,MAApBU,EAAWT,KAAe,IAAMS,EAAWT,MAAMC,KAAK,CAAEC,MAA2B,MAApBO,EAAWT,KAAe,wDAA0DS,EAAWN,MAGvL,MAAOO,EAASC,SAAmBtB,IACnC,GAAGqB,EACD,OAAOjB,EAASM,OAAOW,EAAQV,MAAMC,KAAK,CAAEC,MAAOQ,EAAQP,MAG7D,MAAMS,QAAexB,UAMfwB,EAAOC,OAAO,CAAEF,YAAWG,UAAWV,IAE5C,MAAOF,EAAOa,SAAcH,EAAOI,KAAK,CAAEL,YAAWG,UAAWV,EAAMa,MAAOZ,IAC7E,GAAGH,EACD,OAAOT,EAASM,OAAOG,EAAMF,MAAMC,KAAK,CAAEC,MAAOA,EAAMC,MAGzDV,EAASQ,KAAKc","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import getSetting from '../settings/getSetting.js';
|
|
2
|
-
import { createCatalogClient, DEFAULT_CATALOG_URL } from './
|
|
2
|
+
import { createCatalogClient, DEFAULT_CATALOG_URL } from './marketplaceClient.js';
|
|
3
3
|
|
|
4
4
|
const clients = new Map();
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
This site's marketplace client. The address is the `system:extensions_catalog_url` setting: it
|
|
8
|
-
defaults to https://
|
|
8
|
+
defaults to https://kempo.dev/api/v1, and an empty value turns the marketplace off. It is
|
|
9
9
|
deliberately not one of the seeded default settings, because seeding rewrites those on every run and
|
|
10
10
|
would put a site's chosen address back.
|
|
11
11
|
|
|
@@ -6,7 +6,7 @@ import { eq } from 'drizzle-orm';
|
|
|
6
6
|
import installExtension from './installExtension.js';
|
|
7
7
|
import installPackage from './installPackage.js';
|
|
8
8
|
import enableExtension from './enableExtension.js';
|
|
9
|
-
import { NAME_PATTERN } from './
|
|
9
|
+
import { NAME_PATTERN } from './marketplaceClient.js';
|
|
10
10
|
|
|
11
11
|
const isInstalled = async name => {
|
|
12
12
|
const [row] = await db.select({ name: extension.name }).from(extension).where(eq(extension.name, name)).limit(1);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
The extension marketplace (https://
|
|
2
|
+
The extension marketplace (https://kempo.dev), as this site's SERVER sees it. The browser
|
|
3
3
|
only ever talks to this site's own API, which calls this.
|
|
4
4
|
|
|
5
5
|
list a page of cards: search, sort, limit, offset
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
Every function returns [error, data] and never throws.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
export const DEFAULT_CATALOG_URL = 'https://
|
|
18
|
+
export const DEFAULT_CATALOG_URL = 'https://kempo.dev/api/v1';
|
|
19
19
|
|
|
20
20
|
export const NAME_PATTERN = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
|
|
21
21
|
|
|
@@ -181,12 +181,15 @@ export const createCatalogClient = ({ baseUrl = DEFAULT_CATALOG_URL, fetchImpl =
|
|
|
181
181
|
};
|
|
182
182
|
|
|
183
183
|
return {
|
|
184
|
-
list
|
|
184
|
+
/* `exclude` is a list of extension names to leave out, which is how a site hides what it has installed. */
|
|
185
|
+
list: ({ search, sort, limit, offset, exclude } = {}) => {
|
|
185
186
|
const query = new URLSearchParams();
|
|
186
187
|
if(search) query.set('search', String(search).slice(0, 100));
|
|
187
188
|
if(sort) query.set('sort', String(sort));
|
|
188
189
|
if(limit) query.set('limit', String(limit));
|
|
189
190
|
if(offset) query.set('offset', String(offset));
|
|
191
|
+
const excluded = (Array.isArray(exclude) ? exclude : []).filter(name => NAME_PATTERN.test(name || '')).slice(0, 500);
|
|
192
|
+
if(excluded.length) query.set('exclude', excluded.join(','));
|
|
190
193
|
return read(`/extensions${query.size ? `?${query}` : ''}`, normalizePage);
|
|
191
194
|
},
|
|
192
195
|
|