Compare commits

...

23 Commits

Author SHA1 Message Date
6798e2f71b fix(browser-extension): possible undefined 2024-10-13 11:51:04 +02:00
e26316e4b5 fix(browser-extension): report cancel button clickable area 2024-10-13 11:51:04 +02:00
beb6443579 feat(web): add new issue tracking section 2024-10-13 11:51:04 +02:00
5f778e04ba fix(browser-extension): media queries for mobile version 2024-10-13 11:51:04 +02:00
d44d627fd5 feat(web): update options and popup images 2024-10-13 11:51:04 +02:00
4f37777aea fix(browser-extension): how options and popup look on mobile 2024-10-13 11:51:04 +02:00
303e29f307 chore(browser-extension): bump extension version 2024-10-13 11:51:04 +02:00
d298dac538 feat(browser-extension): minor improvement to new error extra text english translation 2024-10-13 11:51:04 +02:00
855ce1ad65 feat(browser-extension): enable report only on supported pages 2024-10-13 11:51:04 +02:00
6d6f9ab9b7 feat(browser-extension): handle new error cases when reporting 2024-10-13 11:51:04 +02:00
422b8070f7 feat(browser-extension): bump api version to use 2024-10-13 11:51:04 +02:00
d1cacdf027 refactor(browser-extension): move report dialog to popup 2024-10-13 11:51:04 +02:00
1d63706fe5 fix(browser-extension): popup auto height issue 2024-10-13 11:51:04 +02:00
d937f0e838 refactor: drop old dialog stuff 2024-10-13 11:51:04 +02:00
84f9573956 feat(api): add issues and version endpoints 2024-10-13 11:51:04 +02:00
39e7090db0 feat(browser-extension): switch to warn mode after reporting an issue 2024-10-13 11:49:51 +02:00
6e41d1a740 fix(browser-extension): off/on performance 2024-10-13 11:49:51 +02:00
cb34b33b6d feat(browser-extension): add issue banner translations 2024-10-13 11:49:51 +02:00
d9c68bc903 feat(browser-extension): add request batching, issue details fetching and minor refactors to scripts 2024-10-13 11:49:51 +02:00
f2980302e4 feat(browser-extension): add issue banner to popup giving user some information about what's wrong and where to find the issue easily 2024-10-13 11:49:51 +02:00
9c3bd773b8 refactor(browser-extension): assets naming 2024-10-13 11:49:51 +02:00
ef534c7ac3 chore(browser-extension): upgrade manifest version 2024-10-13 11:49:45 +02:00
069bb29242 feat: migrate to git.wanhose.dev 2024-10-13 11:11:31 +02:00
57 changed files with 1835 additions and 1700 deletions

21
.gitea/ISSUE_TEMPLATE.md Normal file
View File

@ -0,0 +1,21 @@
## Issue information
#### 🖥️ Browser
...
#### 📱 Device
...
#### 📝 Reason
...
#### 🔗 URL
...
#### 🏷️ Version
...

View File

@ -0,0 +1,10 @@
## Description
...
## Browsers
- [ ] Google Chrome (specify version if checked)
- [ ] Microsoft Edge (specify version if checked)
- [ ] Mozilla Firefox (specify version if checked)
- [ ] Opera (specify version if checked)

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
custom: ['https://paypal.me/wanhose']

19
README.md Normal file
View File

@ -0,0 +1,19 @@
> AN IMPORTANT UPDATE
> <br><br>
> On the morning of October 11, 2024, GitHub unexpectedly hid our repository without any prior notification. This sudden action immediately disrupted all of our API services, as they relied on files from the repository that were no longer accessible. Our team reached out to GitHub support to understand the situation, but we have not yet received any response. Given the critical impact on our services and the lack of communication from GitHub, we decided to migrate the entire repository to an alternative platform to ensure continuity and reliability.
> <br><br>
> We initially migrated the repository, releases, and open issues (excluding discussions) to GitLab. However, during the migration of issues, GitLab's own spam detection mechanism mistakenly identified its bot activity as spam, leading to our issues being hidden. Despite reaching out to GitLab support, we have not yet received a resolution for this incident. Faced with these ongoing platform limitations and communication delays, we have opted to move forward with self-hosting our own Git system using Gitea to ensure full control over our repository and services.
> <br><br>
> We will no longer support platforms that overlook the contributions of our users and the significant work invested over the last five years. Once our GitHub account is reinstated, we will set up a redirect to guide users to our new, self-hosted repository.
> <br><br>
> Thank you to our community for your patience. Your contributions remain vital to this project, and we are committed to ensuring its stability and growth in a more secure environment.
# Cookie Dialog Monster
Cookie Dialog Monster is a browser extension that hides cookie consent dialogs without changing user preferences. By default, we do NOT accept cookies (except in [a few cases](https://git.wanhose.dev/wanhose/cookie-dialog-monster/src/branch/main/database.json#L248) where the pages do not function without accepting them). You can report broken sites with a single click, which will create an issue in this repository to be fixed promptly.
## Repositories
- [API](/wanhose/cookie-dialog-monster/src/branch/main/packages/api)
- [Browser extension](/wanhose/cookie-dialog-monster/src/branch/main/packages/browser-extension)
- [Web](/wanhose/cookie-dialog-monster/src/branch/main/packages/web)

View File

@ -1,9 +0,0 @@
# Cookie Monster Dialog
Cookie Monster Dialog is a browser extension that hides cookie consent dialogs without changing user preferences. By default, we do NOT accept cookies (except in [a few cases](https://github.com/wanhose/cookie-dialog-monster/blob/main/database.json#L248) where the pages do not function without accepting them). You can report broken sites with a single click, which will create an issue in this repository to be fixed promptly.
## Repositories
- [API](/packages/api/)
- [Browser extension](/packages/browser-extension/)
- [Web](/packages/web/)

View File

@ -1,10 +0,0 @@
## Description
Give a short description about this pull request.
## Browsers
- [ ] Google Chrome (specify version if checked).
- [ ] Microsoft Edge (specify version if checked).
- [ ] Mozilla Firefox (specify version if checked).
- [ ] Opera (specify version if checked).

View File

@ -1 +1,2 @@
GITHUB_TOKEN=? GITEA_RAW=?
GITEA_TOKEN=?

View File

@ -1,4 +1,4 @@
# Cookie Monster Dialog API # Cookie Dialog Monster API
## Installation ## Installation

View File

@ -12,7 +12,6 @@
"@fastify/rate-limit": "^9.1.0", "@fastify/rate-limit": "^9.1.0",
"fastify": "^4.26.2", "fastify": "^4.26.2",
"node-fetch": "^2.7.0", "node-fetch": "^2.7.0",
"octokit": "^3.2.1",
"ua-parser-js": "^1.0.37", "ua-parser-js": "^1.0.37",
"yup": "^1.4.0" "yup": "^1.4.0"
}, },

View File

@ -12,7 +12,6 @@ import v4ReportRoutes from 'routes/v4/report';
import v5DataRoutes from 'routes/v5/data'; import v5DataRoutes from 'routes/v5/data';
import v5IssuesRoutes from 'routes/v5/issues'; import v5IssuesRoutes from 'routes/v5/issues';
import v5ReportRoutes from 'routes/v5/report'; import v5ReportRoutes from 'routes/v5/report';
import v5VersionRoutes from 'routes/v5/version';
import environment from 'services/environment'; import environment from 'services/environment';
const server = fastify({ logger: true }); const server = fastify({ logger: true });
@ -27,8 +26,6 @@ server.register(cors, {
server.register(rateLimit, { server.register(rateLimit, {
global: false, global: false,
max: 1,
timeWindow: 30000,
}); });
server.register(v1EntriesRoutes, { prefix: '/rest/v1' }); server.register(v1EntriesRoutes, { prefix: '/rest/v1' });
@ -42,7 +39,6 @@ server.register(v4ReportRoutes, { prefix: '/rest/v4' });
server.register(v5DataRoutes, { prefix: '/rest/v5' }); server.register(v5DataRoutes, { prefix: '/rest/v5' });
server.register(v5IssuesRoutes, { prefix: '/rest/v5' }); server.register(v5IssuesRoutes, { prefix: '/rest/v5' });
server.register(v5ReportRoutes, { prefix: '/rest/v5' }); server.register(v5ReportRoutes, { prefix: '/rest/v5' });
server.register(v5VersionRoutes, { prefix: '/rest/v5' });
server.listen({ host: '0.0.0.0', port: environment.port }, (error, address) => { server.listen({ host: '0.0.0.0', port: environment.port }, (error, address) => {
if (error) { if (error) {

View File

@ -1,15 +1,24 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import { RATE_LIMIT_1_PER_HOUR } from 'services/rateLimit';
/** /**
* @deprecated This API route is no longer supported. Please use a newer version * @deprecated This API route is no longer supported. Please use a newer version
*/ */
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => { export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
server.get('/entries/', async (_request, reply) => { server.get(
'/entries/',
{
config: {
rateLimit: RATE_LIMIT_1_PER_HOUR,
},
},
async (_request, reply) => {
reply.send({ reply.send({
success: false, success: false,
errors: ['This API route is no longer supported. Please use a newer version'], errors: ['This API route is no longer supported. Please use a newer version'],
}); });
}); }
);
done(); done();
}; };

View File

@ -1,15 +1,24 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import { RATE_LIMIT_1_PER_HOUR } from 'services/rateLimit';
/** /**
* @deprecated This API route is no longer supported. Please use a newer version * @deprecated This API route is no longer supported. Please use a newer version
*/ */
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => { export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
server.post('/report/', {}, async (_request, reply) => { server.post(
'/report/',
{
config: {
rateLimit: RATE_LIMIT_1_PER_HOUR,
},
},
async (_request, reply) => {
reply.send({ reply.send({
success: false, success: false,
errors: ['This API route is no longer supported. Please use a newer version'], errors: ['This API route is no longer supported. Please use a newer version'],
}); });
}); }
);
done(); done();
}; };

View File

@ -2,11 +2,19 @@ import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import { parseNewFix } from 'services/compatibility'; import { parseNewFix } from 'services/compatibility';
import environment from 'services/environment'; import environment from 'services/environment';
import { RATE_LIMIT_10_PER_MIN } from 'services/rateLimit';
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => { export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
server.get('/data/', async (_request, reply) => { server.get(
'/data/',
{
config: {
rateLimit: RATE_LIMIT_10_PER_MIN,
},
},
async (_request, reply) => {
try { try {
const url = `${environment.github.files}/database.json`; const url = `${environment.gitea.raw}/database.json`;
const result = await (await fetch(url)).json(); const result = await (await fetch(url)).json();
reply.send({ reply.send({
@ -20,11 +28,14 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
}, },
success: true, success: true,
}); });
} catch (e) { } catch (error) {
console.error(e); reply.send({
reply.send({ success: false }); errors: [error.message],
} success: false,
}); });
}
}
);
done(); done();
}; };

View File

@ -1,6 +1,7 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import environment from 'services/environment'; import { formatMessage } from 'services/format';
import { octokit } from 'services/octokit'; import { createIssue, createIssueComment, getIssue, updateIssue } from 'services/git';
import { RATE_LIMIT_1_PER_MIN } from 'services/rateLimit';
import { validatorCompiler } from 'services/validation'; import { validatorCompiler } from 'services/validation';
import { UAParser } from 'ua-parser-js'; import { UAParser } from 'ua-parser-js';
import * as yup from 'yup'; import * as yup from 'yup';
@ -22,6 +23,9 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
server.post<{ Body: PostReportBody }>( server.post<{ Body: PostReportBody }>(
'/report/', '/report/',
{ {
config: {
rateLimit: RATE_LIMIT_1_PER_MIN,
},
schema: { schema: {
body: PostReportBodySchema, body: PostReportBodySchema,
}, },
@ -29,45 +33,45 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
}, },
async (request, reply) => { async (request, reply) => {
try { try {
const issues = await octokit.request('GET /repos/{owner}/{repo}/issues', { const { reason, url, userAgent, version } = request.body;
owner: environment.github.owner, const hostname = new URL(url).hostname.split('.').slice(-3).join('.').replace('www.', '');
repo: environment.github.repo, const issue = await getIssue({ title: hostname });
}); const ua = new UAParser(userAgent ?? '').getResult();
const ua = new UAParser(request.body.userAgent ?? '').getResult();
const url = new URL(request.body.url).hostname
.split('.')
.slice(-3)
.join('.')
.replace('www.', '');
if (issues.data.some((issue) => issue.title.includes(url))) { if (issue) {
throw new Error(); if (issue.state === 'closed') {
await updateIssue({
id: issue.id,
labels: ['bug'],
state: 'open',
});
} }
await octokit.request('POST /repos/{owner}/{repo}/issues', { await createIssueComment({
assignees: [environment.github.owner], description: formatMessage({ reason, ua, url, version }),
body: [ id: issue.id,
'## Specifications',
'#### Browser',
`${ua.browser.name ? `${ua.browser.name} ${ua.browser.version || ''}` : '-'}`,
'#### Device',
`${ua.device.type && ua.device.vendor ? `${ua.device.vendor} (${ua.device.type})` : '-'}`,
'#### Reason',
request.body.reason ?? '-',
'#### URL',
request.body.url,
'#### Version',
request.body.version,
].join('\n'),
labels: ['bug'],
owner: environment.github.owner,
repo: environment.github.repo,
title: url,
}); });
reply.send({ success: true }); reply.send({
success: true,
});
return;
}
await createIssue({
description: formatMessage({ reason, ua, url, version }),
labels: ['bug'],
title: hostname,
});
reply.send({
success: true,
});
} catch (error) { } catch (error) {
reply.send({ errors: [error.message], success: false }); reply.send({
errors: [error.message],
success: false,
});
} }
} }
); );

View File

@ -2,11 +2,19 @@ import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import { parseNewFix } from 'services/compatibility'; import { parseNewFix } from 'services/compatibility';
import environment from 'services/environment'; import environment from 'services/environment';
import { RATE_LIMIT_3_PER_MIN } from 'services/rateLimit';
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => { export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
server.get('/data/', async (_request, reply) => { server.get(
'/data/',
{
config: {
rateLimit: RATE_LIMIT_3_PER_MIN,
},
},
async (_request, reply) => {
try { try {
const url = `${environment.github.files}/database.json`; const url = `${environment.gitea.raw}/database.json`;
const result = await (await fetch(url)).json(); const result = await (await fetch(url)).json();
reply.send({ reply.send({
@ -22,7 +30,8 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
success: false, success: false,
}); });
} }
}); }
);
done(); done();
}; };

View File

@ -1,6 +1,7 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import environment from 'services/environment'; import { formatMessage } from 'services/format';
import { octokit } from 'services/octokit'; import { createIssue, createIssueComment, getIssue, updateIssue } from 'services/git';
import { RATE_LIMIT_1_PER_MIN } from 'services/rateLimit';
import { validatorCompiler } from 'services/validation'; import { validatorCompiler } from 'services/validation';
import { UAParser } from 'ua-parser-js'; import { UAParser } from 'ua-parser-js';
import * as yup from 'yup'; import * as yup from 'yup';
@ -22,63 +23,50 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
server.post<{ Body: PostReportBody }>( server.post<{ Body: PostReportBody }>(
'/report/', '/report/',
{ {
config: {
rateLimit: RATE_LIMIT_1_PER_MIN,
},
schema: { schema: {
body: PostReportBodySchema, body: PostReportBodySchema,
}, },
validatorCompiler, validatorCompiler,
}, },
async (request, reply) => { async (request, reply) => {
const { url, userAgent } = request.body;
const ua = new UAParser(userAgent ?? '').getResult();
const hostname = new URL(url).hostname.split('.').slice(-3).join('.').replace('www.', '');
const existingIssues = await octokit.request('GET /search/issues', {
per_page: 50,
q: `in:title+is:issue+repo:${environment.github.owner}/${environment.github.repo}+${hostname}`,
});
const existingIssue = existingIssues.data.items.find(
(issue) =>
hostname === issue.title &&
(issue.state === 'open' ||
(issue.state === 'closed' && issue.labels.some((label) => label.name === 'wontfix')))
);
try { try {
if (existingIssue) { const { reason, url, userAgent, version } = request.body;
if (existingIssue.state === 'closed') { const hostname = new URL(url).hostname.split('.').slice(-3).join('.').replace('www.', '');
await octokit.request('PATCH /repos/{owner}/{repo}/issues/{issue_number}', { const issue = await getIssue({ title: hostname });
issue_number: existingIssue.number, const ua = new UAParser(userAgent ?? '').getResult();
if (issue) {
if (issue.state === 'closed') {
await updateIssue({
id: issue.id,
labels: ['bug'], labels: ['bug'],
owner: environment.github.owner,
repo: environment.github.repo,
state: 'open', state: 'open',
}); });
} }
await octokit.request('POST /repos/{owner}/{repo}/issues/{issue_number}/comments', { await createIssueComment({
body: generateText(request.body, ua), description: formatMessage({ reason, ua, url, version }),
issue_number: existingIssue.number, id: issue.id,
owner: environment.github.owner,
repo: environment.github.repo,
}); });
reply.send({ reply.send({
data: existingIssue.html_url, data: issue.html_url,
success: true, success: true,
}); });
return; return;
} }
const response = await octokit.request('POST /repos/{owner}/{repo}/issues', { const newIssue = await createIssue({
assignees: [environment.github.owner], description: formatMessage({ reason, ua, url, version }),
body: generateText(request.body, ua),
labels: ['bug'], labels: ['bug'],
owner: environment.github.owner,
repo: environment.github.repo,
title: hostname, title: hostname,
}); });
reply.send({ reply.send({
data: response.data.html_url, data: newIssue.html_url,
success: true, success: true,
}); });
} catch (error) { } catch (error) {
@ -92,21 +80,3 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
done(); done();
}; };
function generateText(body: PostReportBody, ua: UAParser.IResult): string {
return [
'## Issue information',
...(ua.browser.name && ua.browser.version
? ['#### 🖥️ Browser', `${ua.browser.name} (${ua.browser.version})`]
: []),
...(ua.device.type && ua.device.vendor
? ['#### 📱 Device', `${ua.device.vendor} (${ua.device.type})`]
: []),
'#### 📝 Reason',
body.reason,
'#### 🔗 URL',
body.url,
'#### 🏷️ Version',
body.version,
].join('\n');
}

View File

@ -1,12 +1,20 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import environment from 'services/environment'; import environment from 'services/environment';
import { RATE_LIMIT_3_PER_MIN } from 'services/rateLimit';
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => { export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
server.get('/data/', async (_request, reply) => { server.get(
'/data/',
{
config: {
rateLimit: RATE_LIMIT_3_PER_MIN,
},
},
async (_request, reply) => {
try { try {
const options = { headers: { 'Cache-Control': 'no-cache' } }; const options = { headers: { 'Cache-Control': 'no-cache' } };
const url = `${environment.github.files}/database.json`; const url = `${environment.gitea.raw}/database.json`;
const { rules, ...result } = await (await fetch(url, options)).json(); const { rules, ...result } = await (await fetch(url, options)).json();
reply.send({ reply.send({
@ -22,7 +30,8 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
success: false, success: false,
}); });
} }
}); }
);
done(); done();
}; };

View File

@ -1,6 +1,6 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import environment from 'services/environment'; import { getIssue } from 'services/git';
import { octokit } from 'services/octokit'; import { RATE_LIMIT_10_PER_MIN } from 'services/rateLimit';
import { validatorCompiler } from 'services/validation'; import { validatorCompiler } from 'services/validation';
import * as yup from 'yup'; import * as yup from 'yup';
@ -14,6 +14,9 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
server.get<{ Params: GetIssuesParams }>( server.get<{ Params: GetIssuesParams }>(
'/issues/:hostname', '/issues/:hostname',
{ {
config: {
rateLimit: RATE_LIMIT_10_PER_MIN,
},
schema: { schema: {
params: GetIssuesParamsSchema, params: GetIssuesParamsSchema,
}, },
@ -22,30 +25,22 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
async (request, reply) => { async (request, reply) => {
try { try {
const { hostname } = request.params; const { hostname } = request.params;
const existingIssues = await octokit.request('GET /search/issues', { const issue = await getIssue({ title: hostname });
per_page: 50,
q: `in:title+is:issue+repo:${environment.github.owner}/${environment.github.repo}+${hostname}`,
});
const existingIssue = existingIssues.data.items.find(
(issue) =>
hostname === issue.title &&
(issue.state === 'open' ||
(issue.state === 'closed' && issue.labels.some((label) => label.name === 'wontfix')))
);
if (existingIssue) { if (
issue &&
((issue.state === 'closed' && issue.labels.some((label) => label.name === 'wontfix')) ||
issue.state === 'open')
) {
reply.send({ reply.send({
data: { data: {
flags: existingIssue.labels.map((label) => label.name), flags: issue.labels.map((label) => label.name),
url: existingIssue.html_url, url: issue.html_url,
}, },
success: true, success: true,
}); });
} else { } else {
reply.send({ throw new Error('Failed to find issue');
data: {},
success: true,
});
} }
} catch (error) { } catch (error) {
reply.send({ reply.send({

View File

@ -1,6 +1,7 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify'; import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import environment from 'services/environment'; import { formatMessage } from 'services/format';
import { octokit } from 'services/octokit'; import { createIssue, getIssue, updateIssue } from 'services/git';
import { RATE_LIMIT_1_PER_MIN } from 'services/rateLimit';
import { validatorCompiler } from 'services/validation'; import { validatorCompiler } from 'services/validation';
import { UAParser } from 'ua-parser-js'; import { UAParser } from 'ua-parser-js';
import * as yup from 'yup'; import * as yup from 'yup';
@ -22,35 +23,34 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
server.post<{ Body: PostReportBody }>( server.post<{ Body: PostReportBody }>(
'/report/', '/report/',
{ {
config: {
rateLimit: RATE_LIMIT_1_PER_MIN,
},
schema: { schema: {
body: PostReportBodySchema, body: PostReportBodySchema,
}, },
validatorCompiler, validatorCompiler,
}, },
async (request, reply) => { async (request, reply) => {
const { reason, url, userAgent, version } = request.body;
const ua = new UAParser(userAgent ?? '').getResult();
const hostname = new URL(url).hostname.split('.').slice(-3).join('.').replace('www.', '');
const existingIssues = await octokit.request('GET /search/issues', {
per_page: 50,
q: `in:title+is:issue+repo:${environment.github.owner}/${environment.github.repo}+${hostname}`,
});
const existingIssue = existingIssues.data.items.find((issue) => hostname === issue.title);
try { try {
if (existingIssue) { const { reason, url, userAgent, version } = request.body;
if (existingIssue.labels.some((label) => label.name === 'wontfix')) { const hostname = new URL(url).hostname.split('.').slice(-3).join('.').replace('www.', '');
const issue = await getIssue({ title: hostname });
const ua = new UAParser(userAgent ?? '').getResult();
if (issue) {
if (issue.labels.some((label) => label.name === 'wontfix')) {
reply.send({ reply.send({
data: existingIssue.html_url, data: issue.html_url,
errors: ['This issue has been marked as "wontfix" and will not be addressed.'], errors: ['This issue has been marked as "wontfix" and will not be addressed.'],
success: false, success: false,
}); });
return; return;
} }
if (existingIssue.state === 'open') { if (issue.state === 'open') {
reply.send({ reply.send({
data: existingIssue.html_url, data: issue.html_url,
errors: [ errors: [
'This issue already exists. Please refer to the existing issue for updates.', 'This issue already exists. Please refer to the existing issue for updates.',
], ],
@ -59,46 +59,27 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
return; return;
} }
await octokit.request('PATCH /repos/{owner}/{repo}/issues/{issue_number}', { await updateIssue({
issue_number: existingIssue.number, id: issue.id,
labels: ['bug'], labels: ['bug'],
owner: environment.github.owner,
repo: environment.github.repo,
state: 'open', state: 'open',
}); });
reply.send({ reply.send({
data: existingIssue.html_url, data: issue.html_url,
success: true, success: true,
}); });
return; return;
} }
const response = await octokit.request('POST /repos/{owner}/{repo}/issues', { const newIssue = await createIssue({
assignees: [environment.github.owner], description: formatMessage({ reason, ua, url, version }),
body: [
'## Issue information',
...(ua.browser.name && ua.browser.version
? ['#### 🖥️ Browser', `${ua.browser.name} (${ua.browser.version})`]
: []),
...(ua.device.type && ua.device.vendor
? ['#### 📱 Device', `${ua.device.vendor} (${ua.device.type})`]
: []),
'#### 📝 Reason',
reason,
'#### 🔗 URL',
url,
'#### 🏷️ Version',
version,
].join('\n'),
labels: ['bug'], labels: ['bug'],
owner: environment.github.owner,
repo: environment.github.repo,
title: hostname, title: hostname,
}); });
reply.send({ reply.send({
data: response.data.html_url, data: newIssue.html_url,
success: true, success: true,
}); });
} catch (error) { } catch (error) {

View File

@ -1,27 +0,0 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch';
import environment from 'services/environment';
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
server.get('/version/', async (_request, reply) => {
try {
const options = { headers: { 'Cache-Control': 'no-cache' } };
const url = `${environment.github.files}/packages/browser-extension/src/manifest.json`;
const { version } = await (await fetch(url, options)).json();
reply.send({
data: {
version,
},
success: true,
});
} catch (error) {
reply.send({
errors: [error.message],
success: false,
});
}
});
done();
};

View File

@ -1,9 +1,7 @@
export default { export default {
github: { gitea: {
files: 'https://raw.githubusercontent.com/wanhose/cookie-dialog-monster/main', raw: process.env.GITEA_RAW ?? '',
owner: 'wanhose', token: process.env.GITEA_TOKEN ?? '',
repo: 'cookie-dialog-monster',
token: process.env.GITHUB_TOKEN ?? '',
}, },
port: (process.env.PORT ? Number(process.env.PORT) : undefined) ?? 8080, port: (process.env.PORT ? Number(process.env.PORT) : undefined) ?? 8080,
}; };

View File

@ -0,0 +1,28 @@
import type { IResult as UAParserResult } from 'ua-parser-js';
export function formatMessage(params: FormatMessageParams): string {
const { reason = '-', ua, url, version } = params;
return [
'## Issue information',
...(ua.browser.name && ua.browser.version
? ['#### 🖥️ Browser', `${ua.browser.name} (${ua.browser.version})`]
: []),
...(ua.device.type && ua.device.vendor
? ['#### 📱 Device', `${ua.device.vendor} (${ua.device.type})`]
: []),
'#### 📝 Reason',
reason,
'#### 🔗 URL',
url,
'#### 🏷️ Version',
version,
].join('\n');
}
export interface FormatMessageParams {
readonly reason?: string;
readonly ua: UAParserResult;
readonly url: string;
readonly version: string;
}

View File

@ -0,0 +1,150 @@
import environment from './environment';
const API_URL = 'https://git.wanhose.dev/api/v1/repos/wanhose/cookie-dialog-monster';
export async function createIssue(params: CreateIssueParams): Promise<Issue> {
const { description, title } = params;
const body: { [key: string]: number[] | string | string[] } = {
assignees: ['wanhose'],
body: description,
labels: [],
title,
};
const headers = new Headers({
Authorization: `token ${environment.gitea.token}`,
'Content-Type': 'application/json',
});
if (params.labels) {
const response = await fetch(`${API_URL}/labels`, { headers });
const labels = (await response.json()) as readonly Label[];
for (const label of labels) {
if (params.labels.includes(label.name)) {
(body.labels as number[]).push(label.id);
}
}
}
const response = await fetch(`${API_URL}/issues`, {
body: JSON.stringify(body),
headers,
method: 'POST',
});
const issue = await response.json();
return issue as unknown as Issue;
}
export async function createIssueComment(params: CreateIssueCommentParams): Promise<Issue | null> {
const { description, id } = params;
const headers = new Headers({
Authorization: `token ${environment.gitea.token}`,
'Content-Type': 'application/json',
});
const response = await fetch(`${API_URL}/issues/${id}/comments`, {
body: JSON.stringify({ body: description }),
headers,
method: 'POST',
});
const issue = await response.json();
return issue as unknown as Issue | null;
}
export async function getIssue(params: GetIssueParams): Promise<Issue | null> {
const { labels, state, title } = params;
const headers = new Headers({
Authorization: `token ${environment.gitea.token}`,
'Content-Type': 'application/json',
});
const search = new URLSearchParams({
q: title,
state: 'all',
type: 'issues',
});
if (labels) {
search.append('labels', `${labels}`);
}
if (state) {
search.append('state', state);
}
const response = await fetch(`${API_URL}/issues?${search}`, { headers });
const issues: readonly Issue[] = (await response.json()) as unknown as readonly Issue[];
return issues.find((issue) => issue.title === title) || null;
}
export async function updateIssue(params: UpdateIssueParams): Promise<Issue | null> {
const { id, labels, state } = params;
const body: { [key: string]: string } = {};
const headers = new Headers({
Authorization: `token ${environment.gitea.token}`,
'Content-Type': 'application/json',
});
if (labels) {
await fetch(`${API_URL}/issues/${id}/labels`, {
headers,
method: 'DELETE',
});
await fetch(`${API_URL}/issues/${id}/labels`, {
body: JSON.stringify({ labels }),
headers,
method: 'POST',
});
}
if (state) {
body['state'] = state;
}
const response = await fetch(`${API_URL}/issues/${id}`, {
body: JSON.stringify(body),
headers,
method: 'PATCH',
});
const issue = await response.json();
return issue as unknown as Issue | null;
}
export interface CreateIssueParams {
readonly description: string;
readonly labels?: readonly string[];
readonly title: string;
}
export interface CreateIssueCommentParams {
readonly description: string;
readonly id: number;
}
export interface GetIssueParams {
readonly labels?: readonly string[];
readonly state?: string;
readonly title: string;
}
export interface Issue {
readonly html_url: string;
readonly id: number;
readonly labels: readonly Label[];
readonly state: string;
readonly title: string;
}
export interface Label {
readonly id: number;
readonly name: string;
}
export interface UpdateIssueParams {
readonly id: number;
readonly labels?: readonly string[];
readonly state?: string;
}

View File

@ -1,4 +0,0 @@
import { Octokit } from 'octokit';
import environment from './environment';
export const octokit = new Octokit({ auth: environment.github.token });

View File

@ -0,0 +1,19 @@
export const RATE_LIMIT_1_PER_HOUR = {
max: 1,
timeWindow: '1 hour',
};
export const RATE_LIMIT_1_PER_MIN = {
max: 1,
timeWindow: '1 minute',
};
export const RATE_LIMIT_10_PER_MIN = {
max: 10,
timeWindow: '1 minute',
};
export const RATE_LIMIT_3_PER_MIN = {
max: 3,
timeWindow: '1 minute',
};

View File

@ -1,4 +1,4 @@
# Cookie Monster Dialog Browser Extension # Cookie Dialog Monster Browser Extension
## Downloads ## Downloads
@ -11,9 +11,9 @@
## Compatibility ## Compatibility
- All browsers based on Chromium 124+ (Blisk, Brave, Colibri, Epic Browser, Iron Browser, Vivaldi and many more) - All browsers based on Chromium 127+ (Blisk, Brave, Colibri, Epic Browser, Iron Browser, Vivaldi and many more)
- Google Chrome 124+ - Google Chrome 127+
- Microsoft Edge 124+ - Microsoft Edge 127+
- Mozilla Firefox 126+ - Mozilla Firefox 126+
- Mozilla Firefox Mobile 126+ - Mozilla Firefox Mobile 126+

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Liste importieren" "message": "Liste importieren"
}, },
"popup_bannerIssueOpen": {
"message": "Ein Problem wurde für diese Seite gemeldet. Die Erweiterung funktioniert möglicherweise vorübergehend nicht wie erwartet. Verfolgen Sie das Problem oder fügen Sie weitere Informationen hinzu."
},
"popup_bannerIssueWontFix": {
"message": "Ein Problem wurde für diese Seite gemeldet, wird jedoch nicht behoben. Bitte beachten Sie, dass die Erweiterung auf dieser Seite möglicherweise nicht wie erwartet funktioniert. Wir empfehlen dringend, die Erweiterung über die Schaltfläche unten zu deaktivieren."
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Zu diesem Projekt beitragen" "message": "Zu diesem Projekt beitragen"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Bewerten Sie diese Erweiterung" "message": "Bewerten Sie diese Erweiterung"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Bitte geben Sie in diesem Bericht keine persönlichen Informationen weiter. Wenn Sie weitere Details hinzufügen möchten, öffnen Sie das GitHub-Problem im nächsten Schritt und fügen Sie einen Kommentar hinzu." "message": "Bitte geben Sie in diesem Bericht keine persönlichen Informationen weiter. Wenn Sie weitere Details hinzufügen möchten, öffnen Sie das GitHub-Problem im nächsten Schritt und fügen Sie einen Kommentar hinzu."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Abbrechen"
},
"report_reasonInputError": {
"message": "Bitte geben Sie einen Grund mit mindestens 10 und höchstens 1000 Zeichen ein" "message": "Bitte geben Sie einen Grund mit mindestens 10 und höchstens 1000 Zeichen ein"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Grund" "message": "Grund"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "Popup ist erschienen" "message": "Popup ist erschienen"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "Es scheint, dass bereits ein Problem geöffnet ist oder als 'wontfix' markiert wurde. Bitte öffnen Sie das Problem und fügen Sie gegebenenfalls weitere Informationen hinzu, indem Sie den folgenden Button verwenden."
},
"report_submitErrorText": {
"message": "Bericht nicht gesendet?"
},
"report_submitSuccessExtraText": {
"message": "Während wir daran arbeiten, können Sie diese Website zur Ausschlussliste in den Erweiterungseinstellungen hinzufügen oder einfach die Erweiterung für diese Website deaktivieren, indem Sie auf das Erweiterungssymbol in Ihrer Browser-Symbolleiste klicken." "message": "Während wir daran arbeiten, können Sie diese Website zur Ausschlussliste in den Erweiterungseinstellungen hinzufügen oder einfach die Erweiterung für diese Website deaktivieren, indem Sie auf das Erweiterungssymbol in Ihrer Browser-Symbolleiste klicken."
}, },
"reportDialog_submitText": { "report_submitSuccessText": {
"message": "Bericht gesendet!" "message": "Bericht gesendet!"
}, },
"reportDialog_urlInputError": { "report_urlInputError": {
"message": "Bitte geben Sie eine gültige URL mit höchstens 1000 Zeichen ein" "message": "Bitte geben Sie eine gültige URL mit höchstens 1000 Zeichen ein"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Import list" "message": "Import list"
}, },
"popup_bannerIssueOpen": {
"message": "An issue has been reported for this page. The extension may not work as expected temporarily. Follow the issue, or add more information"
},
"popup_bannerIssueWontFix": {
"message": "An issue has been reported for this page, but it won't be fixed. Please be aware that the extension may not function as expected on this page. We highly recommend turning off the extension using the button below"
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribute to this project" "message": "Contribute to this project"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Rate this extension" "message": "Rate this extension"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Please, do not share any personal information in this report. If you want to add more details, open the GitHub issue in the next step and add a comment." "message": "Please, do not share any personal information in this report. If you want to add more details, open the GitHub issue in the next step and add a comment."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Cancel"
},
"report_reasonInputError": {
"message": "Please enter a reason with at least 10 characters and no more than 1000 characters" "message": "Please enter a reason with at least 10 characters and no more than 1000 characters"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Reason" "message": "Reason"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "Popup showed up" "message": "Popup showed up"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "It seems that there's an issue open already, or it is marked as 'wontfix'. Please enter the issue if you want to add more information using the following button."
},
"report_submitErrorText": {
"message": "Report not sent?"
},
"report_submitSuccessExtraText": {
"message": "While we are working on this, you can add this website to the exclusion list in the extension settings or just disable the extension for this website clicking on the extension icon in your browser toolbar" "message": "While we are working on this, you can add this website to the exclusion list in the extension settings or just disable the extension for this website clicking on the extension icon in your browser toolbar"
}, },
"reportDialog_submitText": { "report_submitSuccessText": {
"message": "Report sent!" "message": "Report sent!"
}, },
"reportDialog_urlInputError": { "report_urlInputError": {
"message": "Please enter a valid URL with no more than 1000 characters" "message": "Please enter a valid URL with no more than 1000 characters"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Importar lista" "message": "Importar lista"
}, },
"popup_bannerIssueOpen": {
"message": "Se ha informado de un problema en esta página. La extensión puede no funcionar como se espera temporalmente. Siga el problema o agregue más información."
},
"popup_bannerIssueWontFix": {
"message": "Se ha informado de un problema en esta página, pero no se solucionará. Tenga en cuenta que la extensión puede no funcionar como se espera en esta página. Recomendamos encarecidamente desactivar la extensión utilizando el botón a continuación."
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuir a este proyecto" "message": "Contribuir a este proyecto"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Califica esta extensión" "message": "Califica esta extensión"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Por favor, no compartas ninguna información personal en este informe. Si deseas agregar más detalles, abre el problema de GitHub en el siguiente paso y agrega un comentario." "message": "Por favor, no compartas ninguna información personal en este informe. Si deseas agregar más detalles, abre el problema de GitHub en el siguiente paso y agrega un comentario."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Cancelar"
},
"report_reasonInputError": {
"message": "Por favor, ingrese una razón con al menos 10 caracteres y no más de 1000 caracteres" "message": "Por favor, ingrese una razón con al menos 10 caracteres y no más de 1000 caracteres"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Razón" "message": "Razón"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "Apareció un popup" "message": "Apareció un popup"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "Mientras trabajamos en esto, puedes agregar este sitio web a la lista de exclusión en la configuración de la extensión o simplemente deshabilitar la extensión para este sitio web haciendo clic en el ícono de la extensión en la barra de herramientas de tu navegador." "message": "Reporte no enviado?"
}, },
"reportDialog_submitText": { "report_submitErrorText": {
"message": "¡Informe enviado!" "message": "Parece que ya hay un problema abierto o está marcado como 'no se solucionará'. Por favor, ingrese al problema para agregar más información usando el siguiente botón."
}, },
"reportDialog_urlInputError": { "report_submitSuccessExtraText": {
"message": "Mientras trabajamos en esto, puedes agregar este sitio web a la lista de exclusiones en la configuración de la extensión o simplemente deshabilitar la extensión para este sitio web haciendo clic en el icono de la extensión en la barra de herramientas de tu navegador."
},
"report_submitSuccessText": {
"message": "Reporte enviado!"
},
"report_urlInputError": {
"message": "Por favor, ingrese una URL válida con no más de 1000 caracteres" "message": "Por favor, ingrese una URL válida con no más de 1000 caracteres"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Importer la liste" "message": "Importer la liste"
}, },
"popup_bannerIssueOpen": {
"message": "Un problème a été signalé pour cette page. L'extension peut ne pas fonctionner comme prévu temporairement. Suivez le problème ou ajoutez plus d'informations."
},
"popup_bannerIssueWontFix": {
"message": "Un problème a été signalé pour cette page, mais il ne sera pas résolu. Veuillez noter que l'extension pourrait ne pas fonctionner comme prévu sur cette page. Nous vous recommandons vivement de désactiver l'extension en utilisant le bouton ci-dessous."
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuer à ce projet" "message": "Contribuer à ce projet"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Évaluer cette extension" "message": "Évaluer cette extension"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Veuillez ne pas partager d'informations personnelles dans ce rapport. Si vous souhaitez ajouter plus de détails, ouvrez le problème GitHub à l'étape suivante et ajoutez un commentaire." "message": "Veuillez ne pas partager d'informations personnelles dans ce rapport. Si vous souhaitez ajouter plus de détails, ouvrez le problème GitHub à l'étape suivante et ajoutez un commentaire."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Annuler"
},
"report_reasonInputError": {
"message": "Veuillez entrer une raison d'au moins 10 caractères et de pas plus de 1000 caractères" "message": "Veuillez entrer une raison d'au moins 10 caractères et de pas plus de 1000 caractères"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Raison" "message": "Raison"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "Le popup est apparu" "message": "Le popup est apparu"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "Il semble qu'un problème soit déjà ouvert ou marqué comme 'ne sera pas corrigé'. Veuillez entrer dans le problème pour ajouter plus d'informations en utilisant le bouton suivant."
},
"report_submitErrorText": {
"message": "Rapport non envoyé?"
},
"report_submitSuccessExtraText": {
"message": "Pendant que nous travaillons sur ce point, vous pouvez ajouter ce site web à la liste d'exclusion dans les paramètres de l'extension ou simplement désactiver l'extension pour ce site web en cliquant sur l'icône de l'extension dans la barre d'outils de votre navigateur." "message": "Pendant que nous travaillons sur ce point, vous pouvez ajouter ce site web à la liste d'exclusion dans les paramètres de l'extension ou simplement désactiver l'extension pour ce site web en cliquant sur l'icône de l'extension dans la barre d'outils de votre navigateur."
}, },
"reportDialog_submitText": { "report_submitSuccessText": {
"message": "Rapport envoyé!" "message": "Rapport envoyé!"
}, },
"reportDialog_urlInputError": { "report_urlInputError": {
"message": "Veuillez entrer une URL valide de pas plus de 1000 caractères" "message": "Veuillez entrer une URL valide de pas plus de 1000 caractères"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Importa lista" "message": "Importa lista"
}, },
"popup_bannerIssueOpen": {
"message": "È stato segnalato un problema per questa pagina. L'estensione potrebbe non funzionare temporaneamente come previsto. Segui il problema o aggiungi ulteriori informazioni."
},
"popup_bannerIssueWontFix": {
"message": "È stato segnalato un problema per questa pagina, ma non verrà risolto. Si prega di notare che l'estensione potrebbe non funzionare come previsto su questa pagina. Si consiglia vivamente di disattivare l'estensione utilizzando il pulsante qui sotto."
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuisci a questo progetto" "message": "Contribuisci a questo progetto"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Valuta questa estensione" "message": "Valuta questa estensione"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Per favore, non condividere informazioni personali in questo rapporto. Se vuoi aggiungere più dettagli, apri il problema su GitHub nel passaggio successivo e aggiungi un commento." "message": "Per favore, non condividere informazioni personali in questo rapporto. Se vuoi aggiungere più dettagli, apri il problema su GitHub nel passaggio successivo e aggiungi un commento."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Annulla"
},
"report_reasonInputError": {
"message": "Inserisci una motivazione con almeno 10 caratteri e non più di 1000 caratteri" "message": "Inserisci una motivazione con almeno 10 caratteri e non più di 1000 caratteri"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Motivo" "message": "Motivo"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "Popup apparso" "message": "Popup apparso"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "Sembra che ci sia già un problema aperto o contrassegnato come 'non risolvibile'. Per favore, entra nel problema per aggiungere ulteriori informazioni usando il pulsante seguente."
},
"report_submitErrorText": {
"message": "Segnalazione non inviata?"
},
"report_submitSuccessExtraText": {
"message": "Mentre lavoriamo su questo, puoi aggiungere questo sito web alla lista di esclusione nelle impostazioni dell'estensione o semplicemente disattivare l'estensione per questo sito web cliccando sull'icona dell'estensione nella barra degli strumenti del browser." "message": "Mentre lavoriamo su questo, puoi aggiungere questo sito web alla lista di esclusione nelle impostazioni dell'estensione o semplicemente disattivare l'estensione per questo sito web cliccando sull'icona dell'estensione nella barra degli strumenti del browser."
}, },
"reportDialog_submitText": { "report_submitSuccessText": {
"message": "Rapporto inviato!" "message": "Rapporto inviato!"
}, },
"reportDialog_urlInputError": { "report_urlInputError": {
"message": "Inserisci un URL valido con non più di 1000 caratteri" "message": "Inserisci un URL valido con non più di 1000 caratteri"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Importuj listę" "message": "Importuj listę"
}, },
"popup_bannerIssueOpen": {
"message": "Zgłoszono problem z tą stroną. Rozszerzenie może tymczasowo nie działać zgodnie z oczekiwaniami. Śledź problem lub dodaj więcej informacji."
},
"popup_bannerIssueWontFix": {
"message": "Zgłoszono problem z tą stroną, ale nie zostanie on naprawiony. Należy pamiętać, że rozszerzenie może nie działać zgodnie z oczekiwaniami na tej stronie. Zdecydowanie zalecamy wyłączenie rozszerzenia za pomocą poniższego przycisku."
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Wesprzyj ten projekt" "message": "Wesprzyj ten projekt"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Oceń to rozszerzenie" "message": "Oceń to rozszerzenie"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Prosimy, nie udostępniaj żadnych danych osobowych w tym raporcie. Jeśli chcesz dodać więcej szczegółów, otwórz zgłoszenie na GitHub w następnym kroku i dodaj komentarz." "message": "Prosimy, nie udostępniaj żadnych danych osobowych w tym raporcie. Jeśli chcesz dodać więcej szczegółów, otwórz zgłoszenie na GitHub w następnym kroku i dodaj komentarz."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Anuluj"
},
"report_reasonInputError": {
"message": "Proszę podać powód zawierający co najmniej 10 znaków i nie więcej niż 1000 znaków" "message": "Proszę podać powód zawierający co najmniej 10 znaków i nie więcej niż 1000 znaków"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Powód" "message": "Powód"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "Pojawił się popup" "message": "Pojawił się popup"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "Wygląda na to, że istnieje już otwarte zgłoszenie lub zostało oznaczone jako 'nie do rozwiązania'. Wprowadź zgłoszenie, aby dodać więcej informacji, używając poniższego przycisku."
},
"report_submitErrorText": {
"message": "Raport nie został wysłany?"
},
"report_submitSuccessExtraText": {
"message": "Podczas gdy nad tym pracujemy, możesz dodać tę stronę do listy wykluczeń w ustawieniach rozszerzenia lub po prostu wyłączyć rozszerzenie dla tej strony, klikając ikonę rozszerzenia na pasku narzędzi przeglądarki." "message": "Podczas gdy nad tym pracujemy, możesz dodać tę stronę do listy wykluczeń w ustawieniach rozszerzenia lub po prostu wyłączyć rozszerzenie dla tej strony, klikając ikonę rozszerzenia na pasku narzędzi przeglądarki."
}, },
"reportDialog_submitText": { "report_submitSuccessText": {
"message": "Zgłoszenie wysłane!" "message": "Zgłoszenie wysłane!"
}, },
"reportDialog_urlInputError": { "report_urlInputError": {
"message": "Proszę wprowadzić prawidłowy URL zawierający nie więcej niż 1000 znaków" "message": "Proszę wprowadzić prawidłowy URL zawierający nie więcej niż 1000 znaków"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Importar lista" "message": "Importar lista"
}, },
"popup_bannerIssueOpen": {
"message": "Um problema foi relatado para esta página. A extensão pode não funcionar conforme o esperado temporariamente. Acompanhe o problema ou adicione mais informações."
},
"popup_bannerIssueWontFix": {
"message": "Um problema foi relatado para esta página, mas não será corrigido. Esteja ciente de que a extensão pode não funcionar conforme o esperado nesta página. Recomendamos desativar a extensão usando o botão abaixo."
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuir para este projeto" "message": "Contribuir para este projeto"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Avalie esta extensão" "message": "Avalie esta extensão"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Por favor, não compartilhe nenhuma informação pessoal neste relatório. Se você quiser adicionar mais detalhes, abra o problema no GitHub na próxima etapa e adicione um comentário." "message": "Por favor, não compartilhe nenhuma informação pessoal neste relatório. Se você quiser adicionar mais detalhes, abra o problema no GitHub na próxima etapa e adicione um comentário."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Cancelar"
},
"report_reasonInputError": {
"message": "Por favor, insira um motivo com pelo menos 10 caracteres e no máximo 1000 caracteres" "message": "Por favor, insira um motivo com pelo menos 10 caracteres e no máximo 1000 caracteres"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Motivo" "message": "Motivo"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "Popup apareceu" "message": "Popup apareceu"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "Parece que já existe um problema aberto ou marcado como 'não corrigido'. Por favor, acesse o problema para adicionar mais informações usando o botão a seguir."
},
"report_submitErrorText": {
"message": "Relatório não enviado?"
},
"report_submitSuccessExtraText": {
"message": "Enquanto estamos trabalhando nisso, você pode adicionar este site à lista de exclusão nas configurações da extensão ou simplesmente desativar a extensão para este site clicando no ícone da extensão na barra de ferramentas do navegador." "message": "Enquanto estamos trabalhando nisso, você pode adicionar este site à lista de exclusão nas configurações da extensão ou simplesmente desativar a extensão para este site clicando no ícone da extensão na barra de ferramentas do navegador."
}, },
"reportDialog_submitText": { "report_submitSuccessText": {
"message": "Relatório enviado!" "message": "Relatório enviado!"
}, },
"reportDialog_urlInputError": { "report_urlInputError": {
"message": "Por favor, insira uma URL válida com no máximo 1000 caracteres" "message": "Por favor, insira uma URL válida com no máximo 1000 caracteres"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Importar lista" "message": "Importar lista"
}, },
"popup_bannerIssueOpen": {
"message": "Foi relatado um problema para esta página. A extensão pode não funcionar conforme o esperado temporariamente. Siga o problema ou adicione mais informações."
},
"popup_bannerIssueWontFix": {
"message": "Foi relatado um problema para esta página, mas não será resolvido. Esteja ciente de que a extensão pode não funcionar conforme o esperado nesta página. Recomendamos desativar a extensão usando o botão abaixo."
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuir para este projeto" "message": "Contribuir para este projeto"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Avalie esta extensão" "message": "Avalie esta extensão"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Por favor, não partilhe nenhuma informação pessoal neste relatório. Se quiser adicionar mais detalhes, abra o problema no GitHub na próxima etapa e adicione um comentário." "message": "Por favor, não partilhe nenhuma informação pessoal neste relatório. Se quiser adicionar mais detalhes, abra o problema no GitHub na próxima etapa e adicione um comentário."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Cancelar"
},
"report_reasonInputError": {
"message": "Por favor, insira um motivo com pelo menos 10 caracteres e no máximo 1000 caracteres" "message": "Por favor, insira um motivo com pelo menos 10 caracteres e no máximo 1000 caracteres"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Motivo" "message": "Motivo"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "Popup apareceu" "message": "Popup apareceu"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "Parece que já existe um problema aberto ou marcado como 'não corrigido'. Por favor, aceda ao problema para adicionar mais informações usando o botão seguinte."
},
"report_submitErrorText": {
"message": "Relatório não enviado?"
},
"report_submitSuccessExtraText": {
"message": "Enquanto trabalhamos nisso, pode adicionar este site à lista de exclusão nas definições da extensão ou simplesmente desativar a extensão para este site clicando no ícone da extensão na barra de ferramentas do navegador." "message": "Enquanto trabalhamos nisso, pode adicionar este site à lista de exclusão nas definições da extensão ou simplesmente desativar a extensão para este site clicando no ícone da extensão na barra de ferramentas do navegador."
}, },
"reportDialog_submitText": { "report_submitSuccessText": {
"message": "Relatório enviado!" "message": "Relatório enviado!"
}, },
"reportDialog_urlInputError": { "report_urlInputError": {
"message": "Por favor, insira uma URL válida com no máximo 1000 caracteres" "message": "Por favor, insira uma URL válida com no máximo 1000 caracteres"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Importă lista" "message": "Importă lista"
}, },
"popup_bannerIssueOpen": {
"message": "A fost raportată o problemă pentru această pagină. Extensia poate să nu funcționeze temporar conform așteptărilor. Urmăriți problema sau adăugați mai multe informații."
},
"popup_bannerIssueWontFix": {
"message": "A fost raportată o problemă pentru această pagină, dar nu va fi rezolvată. Rețineți că extensia poate să nu funcționeze conform așteptărilor pe această pagină. Vă recomandăm cu insistență să dezactivați extensia folosind butonul de mai jos."
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Contribuie la acest proiect" "message": "Contribuie la acest proiect"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Evaluează această extensie" "message": "Evaluează această extensie"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Te rugăm să nu împărtășești informații personale în acest raport. Dacă dorești să adaugi mai multe detalii, deschide problema GitHub în pasul următor și adaugă un comentariu." "message": "Te rugăm să nu împărtășești informații personale în acest raport. Dacă dorești să adaugi mai multe detalii, deschide problema GitHub în pasul următor și adaugă un comentariu."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Anulează"
},
"report_reasonInputError": {
"message": "Vă rugăm să introduceți un motiv cu cel puțin 10 caractere și maximum 1000 de caractere" "message": "Vă rugăm să introduceți un motiv cu cel puțin 10 caractere și maximum 1000 de caractere"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Motiv" "message": "Motiv"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "A apărut un popup" "message": "A apărut un popup"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "Se pare că există deja o problemă deschisă sau marcată ca 'nu va fi rezolvată'. Vă rugăm să intrați în problemă pentru a adăuga mai multe informații folosind butonul de mai jos."
},
"report_submitErrorText": {
"message": "Raportul nu a fost trimis?"
},
"report_submitSuccessExtraText": {
"message": "În timp ce lucrăm la acest aspect, poți adăuga acest site web la lista de excludere din setările extensiei sau poți dezactiva extensia pentru acest site web făcând clic pe pictograma extensiei din bara de instrumente a browserului." "message": "În timp ce lucrăm la acest aspect, poți adăuga acest site web la lista de excludere din setările extensiei sau poți dezactiva extensia pentru acest site web făcând clic pe pictograma extensiei din bara de instrumente a browserului."
}, },
"reportDialog_submitText": { "report_submitSuccessText": {
"message": "Raport trimis!" "message": "Raport trimis!"
}, },
"reportDialog_urlInputError": { "report_urlInputError": {
"message": "Vă rugăm să introduceți o adresă URL validă cu maximum 1000 de caractere" "message": "Vă rugăm să introduceți o adresă URL validă cu maximum 1000 de caractere"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

@ -32,6 +32,12 @@
"options_importButton": { "options_importButton": {
"message": "Импорт списка" "message": "Импорт списка"
}, },
"popup_bannerIssueOpen": {
"message": "Для этой страницы было сообщено о проблеме. Расширение может временно не работать должным образом. Следите за проблемой или добавьте дополнительную информацию."
},
"popup_bannerIssueWontFix": {
"message": "Для этой страницы было сообщено о проблеме, но она не будет исправлена. Обратите внимание, что расширение может работать некорректно на этой странице. Мы настоятельно рекомендуем отключить расширение, используя кнопку ниже."
},
"popup_contributeOption": { "popup_contributeOption": {
"message": "Содействовать этому проекту" "message": "Содействовать этому проекту"
}, },
@ -47,28 +53,37 @@
"popup_rateOption": { "popup_rateOption": {
"message": "Оцените это расширение" "message": "Оцените это расширение"
}, },
"reportDialog_bodyText": { "report_bodyText": {
"message": "Пожалуйста, не делитесь личной информацией в этом отчете. Если вы хотите добавить больше деталей, откройте вопрос на GitHub на следующем шаге и добавьте комментарий." "message": "Пожалуйста, не делитесь личной информацией в этом отчете. Если вы хотите добавить больше деталей, откройте вопрос на GitHub на следующем шаге и добавьте комментарий."
}, },
"reportDialog_reasonInputError": { "report_cancelButtonText": {
"message": "Отмена"
},
"report_reasonInputError": {
"message": "Пожалуйста, введите причину длиной не менее 10 и не более 1000 символов" "message": "Пожалуйста, введите причину длиной не менее 10 и не более 1000 символов"
}, },
"reportDialog_reasonInputLabel": { "report_reasonInputLabel": {
"message": "Причина" "message": "Причина"
}, },
"reportDialog_reasonInputPlaceholder": { "report_reasonInputPlaceholder": {
"message": "Появилось всплывающее окно" "message": "Появилось всплывающее окно"
}, },
"reportDialog_submitExtraText": { "report_submitErrorExtraText": {
"message": "Похоже, что уже существует открытая проблема или она помечена как 'не будет исправлено'. Пожалуйста, войдите в проблему, чтобы добавить больше информации, используя следующую кнопку."
},
"report_submitErrorText": {
"message": "Отчет не отправлен?"
},
"report_submitSuccessExtraText": {
"message": "Пока мы работаем над этим, вы можете добавить этот сайт в список исключений в настройках расширения или просто отключить расширение для этого сайта, нажав на значок расширения на панели инструментов вашего браузера." "message": "Пока мы работаем над этим, вы можете добавить этот сайт в список исключений в настройках расширения или просто отключить расширение для этого сайта, нажав на значок расширения на панели инструментов вашего браузера."
}, },
"reportDialog_submitText": { "report_submitSuccessText": {
"message": "Отчет отправлен!" "message": "Отчет отправлен!"
}, },
"reportDialog_urlInputError": { "report_urlInputError": {
"message": "Пожалуйста, введите корректный URL длиной не более 1000 символов" "message": "Пожалуйста, введите корректный URL длиной не более 1000 символов"
}, },
"reportDialog_urlInputLabel": { "report_urlInputLabel": {
"message": "URL" "message": "URL"
} }
} }

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "Cookie Dialog Monster", "name": "Cookie Dialog Monster",
"version": "7.3.2", "version": "8.0.0",
"default_locale": "en", "default_locale": "en",
"description": "__MSG_appDesc__", "description": "__MSG_appDesc__",
"icons": { "icons": {
@ -10,7 +10,7 @@
"128": "assets/icons/128.png" "128": "assets/icons/128.png"
}, },
"action": { "action": {
"default_icon": "assets/icons/disabled.png", "default_icon": "assets/icons/off.png",
"default_title": "Cookie Dialog Monster" "default_title": "Cookie Dialog Monster"
}, },
"options_page": "options.html", "options_page": "options.html",
@ -51,7 +51,7 @@
"*://translate.google.it/*", "*://translate.google.it/*",
"*://www.cookie-dialog-monster.com/*" "*://www.cookie-dialog-monster.com/*"
], ],
"js": ["scripts/content.js", "scripts/dialog.js"], "js": ["scripts/content.js"],
"matches": ["http://*/*", "https://*/*"], "matches": ["http://*/*", "https://*/*"],
"run_at": "document_start" "run_at": "document_start"
} }

View File

@ -1,6 +1,8 @@
<!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cookie Dialog Monster > Exclusion List</title> <title>Cookie Dialog Monster > Exclusion List</title>
<link rel="stylesheet" href="/styles/reset.css" /> <link rel="stylesheet" href="/styles/reset.css" />
<link rel="stylesheet" href="/styles/options.css" /> <link rel="stylesheet" href="/styles/options.css" />

View File

@ -1,6 +1,8 @@
<!doctype html>
<html> <html>
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/styles/reset.css" /> <link rel="stylesheet" href="/styles/reset.css" />
<link rel="stylesheet" href="/styles/popup.css" /> <link rel="stylesheet" href="/styles/popup.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter" />
@ -9,6 +11,22 @@
<body> <body>
<header> <header>
<h1 class="header-title">Cookie Dialog Monster</h1> <h1 class="header-title">Cookie Dialog Monster</h1>
<div class="header-actions">
<button disabled id="report-button">
<svg
fill="none"
height="18"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
stroke="currentColor"
viewBox="0 0 24 24"
width="18"
>
<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"></path>
<line x1="4" y1="22" x2="4" y2="15"></line>
</svg>
</button>
<button id="settings-button"> <button id="settings-button">
<svg <svg
aria-hidden="true" aria-hidden="true"
@ -27,8 +45,29 @@
/> />
</svg> </svg>
</button> </button>
</div>
</header> </header>
<main> <main>
<p aria-hidden="true" class="banner" id="issue-banner" role="alert">
<span id="issue-banner-text"></span>
<a aria-label="GitHub" id="issue-banner-url" target="_blank">
<svg
fill="none"
height="12"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
stroke="currentColor"
viewBox="0 0 24 24"
width="12"
>
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
<polyline points="15 3 21 3 21 9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg>
</a>
</p>
<div class="content">
<popup-button id="power-option" role="button" tabindex="0"> <popup-button id="power-option" role="button" tabindex="0">
<svg <svg
aria-hidden="true" aria-hidden="true"
@ -46,7 +85,12 @@
</svg> </svg>
<span id="host"></span> <span id="host"></span>
</popup-button> </popup-button>
<popup-button data-href="mailto:hello@wanhose.dev" id="help-option" role="link" tabindex="0"> <popup-button
data-href="mailto:hello@wanhose.dev"
id="help-option"
role="link"
tabindex="0"
>
<svg <svg
aria-hidden="true" aria-hidden="true"
fill="none" fill="none"
@ -129,7 +173,9 @@
> >
<polyline points="1 4 1 10 7 10"></polyline> <polyline points="1 4 1 10 7 10"></polyline>
<polyline points="23 20 23 14 17 14"></polyline> <polyline points="23 20 23 14 17 14"></polyline>
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path> <path
d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"
></path>
</svg> </svg>
<svg <svg
aria-hidden="true" aria-hidden="true"
@ -152,6 +198,101 @@
<span id="extension-version"></span> <span id="extension-version"></span>
</popup-data> </popup-data>
</popup-data-container> </popup-data-container>
</div>
<div class="report" style="display: none">
<div class="report-form-view">
<div class="report-body-text" data-i18n="report_bodyText"></div>
<div class="report-form">
<div class="report-input-group">
<div class="report-input-label" id="report-label-url">
<span data-i18n="report_urlInputLabel"></span>
<span class="report-input-label-required">*</span>
</div>
<input
aria-labelledby="report-label-url"
aria-required="true"
class="report-input"
id="report-input-url"
/>
<div
class="report-input-error"
data-i18n="report_urlInputError"
id="report-input-url-error"
></div>
</div>
<div class="report-input-group">
<div class="report-input-label" id="report-label-reason">
<span data-i18n="report_reasonInputLabel"></span>
<span class="report-input-label-required">*</span>
</div>
<textarea
aria-labelledby="report-label-reason"
aria-required="true"
class="report-input"
data-i18n="report_reasonInputPlaceholder"
id="report-input-reason"
rows="4"
></textarea>
<div
class="report-input-error"
data-i18n="report_reasonInputError"
id="report-input-reason-error"
></div>
</div>
<div class="report-buttons">
<button class="report-submit-button" data-i18n="contextMenu_reportOption"></button>
<button class="report-cancel-button" data-i18n="report_cancelButtonText"></button>
</div>
</div>
</div>
<div class="report-submit-error-view" hidden>
<svg
fill="none"
height="48"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
stroke="var(--color-error)"
viewBox="0 0 24 24"
width="48"
>
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="12"></line>
<line x1="12" y1="16" x2="12.01" y2="16"></line>
</svg>
<div class="report-submit-text" data-i18n="report_submitErrorText"></div>
<div class="report-submit-extra-text" data-i18n="report_submitErrorExtraText"></div>
<div
class="report-issue-button"
data-i18n="contextMenu_issueOption"
role="button"
tabindex="0"
></div>
</div>
<div class="report-submit-success-view" hidden>
<svg
fill="none"
height="48"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
stroke="var(--color-success)"
viewBox="0 0 24 24"
width="48"
>
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
<polyline points="22 4 12 14.01 9 11.01" />
</svg>
<div class="report-submit-text" data-i18n="report_submitSuccessText"></div>
<div class="report-submit-extra-text" data-i18n="report_submitSuccessExtraText"></div>
<div
class="report-issue-button"
data-i18n="contextMenu_issueOption"
role="button"
tabindex="0"
></div>
</div>
</div>
</main> </main>
<footer></footer> <footer></footer>
</body> </body>

View File

@ -1,12 +1,54 @@
/**
* @typedef {Object} ExtensionIssue
* @property {number} [expiresIn]
* @property {string[]} [flags]
* @property {string} [url]
*/
/**
* @typedef {Object} ExtensionState
* @property {ExtensionIssue} [issue]
* @property {boolean} on
*/
if (typeof browser === 'undefined') { if (typeof browser === 'undefined') {
browser = chrome; browser = chrome;
} }
/**
* @description Class for request batching
*/
class RequestManager {
constructor() {
this.requests = new Map(); // Store ongoing requests
}
/**
* @description Fetch wrapper to play with the request map
* @param {string} input
* @param {RequestInit} [init]
* @returns {Promise<any>}
*/
fetchData(input, init) {
if (this.requests.has(input)) {
return this.requests.get(input);
}
const promise = fetch(input, init)
.then((response) => response.json())
.finally(() => this.requests.delete(input));
this.requests.set(input, promise);
return promise;
}
}
/** /**
* @description API URL * @description API URL
* @type {string} * @type {string}
*/ */
const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v4'; const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v5';
/** /**
* @description Context menu identifier * @description Context menu identifier
@ -20,6 +62,11 @@ const extensionMenuItemId = 'CDM-MENU';
*/ */
const reportMenuItemId = 'CDM-REPORT'; const reportMenuItemId = 'CDM-REPORT';
/**
* @description Request manager instance
*/
const requestManager = new RequestManager();
/** /**
* @description Context menu identifier * @description Context menu identifier
* @type {string} * @type {string}
@ -32,9 +79,15 @@ const settingsMenuItemId = 'CDM-SETTINGS';
*/ */
const script = browser.scripting; const script = browser.scripting;
/**
* @description Default value for extension state
* @type {ExtensionState}
*/
const stateByDefault = { issue: { expiresIn: 0 }, on: true };
/** /**
* @description The storage to use * @description The storage to use
* @type {browser.storage.LocalStorageArea} * @type {browser.storage.StorageArea}
*/ */
const storage = browser.storage.local; const storage = browser.storage.local;
@ -44,7 +97,44 @@ const storage = browser.storage.local;
const suppressLastError = () => void browser.runtime.lastError; const suppressLastError = () => void browser.runtime.lastError;
/** /**
* @description Calculate current hostname * @async
* @description Enable extension icon
* @param {number} tabId
* @returns {Promise<void>}
*/
async function enableIcon(hostname, tabId) {
const state = await getState(hostname);
const path = state.issue?.url ? '/assets/icons/warn.png' : '/assets/icons/on.png';
await browser.action.setIcon({ path, tabId }, suppressLastError);
}
/**
* @async
* @description Get database
* @returns {Promise<Object>}
*/
async function getData() {
const { data } = await storage.get('data');
if (!data) {
return await refreshData();
}
return data;
}
/**
* @async
* @description Disable report context menu option
* @returns {Promise<void>}
*/
async function disableReport() {
return browser.contextMenus.update(reportMenuItemId, { enabled: false });
}
/**
* @description Get current hostname
* @param {string} url * @param {string} url
* @returns {string} * @returns {string}
*/ */
@ -52,6 +142,33 @@ function getHostname(url) {
return new URL(url).hostname.split('.').slice(-3).join('.').replace('www.', ''); return new URL(url).hostname.split('.').slice(-3).join('.').replace('www.', '');
} }
/**
* @async
* @description Get current active tab
* @returns {Promise<browser.tabs.Tab>}
*/
async function getTab() {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
return tabs[0];
}
/**
* @async
* @description Get state for the given hostname
* @param {string} hostname
* @returns {Promise<ExtensionState>}
*/
async function getState(hostname) {
const { [hostname]: state = stateByDefault } = await storage.get(hostname);
if ((state.issue && Date.now() > state.issue.expiresIn) || !state.issue?.expiresIn) {
state.issue = await refreshIssue(hostname);
}
return { ...stateByDefault, ...state };
}
/** /**
* @description Format number to avoid errors * @description Format number to avoid errors
* @param {number} [value] * @param {number} [value]
@ -81,32 +198,57 @@ function matchToPattern(match) {
} }
/** /**
* @async
* @description Refresh data * @description Refresh data
* @param {void?} callback * @returns {Promise<void>}
* @returns {void}
*/ */
function refreshData(callback) { async function refreshData() {
try { try {
fetch(`${apiUrl}/data/`).then((result) => { const { data } = await requestManager.fetchData(`${apiUrl}/data/`);
result.json().then(({ data }) => {
storage.set({ data }, suppressLastError); await updateStore('data', data);
callback?.(data);
}); return data;
});
} catch { } catch {
refreshData(callback); return await refreshData();
} }
} }
/** /**
* @async * @async
* @description Report active tab URL * @description Refresh issues for the given hostname
* @param {string} hostname
* @returns {Promise<ExtensionIssue | undefined>}
*/
async function refreshIssue(hostname) {
try {
const { data } = await requestManager.fetchData(`${apiUrl}/issues/${hostname}`);
if (Object.keys(data).length === 0) {
await updateStore(hostname, { issue: { expiresIn: Date.now() + 8 * 60 * 60 * 1000 } });
return undefined;
}
const issue = { expiresIn: Date.now() + 4 * 60 * 60 * 1000, flags: data.flags, url: data.url };
await updateStore(hostname, { issue });
return data;
} catch {
return await refreshData();
}
}
/**
* @async
* @description Report given page
* @param {any} message * @param {any} message
* @param {browser.tabs.Tab} tab * @param {browser.tabs.Tab} tab
* @param {void?} callback * @param {void?} callback
* @returns {void} * @returns {Promise<void>}
*/ */
async function report(message, tab, callback) { async function report(message) {
try { try {
const reason = message.reason; const reason = message.reason;
const url = message.url; const url = message.url;
@ -114,25 +256,36 @@ async function report(message, tab, callback) {
const version = browser.runtime.getManifest().version; const version = browser.runtime.getManifest().version;
const body = JSON.stringify({ reason, url, userAgent, version }); const body = JSON.stringify({ reason, url, userAgent, version });
const headers = { 'Cache-Control': 'no-cache', 'Content-type': 'application/json' }; const headers = { 'Cache-Control': 'no-cache', 'Content-type': 'application/json' };
const requestInit = { body, headers, method: 'POST' };
const response = await fetch(`${apiUrl}/report/`, { body, headers, method: 'POST' }); return await requestManager.fetchData(`${apiUrl}/report/`, requestInit);
callback?.((await response.json()).data);
} catch { } catch {
console.error("Can't send report"); console.error("Can't send report");
} }
} }
/**
* @async
* @description Update extension store for a given key
* @param {string} [key]
* @param {Object} value
* @returns {Promise<void>}
*/
async function updateStore(key, value) {
if (key) {
const { [key]: prev } = await storage.get(key);
await storage.set({ [key]: { ...prev, ...value } }, suppressLastError);
}
}
/** /**
* @description Listen to context menus clicked * @description Listen to context menus clicked
*/ */
browser.contextMenus.onClicked.addListener((info, tab) => { browser.contextMenus.onClicked.addListener((info) => {
const tabId = tab?.id;
switch (info.menuItemId) { switch (info.menuItemId) {
case reportMenuItemId: case reportMenuItemId:
if (tabId !== undefined) { browser.action.openPopup();
browser.tabs.sendMessage(tabId, { type: 'SHOW_REPORT_DIALOG' }, suppressLastError);
}
break; break;
case settingsMenuItemId: case settingsMenuItemId:
browser.runtime.openOptionsPage(); browser.runtime.openOptionsPage();
@ -151,14 +304,18 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
const tabId = sender.tab?.id; const tabId = sender.tab?.id;
switch (message.type) { switch (message.type) {
case 'DISABLE_REPORT':
if (isPage && tabId !== undefined) disableReport();
break;
case 'DISABLE_ICON': case 'DISABLE_ICON':
if (isPage && tabId !== undefined) { if (isPage && tabId !== undefined) {
browser.action.setIcon({ path: '/assets/icons/disabled.png', tabId }, suppressLastError); browser.action.setIcon({ path: '/assets/icons/off.png', tabId }, suppressLastError);
} }
break; break;
case 'ENABLE_ICON': case 'ENABLE_ICON':
if (isPage && tabId !== undefined) { if (isPage && tabId !== undefined) {
browser.action.setIcon({ path: '/assets/icons/enabled.png', tabId }, suppressLastError); enableIcon(hostname, tabId).then(callback);
return true;
} }
break; break;
case 'ENABLE_POPUP': case 'ENABLE_POPUP':
@ -166,59 +323,47 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
browser.action.setPopup({ popup: '/popup.html', tabId }, suppressLastError); browser.action.setPopup({ popup: '/popup.html', tabId }, suppressLastError);
} }
break; break;
case 'ENABLE_REPORT':
if (isPage && tabId !== undefined) {
browser.contextMenus.update(reportMenuItemId, { enabled: true });
}
break;
case 'GET_DATA': case 'GET_DATA':
storage.get('data', ({ data }) => { getData().then(callback);
if (data) callback(data);
else refreshData(callback);
});
return true; return true;
case 'GET_EXCLUSION_LIST': case 'GET_EXCLUSION_LIST':
storage.get(null, (exclusions) => { storage.get(null, (exclusions) => {
const exclusionList = Object.entries(exclusions || {}).flatMap((exclusion) => const exclusionList = Object.entries(exclusions || {}).flatMap((exclusion) => {
exclusion[0] !== 'data' && !exclusion[1]?.enabled ? [exclusion[0]] : [] return exclusion[0] !== 'data' && exclusion[1].on === false ? [exclusion[0]] : [];
); });
callback(exclusionList); callback(exclusionList);
}); });
return true; return true;
case 'GET_HOSTNAME_STATE': case 'GET_STATE':
if (hostname) { if (hostname) {
storage.get(hostname, (state) => { getState(hostname).then(callback);
callback(state[hostname] ?? { enabled: true });
});
return true; return true;
} }
break; break;
case 'GET_TAB': case 'GET_TAB':
browser.tabs.query({ active: true, currentWindow: true }, (tabs) => { getTab().then(callback);
callback(tabs[0]);
});
return true; return true;
case 'INSERT_DIALOG_CSS':
if (isPage && tabId !== undefined) {
script.insertCSS({ files: ['styles/dialog.css'], target: { tabId } });
}
break;
case 'REFRESH_DATA': case 'REFRESH_DATA':
refreshData(callback); refreshData().then(callback);
return true; return true;
case 'REPORT': case 'REPORT':
if (tabId !== undefined) { report(message).then(callback);
report(message, sender.tab, callback);
return true; return true;
}
break; case 'UPDATE_BADGE':
case 'SET_BADGE':
if (isPage && tabId !== undefined) { if (isPage && tabId !== undefined) {
browser.action.setBadgeBackgroundColor({ color: '#6b7280' }); browser.action.setBadgeBackgroundColor({ color: '#6b7280' });
browser.action.setBadgeText({ tabId, text: formatNumber(message.value) }); browser.action.setBadgeText({ tabId, text: formatNumber(message.value) });
} }
break; break;
case 'SET_HOSTNAME_STATE': case 'UPDATE_STORE':
if (hostname) { updateStore(hostname, message.state).then(callback);
if (message.state.enabled === false) storage.set({ [hostname]: message.state }); return true;
else storage.remove(hostname);
}
break;
default: default:
break; break;
} }
@ -227,7 +372,7 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
/** /**
* @description Listens to extension installed * @description Listens to extension installed
*/ */
browser.runtime.onInstalled.addListener(() => { browser.runtime.onInstalled.addListener((details) => {
const documentUrlPatterns = browser.runtime.getManifest().content_scripts[0].matches; const documentUrlPatterns = browser.runtime.getManifest().content_scripts[0].matches;
browser.contextMenus.create( browser.contextMenus.create(
@ -253,12 +398,24 @@ browser.runtime.onInstalled.addListener(() => {
{ {
contexts: ['all'], contexts: ['all'],
documentUrlPatterns, documentUrlPatterns,
enabled: false,
id: reportMenuItemId, id: reportMenuItemId,
parentId: extensionMenuItemId, parentId: extensionMenuItemId,
title: browser.i18n.getMessage('contextMenu_reportOption'), title: browser.i18n.getMessage('contextMenu_reportOption'),
}, },
suppressLastError suppressLastError
); );
if (details.reason === 'update') {
storage.remove('updateAvailable');
}
});
/**
* @description Listen to available updates
*/
browser.runtime.onUpdateAvailable.addListener((details) => {
storage.set({ updateAvailable: details.version }, suppressLastError);
}); });
/** /**
@ -268,6 +425,13 @@ browser.runtime.onStartup.addListener(() => {
refreshData(); refreshData();
}); });
/**
* @description Listen to tab changes
*/
browser.tabs.onActivated.addListener(() => {
disableReport();
});
/** /**
* @description Listen to the moment before a request is made to apply the rules * @description Listen to the moment before a request is made to apply the rules
* @returns {Promise<void>} * @returns {Promise<void>}
@ -285,8 +449,9 @@ browser.webRequest.onBeforeRequest.addListener(
return; return;
} }
const data = await getData();
const hostname = getHostname(url); const hostname = getHostname(url);
const { data, [hostname]: state = { enabled: true } } = await storage.get(['data', hostname]); const state = await getState(hostname);
if (data?.rules?.length) { if (data?.rules?.length) {
const rules = data.rules.map((rule) => ({ const rules = data.rules.map((rule) => ({
@ -295,7 +460,7 @@ browser.webRequest.onBeforeRequest.addListener(
})); }));
await browser.declarativeNetRequest.updateSessionRules({ await browser.declarativeNetRequest.updateSessionRules({
addRules: state.enabled ? rules : undefined, addRules: state.on ? rules : undefined,
removeRuleIds: data.rules.map((rule) => rule.id), removeRuleIds: data.rules.map((rule) => rule.id),
}); });
} }
@ -313,9 +478,9 @@ browser.webRequest.onErrorOccurred.addListener(
if (error === 'net::ERR_BLOCKED_BY_CLIENT' && tabId > -1) { if (error === 'net::ERR_BLOCKED_BY_CLIENT' && tabId > -1) {
const hostname = getHostname(url); const hostname = getHostname(url);
const { [hostname]: state = { enabled: true } } = await storage.get(hostname); const state = await getState(hostname);
if (state.enabled) { if (state.on) {
await browser.tabs.sendMessage(tabId, { type: 'INCREASE_ACTIONS_COUNT' }); await browser.tabs.sendMessage(tabId, { type: 'INCREASE_ACTIONS_COUNT' });
} }
} }

View File

@ -6,6 +6,11 @@
* @property {{ backdrops: string[], classes: string[], containers: string[], selectors: string[] }} tokens * @property {{ backdrops: string[], classes: string[], containers: string[], selectors: string[] }} tokens
*/ */
/**
* @typedef {Object} ContentState
* @property {boolean} on
*/
/** /**
* @typedef {Object} Fix * @typedef {Object} Fix
* @property {string} action * @property {string} action
@ -91,9 +96,9 @@ const seen = new Set();
/** /**
* @description Extension state * @description Extension state
* @type {{ enabled: boolean }} * @type {ContentState}
*/ */
let state = { enabled: true }; let state = { on: true };
/** /**
* @description Clean DOM * @description Clean DOM
@ -115,8 +120,8 @@ function clean(elements, skipMatch) {
if (element instanceof HTMLDialogElement) element.close(); if (element instanceof HTMLDialogElement) element.close();
hide(element); hide(element);
actions.add(new Date().getTime().toString()); actions.add(`${Date.now()}`);
dispatch({ type: 'SET_BADGE', value: actions.size }); dispatch({ type: 'UPDATE_BADGE', value: actions.size });
} }
seen.add(element); seen.add(element);
@ -295,7 +300,7 @@ function fix() {
for (const backdrop of backdrops) { for (const backdrop of backdrops) {
if (backdrop.children.length === 0 && !seen.has(backdrop)) { if (backdrop.children.length === 0 && !seen.has(backdrop)) {
actions.add(new Date().getTime().toString()); actions.add(`${Date.now()}`);
seen.add(backdrop); seen.add(backdrop);
hide(backdrop); hide(backdrop);
} }
@ -366,7 +371,7 @@ function fix() {
t4Wrapper.removeAttribute('inert'); t4Wrapper.removeAttribute('inert');
} }
dispatch({ type: 'SET_BADGE', value: actions.size }); dispatch({ type: 'UPDATE_BADGE', value: actions.size });
} }
/** /**
@ -390,7 +395,7 @@ function hide(element) {
function run(params = {}) { function run(params = {}) {
const { containers, elements, skipMatch } = params; const { containers, elements, skipMatch } = params;
if (document.body?.children.length && state.enabled && tokens.selectors.length) { if (document.body?.children.length && state.on && tokens.selectors.length) {
fix(); fix();
if (elements?.length) { if (elements?.length) {
@ -409,10 +414,10 @@ function run(params = {}) {
* @param {SetUpParams} [params] * @param {SetUpParams} [params]
*/ */
async function setUp(params = {}) { async function setUp(params = {}) {
state = (await dispatch({ hostname, type: 'GET_HOSTNAME_STATE' })) ?? state; state = await dispatch({ hostname, type: 'GET_STATE' });
dispatch({ type: 'ENABLE_POPUP' }); dispatch({ type: 'ENABLE_POPUP' });
if (state.enabled) { if (state.on) {
const data = await dispatch({ hostname, type: 'GET_DATA' }); const data = await dispatch({ hostname, type: 'GET_DATA' });
commonWords = data?.commonWords ?? commonWords; commonWords = data?.commonWords ?? commonWords;
@ -420,13 +425,15 @@ async function setUp(params = {}) {
skips = data?.skips ?? skips; skips = data?.skips ?? skips;
tokens = data?.tokens ?? tokens; tokens = data?.tokens ?? tokens;
dispatch({ type: 'ENABLE_ICON' }); dispatch({ type: 'ENABLE_REPORT' });
dispatch({ type: 'SET_BADGE', value: actions.size }); dispatch({ hostname, type: 'ENABLE_ICON' });
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
observer.observe(document.body ?? document.documentElement, options); observer.observe(document.body ?? document.documentElement, options);
if (!params.skipRunFn) run({ containers: tokens.containers }); if (!params.skipRunFn) run({ containers: tokens.containers });
} else { } else {
dispatch({ type: 'DISABLE_REPORT' });
dispatch({ type: 'DISABLE_ICON' }); dispatch({ type: 'DISABLE_ICON' });
dispatch({ type: 'SET_BADGE', value: actions.size }); dispatch({ type: 'UPDATE_BADGE', value: actions.size });
observer.disconnect(); observer.disconnect();
} }
} }
@ -449,7 +456,7 @@ async function setUpAfterWaitForBody() {
* @type {MutationObserver} * @type {MutationObserver}
*/ */
const observer = new MutationObserver((mutations) => { const observer = new MutationObserver((mutations) => {
if (!state.enabled || !tokens.selectors.length) { if (!state.on || !tokens.selectors.length) {
return; return;
} }
@ -466,7 +473,7 @@ const observer = new MutationObserver((mutations) => {
browser.runtime.onMessage.addListener(async (message) => { browser.runtime.onMessage.addListener(async (message) => {
switch (message.type) { switch (message.type) {
case 'INCREASE_ACTIONS_COUNT': { case 'INCREASE_ACTIONS_COUNT': {
actions.add(new Date().getTime().toString()); actions.add(`${Date.now()}`);
break; break;
} }
} }
@ -490,10 +497,14 @@ window.addEventListener('pageshow', async (event) => {
* @returns {void} * @returns {void}
*/ */
window.addEventListener('visibilitychange', async () => { window.addEventListener('visibilitychange', async () => {
if (document.visibilityState === 'visible' && !initiallyVisible) { if (document.visibilityState === 'visible') {
if (!initiallyVisible) {
initiallyVisible = true; initiallyVisible = true;
await setUp(); await setUp();
} }
dispatch({ type: state.on ? 'ENABLE_REPORT' : 'DISABLE_REPORT' });
}
}); });
/** /**

View File

@ -1,272 +0,0 @@
if (typeof browser === 'undefined') {
browser = chrome;
}
/**
* @description Report dialog ID
*/
const reportDialogId = 'report-dialog';
/**
* @description Report dialog outer HTML
*/
const reportDialogHtml = `
<dialog id="${reportDialogId}" tabindex="0">
<div class="report-dialog-header">
<div class="report-dialog-header-title">Cookie Dialog Monster</div>
<div class="report-dialog-close-button" role="button" tabindex="0">
<svg
fill="none"
height="20"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="20"
>
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
</div>
</div>
<div class="report-dialog-body">
<div class="report-dialog-form-view">
<div class="report-dialog-body-text">
${browser.i18n.getMessage('reportDialog_bodyText')}
</div>
<div class="report-dialog-form">
<div class="report-dialog-input-group">
<div class="report-dialog-input-label" id="report-dialog-label-url">
${browser.i18n.getMessage('reportDialog_urlInputLabel')}
<span class="report-dialog-input-label-required">*</span>
</div>
<input
aria-labelledby="report-dialog-label-url"
aria-required="true"
class="report-dialog-input"
id="report-dialog-input-url"
/>
<div class="report-dialog-input-error" id="report-dialog-input-url-error">
${browser.i18n.getMessage('reportDialog_urlInputError')}
</div>
</div>
<div class="report-dialog-input-group">
<div class="report-dialog-input-label" id="report-dialog-label-reason">
${browser.i18n.getMessage('reportDialog_reasonInputLabel')}
<span class="report-dialog-input-label-required">*</span>
</div>
<textarea
aria-labelledby="report-dialog-label-reason"
aria-required="true"
class="report-dialog-input"
id="report-dialog-input-reason"
rows="4"
>${browser.i18n.getMessage('reportDialog_reasonInputPlaceholder')}</textarea>
<div class="report-dialog-input-error" id="report-dialog-input-reason-error">
${browser.i18n.getMessage('reportDialog_reasonInputError')}
</div>
</div>
<div class="report-dialog-submit-button" role="button" tabindex="0">
${browser.i18n.getMessage('contextMenu_reportOption')?.replace('...', '')}
</div>
</div>
</div>
<div class="report-dialog-submit-view" hidden>
<svg
fill="none"
height="48"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
stroke="var(--cookie-dialog-monster-color-success)"
viewBox="0 0 24 24"
width="48"
>
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
<polyline points="22 4 12 14.01 9 11.01" />
</svg>
<div class="report-dialog-submit-text">
${browser.i18n.getMessage('reportDialog_submitText')}
</div>
<div class="report-dialog-submit-extra-text">
${browser.i18n.getMessage('reportDialog_submitExtraText')}
</div>
<div class="report-dialog-issue-button" role="button" tabindex="0">
${browser.i18n.getMessage('contextMenu_issueOption')}
</div>
</div>
</div>
</dialog>
`;
/**
* @description Dialog close button click handler
* @param {MouseEvent} event
*/
function closeButtonClickHandler(event) {
const dialog = document.getElementById(reportDialogId);
event.preventDefault();
dialog?.remove();
}
/**
* @description Hide report dialog
*/
function hideReportDialog() {
document.getElementById(reportDialogId)?.remove();
}
/**
* @description Input change handler
* @param {InputEvent} event
*/
function inputChangeHandler(event) {
event.currentTarget.removeAttribute('aria-invalid');
}
/**
* @description Input key down handler
* @param {KeyboardEvent} event
*/
function inputKeyDownHandler(event) {
if (event.key === 'Enter') {
event.preventDefault();
event.currentTarget.blur();
}
}
/**
* @description Show report dialog
*/
function showReportDialog() {
const existingDialog = document.getElementById(reportDialogId);
if (existingDialog) {
const submitButton = existingDialog.getElementsByClassName('report-dialog-submit-button')[0];
const urlInput = existingDialog.querySelector('#report-dialog-input-url');
existingDialog.showModal();
submitButton.setAttribute('aria-disabled', 'false');
urlInput.setAttribute('value', window.location.origin + window.location.pathname);
return;
}
const parser = new DOMParser();
const result = parser.parseFromString(reportDialogHtml, 'text/html');
const dialog = result.body.firstElementChild;
const closeButton = dialog.getElementsByClassName('report-dialog-close-button')[0];
const link = document.createElement('link');
const reasonInput = dialog?.querySelector('#report-dialog-input-reason');
const submitButton = dialog?.getElementsByClassName('report-dialog-submit-button')[0];
const urlInput = dialog?.querySelector('#report-dialog-input-url');
closeButton.addEventListener('click', closeButtonClickHandler);
urlInput.setAttribute('value', window.location.origin + window.location.pathname);
link.setAttribute('href', 'https://fonts.googleapis.com/css?family=Inter');
link.setAttribute('id', 'report-dialog-font');
link.setAttribute('rel', 'stylesheet');
reasonInput.addEventListener('input', inputChangeHandler);
reasonInput.addEventListener('keydown', inputKeyDownHandler);
submitButton.addEventListener('click', submitButtonClickHandler);
urlInput.addEventListener('input', inputChangeHandler);
urlInput.addEventListener('keydown', inputKeyDownHandler);
dispatch({ type: 'INSERT_DIALOG_CSS' });
document.body.appendChild(dialog);
document.head.appendChild(link);
dialog.showModal();
}
/**
* @description Dialog submit button click handler
* @param {MouseEvent} event
*/
async function submitButtonClickHandler(event) {
event.preventDefault();
if (event.currentTarget.getAttribute('aria-disabled') === 'true') {
return;
}
event.currentTarget.setAttribute('aria-disabled', 'true');
const dialog = document.getElementById(reportDialogId);
const reasonInput = dialog?.querySelector('#report-dialog-input-reason');
const reasonText = reasonInput?.value.trim();
const urlInput = dialog?.querySelector('#report-dialog-input-url');
const urlText = urlInput?.value.trim();
const errors = validateForm({ reason: reasonText, url: urlText });
if (errors) {
if (errors.reason) {
reasonInput?.setAttribute('aria-invalid', 'true');
reasonInput?.setAttribute('aria-errormessage', 'report-dialog-input-reason-error');
}
if (errors.url) {
urlInput?.setAttribute('aria-invalid', 'true');
urlInput?.setAttribute('aria-errormessage', 'report-dialog-input-url-error');
}
event.currentTarget.setAttribute('aria-disabled', 'false');
return;
}
const formView = dialog?.getElementsByClassName('report-dialog-form-view')[0];
const issueButton = dialog?.getElementsByClassName('report-dialog-issue-button')[0];
const submitView = dialog?.getElementsByClassName('report-dialog-submit-view')[0];
const userAgent = window.navigator.userAgent;
const issueUrl = await dispatch({ userAgent, reason: reasonText, url: urlText, type: 'REPORT' });
formView?.setAttribute('hidden', 'true');
issueButton?.addEventListener('click', () => window.open(issueUrl, '_blank'));
submitView?.removeAttribute('hidden');
}
/**
* @description Validate form
* @param {{ reason: string | undefined | undefined, url: string | undefined }} params
* @returns {{ reason: string | undefined, url: string | undefined } | undefined}
*/
function validateForm(params) {
const { reason, url } = params;
let errors = undefined;
if (!reason || reason.length < 10 || reason.length > 1000) {
errors = {
...(errors ?? {}),
reason: browser.i18n.getMessage('reportDialog_reasonInputError'),
};
}
try {
new URL(url);
} catch {
errors = {
...(errors ?? {}),
url: browser.i18n.getMessage('reportDialog_urlInputError'),
};
}
return errors;
}
/**
* @description Listen to messages
*/
browser.runtime.onMessage.addListener((message) => {
const isPage = window === window.top;
switch (message.type) {
case 'HIDE_REPORT_DIALOG':
if (isPage) hideReportDialog();
break;
case 'SHOW_REPORT_DIALOG':
if (isPage) showReportDialog();
break;
default:
break;
}
});

View File

@ -62,8 +62,8 @@ async function handleAddClick() {
if (exclusionValue?.trim() && (domainRx.test(exclusionValue) || exclusionValue === 'localhost')) { if (exclusionValue?.trim() && (domainRx.test(exclusionValue) || exclusionValue === 'localhost')) {
const filterInputElement = document.getElementById('filter-input'); const filterInputElement = document.getElementById('filter-input');
const state = { enabled: false }; const state = { on: false };
await dispatch({ hostname: exclusionValue, state, type: 'SET_HOSTNAME_STATE' }); await dispatch({ hostname: exclusionValue, state, type: 'UPDATE_STORE' });
exclusionList = [...new Set([...exclusionList, exclusionValue])].sort(); exclusionList = [...new Set([...exclusionList, exclusionValue])].sort();
createList(); createList();
@ -80,8 +80,8 @@ async function handleClearClick() {
const filterInputElement = document.getElementById('filter-input'); const filterInputElement = document.getElementById('filter-input');
for (const exclusionValue of exclusionList) { for (const exclusionValue of exclusionList) {
const state = { enabled: true }; const state = { on: true };
await dispatch({ hostname: exclusionValue, state, type: 'SET_HOSTNAME_STATE' }); await dispatch({ hostname: exclusionValue, state, type: 'UPDATE_STORE' });
} }
exclusionList = []; exclusionList = [];
@ -128,9 +128,9 @@ async function handleDeleteClick(event) {
const filterInputElement = document.getElementById('filter-input'); const filterInputElement = document.getElementById('filter-input');
const { value } = event.currentTarget.parentElement.dataset; const { value } = event.currentTarget.parentElement.dataset;
const itemElement = document.querySelector(`[data-value="${value}"]`); const itemElement = document.querySelector(`[data-value="${value}"]`);
const state = { enabled: true }; const state = { on: true };
await dispatch({ hostname: value, state, type: 'SET_HOSTNAME_STATE' }); await dispatch({ hostname: value, state, type: 'UPDATE_STORE' });
exclusionList = exclusionList.filter((exclusionValue) => exclusionValue !== value); exclusionList = exclusionList.filter((exclusionValue) => exclusionValue !== value);
itemElement?.remove(); itemElement?.remove();
updateList(filterInputElement.value.trim()); updateList(filterInputElement.value.trim());
@ -172,8 +172,8 @@ function handleFileChange(event) {
const newExclusionList = event.currentTarget.result.split('\n').filter((x) => x.trim()); const newExclusionList = event.currentTarget.result.split('\n').filter((x) => x.trim());
for (const exclusionValue of newExclusionList) { for (const exclusionValue of newExclusionList) {
const state = { enabled: false }; const state = { on: false };
await dispatch({ hostname: exclusionValue, state, type: 'SET_HOSTNAME_STATE' }); await dispatch({ hostname: exclusionValue, state, type: 'UPDATE_STORE' });
} }
if (newExclusionList.length) { if (newExclusionList.length) {

View File

@ -1,3 +1,15 @@
/**
* @typedef {Object} ExtensionState
* @property {boolean} on
* @property {ExtensionIssue} [issue]
*/
/**
* @typedef {Object} PopupState
* @extends {ExtensionState}
* @property {number} [tabId]
*/
if (typeof browser === 'undefined') { if (typeof browser === 'undefined') {
browser = chrome; browser = chrome;
} }
@ -8,6 +20,11 @@ if (typeof browser === 'undefined') {
*/ */
const chromeUrl = 'https://chrome.google.com/webstore/detail/djcbfpkdhdkaflcigibkbpboflaplabg'; const chromeUrl = 'https://chrome.google.com/webstore/detail/djcbfpkdhdkaflcigibkbpboflaplabg';
/**
* @description Shortcut to send messages to background script
*/
const dispatch = browser.runtime.sendMessage;
/** /**
* @description Edge Add-ons link * @description Edge Add-ons link
* @type {string} * @type {string}
@ -46,10 +63,24 @@ const isEdge = navigator.userAgent.indexOf('Edg') !== -1;
const isFirefox = navigator.userAgent.indexOf('Firefox') !== -1; const isFirefox = navigator.userAgent.indexOf('Firefox') !== -1;
/** /**
* @description Extension state * @description Popup state
* @type {{ enabled: boolean, tabId: number | undefined }} * @type {PopupState}
*/ */
let state = { enabled: true, tabId: undefined }; let state = { on: true };
/**
* @description Close report form
* @returns {void}
*/
function handleCancelClick() {
const content = document.getElementsByClassName('content')[0];
const report = document.getElementsByClassName('report')[0];
if (content instanceof HTMLElement && report instanceof HTMLElement) {
content.style.removeProperty('display');
report.style.display = 'none';
}
}
/** /**
* @async * @async
@ -57,15 +88,46 @@ let state = { enabled: true, tabId: undefined };
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async function handleContentLoaded() { async function handleContentLoaded() {
const tab = await browser.runtime.sendMessage({ type: 'GET_TAB' }); const tab = await dispatch({ type: 'GET_TAB' });
const tabUrl = tab?.url ? new URL(tab.url) : undefined;
hostname = tab?.url hostname = tabUrl?.hostname.split('.').slice(-3).join('.').replace('www.', '');
? new URL(tab.url).hostname.split('.').slice(-3).join('.').replace('www.', '')
: undefined;
const next = await browser.runtime.sendMessage({ hostname, type: 'GET_HOSTNAME_STATE' }); const next = await dispatch({ hostname, type: 'GET_STATE' });
state = { ...(next ?? state), tabId: tab?.id }; state = { ...(next ?? state), tabId: tab?.id };
if (state.issue?.url) {
const issueBanner = document.getElementById('issue-banner');
issueBanner.removeAttribute('aria-hidden');
const issueBannerText = document.getElementById('issue-banner-text');
if (state.issue.flags.includes('wontfix'))
issueBannerText.innerText = browser.i18n.getMessage('popup_bannerIssueWontFix');
else issueBannerText.innerText = browser.i18n.getMessage('popup_bannerIssueOpen');
const issueBannerUrl = document.getElementById('issue-banner-url');
issueBannerUrl.setAttribute('href', state.issue.url);
} else {
const cancelButtonElement = document.getElementsByClassName('report-cancel-button')[0];
cancelButtonElement?.addEventListener('click', handleCancelClick);
const reasonInputElement = document.getElementById('report-input-reason');
reasonInputElement?.addEventListener('input', handleInputChange);
reasonInputElement?.addEventListener('keydown', handleInputKeyDown);
const reportButtonElement = document.getElementById('report-button');
reportButtonElement?.addEventListener('click', handleReportClick);
reportButtonElement?.removeAttribute('disabled');
const urlInputElement = document.getElementById('report-input-url');
urlInputElement?.addEventListener('input', handleInputChange);
urlInputElement?.addEventListener('keydown', handleInputKeyDown);
if (tabUrl) urlInputElement?.setAttribute('value', `${tabUrl.origin}${tabUrl.pathname}`);
const submitButtonElement = document.getElementsByClassName('report-submit-button')[0];
submitButtonElement?.addEventListener('click', handleSubmitButtonClick);
}
const hostTextElement = document.getElementById('host'); const hostTextElement = document.getElementById('host');
hostTextElement.innerText = hostname ?? 'unknown'; hostTextElement.innerText = hostname ?? 'unknown';
@ -83,7 +145,7 @@ async function handleContentLoaded() {
const powerButtonElement = document.getElementById('power-option'); const powerButtonElement = document.getElementById('power-option');
powerButtonElement?.addEventListener('click', handlePowerToggle); powerButtonElement?.addEventListener('click', handlePowerToggle);
if (state.enabled) powerButtonElement?.setAttribute('data-value', 'on'); if (state.on) powerButtonElement?.setAttribute('data-value', 'on');
else powerButtonElement?.setAttribute('data-value', 'off'); else powerButtonElement?.setAttribute('data-value', 'off');
const rateButtonElement = document.getElementById('rate-option'); const rateButtonElement = document.getElementById('rate-option');
@ -93,10 +155,10 @@ async function handleContentLoaded() {
else if (isFirefox) rateButtonElement?.setAttribute('data-href', firefoxUrl); else if (isFirefox) rateButtonElement?.setAttribute('data-href', firefoxUrl);
const settingsButtonElement = document.getElementById('settings-button'); const settingsButtonElement = document.getElementById('settings-button');
settingsButtonElement.addEventListener('click', handleSettingsClick); settingsButtonElement?.addEventListener('click', handleSettingsClick);
translate(); translate();
updateDatabaseVersion(); await updateDatabaseVersion();
} }
/** /**
@ -116,12 +178,12 @@ async function handleDatabaseRefresh(event) {
target.setAttribute('data-refreshing', 'true'); target.setAttribute('data-refreshing', 'true');
target.setAttribute('aria-disabled', 'true'); target.setAttribute('aria-disabled', 'true');
await browser.runtime.sendMessage({ type: 'REFRESH_DATA' }); await dispatch({ type: 'REFRESH_DATA' });
checkIcon.style.setProperty('display', 'block'); checkIcon.style.setProperty('display', 'block');
spinnerIcon.style.setProperty('display', 'none'); spinnerIcon.style.setProperty('display', 'none');
target.removeAttribute('data-animation'); target.removeAttribute('data-animation');
target.removeAttribute('data-refreshing'); target.removeAttribute('data-refreshing');
updateDatabaseVersion(); await updateDatabaseVersion();
window.setTimeout(() => { window.setTimeout(() => {
checkIcon.style.setProperty('display', 'none'); checkIcon.style.setProperty('display', 'none');
@ -131,6 +193,25 @@ async function handleDatabaseRefresh(event) {
}, 5000); }, 5000);
} }
/**
* @description Input change handler
* @param {InputEvent} event
*/
function handleInputChange(event) {
event.currentTarget.removeAttribute('aria-invalid');
}
/**
* @description Input key down handler
* @param {KeyboardEvent} event
*/
function handleInputKeyDown(event) {
if (event.key === 'Enter') {
event.preventDefault();
event.currentTarget.blur();
}
}
/** /**
* @async * @async
* @description Open a new tab * @description Open a new tab
@ -146,17 +227,32 @@ async function handleLinkRedirect(event) {
} }
/** /**
* @async
* @description Disable or enable extension on current page * @description Disable or enable extension on current page
* @returns {void} * @returns {void}
*/ */
function handlePowerToggle() { async function handlePowerToggle() {
const next = { enabled: !state.enabled }; const next = { on: !state.on };
browser.runtime.sendMessage({ hostname, state: next, type: 'SET_HOSTNAME_STATE' }); await dispatch({ hostname, state: next, type: 'UPDATE_STORE' });
browser.tabs.reload(state.tabId, { bypassCache: true }); await browser.tabs.reload(state.tabId, { bypassCache: true });
window.close(); window.close();
} }
/**
* @description Show report form
* @returns {void}
*/
function handleReportClick() {
const content = document.getElementsByClassName('content')[0];
const report = document.getElementsByClassName('report')[0];
if (content instanceof HTMLElement && report instanceof HTMLElement) {
content.style.display = 'none';
report.style.removeProperty('display');
}
}
/** /**
* @async * @async
* @description Open options page * @description Open options page
@ -166,6 +262,76 @@ async function handleSettingsClick() {
await browser.runtime.openOptionsPage(); await browser.runtime.openOptionsPage();
} }
/**
* @async
* @description Report submit button click handler
* @param {MouseEvent} event
*/
async function handleSubmitButtonClick(event) {
event.preventDefault();
if (event.currentTarget.getAttribute('aria-disabled') === 'true') {
return;
}
event.currentTarget.setAttribute('aria-disabled', 'true');
const reasonInput = document.getElementById('report-input-reason');
const reasonText = reasonInput?.value.trim();
const urlInput = document.getElementById('report-input-url');
const urlText = urlInput?.value.trim();
const errors = validateForm({ reason: reasonText, url: urlText });
if (errors) {
if (errors.reason) {
reasonInput?.setAttribute('aria-invalid', 'true');
reasonInput?.setAttribute('aria-errormessage', 'report-input-reason-error');
}
if (errors.url) {
urlInput?.setAttribute('aria-invalid', 'true');
urlInput?.setAttribute('aria-errormessage', 'report-input-url-error');
}
event.currentTarget.setAttribute('aria-disabled', 'false');
return;
}
const issueButtons = document.getElementsByClassName('report-issue-button');
const formView = document.getElementsByClassName('report-form-view')[0];
const userAgent = window.navigator.userAgent;
const response = await dispatch({ userAgent, reason: reasonText, url: urlText, type: 'REPORT' });
const hostname = new URL(urlText).hostname.split('.').slice(-3).join('.').replace('www.', '');
const issue = { expiresIn: Date.now() + 8 * 60 * 60 * 1000, flags: ['bug'], url: response.data };
if (response.success) {
const successView = document.getElementsByClassName('report-submit-success-view')[0];
await dispatch({ hostname, state: { issue }, type: 'UPDATE_STORE' });
await dispatch({ hostname, type: 'ENABLE_ICON' });
formView?.setAttribute('hidden', 'true');
issueButtons[1]?.addEventListener('click', () => window.open(response.data, '_blank'));
successView?.removeAttribute('hidden');
return;
}
if (response.data) {
const errorView = document.getElementsByClassName('report-submit-error-view')[0];
if (response.errors?.some((error) => error.includes('wontfix'))) {
issue.flags.push('wontfix');
}
await dispatch({ hostname, state: { issue }, type: 'UPDATE_STORE' });
errorView?.removeAttribute('hidden');
formView?.setAttribute('hidden', 'true');
issueButtons[0]?.addEventListener('click', () => window.open(response.data, '_blank'));
return;
}
window.close();
}
/** /**
* @description Apply translations to tags with i18n data attribute * @description Apply translations to tags with i18n data attribute
* @returns {void} * @returns {void}
@ -193,13 +359,41 @@ function translate() {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async function updateDatabaseVersion() { async function updateDatabaseVersion() {
const data = await browser.runtime.sendMessage({ hostname, type: 'GET_DATA' }); const data = await dispatch({ hostname, type: 'GET_DATA' });
const databaseVersionElement = document.getElementById('database-version'); const databaseVersionElement = document.getElementById('database-version');
if (data.version) databaseVersionElement.innerText = data.version; if (data.version) databaseVersionElement.innerText = data.version;
else databaseVersionElement.style.setProperty('display', 'none'); else databaseVersionElement.style.setProperty('display', 'none');
} }
/**
* @description Validate form
* @param {{ reason: string | undefined | undefined, url: string | undefined }} params
* @returns {{ reason: string | undefined, url: string | undefined } | undefined}
*/
function validateForm(params) {
const { reason, url } = params;
let errors = undefined;
if (!reason || reason.length < 10 || reason.length > 1000) {
errors = {
...(errors ?? {}),
reason: browser.i18n.getMessage('report_reasonInputError'),
};
}
try {
new URL(url);
} catch {
errors = {
...(errors ?? {}),
url: browser.i18n.getMessage('report_urlInputError'),
};
}
return errors;
}
/** /**
* @description Listen to document ready * @description Listen to document ready
* @listens document#DOMContentLoaded * @listens document#DOMContentLoaded

View File

@ -1,276 +0,0 @@
:root {
--cookie-dialog-monster-color-error: #cc0000;
--cookie-dialog-monster-color-primary: #3dd9eb;
--cookie-dialog-monster-color-secondary: #34495e;
--cookie-dialog-monster-color-success: #5cb85c;
--cookie-dialog-monster-color-tertiary: #6b7280;
--cookie-dialog-monster-color-white: #ffffff;
}
#report-dialog {
background-color: var(--cookie-dialog-monster-color-white);
border: none;
border-radius: 4px;
box-sizing: border-box;
color: var(--cookie-dialog-monster-color-secondary);
font-size: 100%;
letter-spacing: normal;
margin: auto;
padding: 0px;
text-align: left;
width: 320px;
}
#report-dialog::backdrop {
background-color: rgba(0, 0, 0, 0.5);
}
#report-dialog * {
box-sizing: border-box;
}
#report-dialog div {
all: unset;
display: block;
box-sizing: border-box;
}
#report-dialog *::-moz-selection {
color: var(--cookie-dialog-monster-color-white);
background: var(--cookie-dialog-monster-color-tertiary);
}
#report-dialog *::selection {
color: var(--cookie-dialog-monster-color-white);
background: var(--cookie-dialog-monster-color-tertiary);
}
#report-dialog .report-dialog-body {
display: block;
font-size: 14px;
line-height: 1.2;
padding: 16px;
}
#report-dialog .report-dialog-body-text {
display: block;
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 14px;
line-height: 1.2;
margin: 0px;
padding: 0px;
}
#report-dialog .report-dialog-close-button {
align-items: center;
background-color: transparent;
border: none;
border-radius: 4px;
cursor: pointer;
display: inline-flex;
justify-content: center;
margin: 0px;
outline: none;
padding: 0px;
}
#report-dialog .report-dialog-close-button {
stroke: var(--cookie-dialog-monster-color-white);
}
#report-dialog .report-dialog-close-button:focus,
#report-dialog .report-dialog-close-button:hover > svg {
stroke: var(--cookie-dialog-monster-color-secondary);
}
#report-dialog .report-dialog-close-button:focus-visible {
box-shadow: initial;
transition: initial;
}
#report-dialog .report-dialog-close-button:focus,
#report-dialog .report-dialog-close-button:hover {
background-color: var(--cookie-dialog-monster-color-white);
}
#report-dialog .report-dialog-form {
display: grid;
gap: 10px;
}
#report-dialog .report-dialog-form-view {
display: flex;
flex-direction: column;
gap: 24px;
}
#report-dialog .report-dialog-form-view[hidden] {
display: none;
}
#report-dialog .report-dialog-header {
align-items: center;
background-color: var(--cookie-dialog-monster-color-secondary);
display: flex;
font-size: 16px;
height: 54px;
justify-content: space-between;
line-height: 1.2;
padding: 16px;
}
#report-dialog .report-dialog-header-title {
color: var(--cookie-dialog-monster-color-white);
font-family: Inter, Arial, Helvetica, sans-serif;
font-weight: 500;
}
#report-dialog .report-dialog-input {
all: unset;
border: 1px solid var(--cookie-dialog-monster-color-tertiary);
border-radius: 4px;
color: var(--cookie-dialog-monster-color-secondary);
cursor: text;
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 14px;
line-height: 1;
outline: none;
padding: 12px 8px;
}
#report-dialog .report-dialog-input:hover {
border-color: var(--cookie-dialog-monster-color-secondary);
}
#report-dialog .report-dialog-input:focus {
border-color: var(--cookie-dialog-monster-color-primary);
}
#report-dialog .report-dialog-input:focus-visible {
box-shadow: initial;
transition: initial;
}
#report-dialog .report-dialog-input::-webkit-scrollbar {
display: none;
}
#report-dialog .report-dialog-input[aria-invalid='true'] {
border-color: var(--cookie-dialog-monster-color-error);
}
#report-dialog .report-dialog-input[aria-invalid='true'] + .report-dialog-input-error {
visibility: visible;
}
#report-dialog .report-dialog-input[aria-multiline='false'] {
-ms-overflow-style: none;
display: flex;
height: 40px;
overflow-x: auto;
scrollbar-width: none;
text-wrap: nowrap;
}
#report-dialog .report-dialog-input[aria-multiline='true'] {
-ms-overflow-style: none;
height: 120px;
overflow-y: auto;
scrollbar-width: none;
}
#report-dialog .report-dialog-input-error {
color: var(--cookie-dialog-monster-color-error);
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 10px;
line-height: 1.2;
visibility: hidden;
}
#report-dialog .report-dialog-input-group {
display: grid;
gap: 4px;
}
#report-dialog .report-dialog-input-label {
color: var(--cookie-dialog-monster-color-secondary);
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 12px;
line-height: 1.2;
}
#report-dialog .report-dialog-input-label-required {
color: var(--cookie-dialog-monster-color-error);
}
#report-dialog .report-dialog-issue-button,
#report-dialog .report-dialog-submit-button {
align-items: center;
background-color: var(--cookie-dialog-monster-color-secondary);
border: 1px solid var(--cookie-dialog-monster-color-secondary);
border-radius: 4px;
color: var(--cookie-dialog-monster-color-white);
cursor: pointer;
display: flex;
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 14px;
height: 42px;
justify-content: center;
line-height: 1.2;
outline: none;
padding: 8px 16px;
text-align: center;
width: 100%;
}
#report-dialog .report-dialog-issue-button:focus,
#report-dialog .report-dialog-issue-button:hover,
#report-dialog .report-dialog-submit-button:focus,
#report-dialog .report-dialog-submit-button:hover {
background-color: var(--cookie-dialog-monster-color-white);
color: var(--cookie-dialog-monster-color-secondary);
}
#report-dialog .report-dialog-issue-button:focus-visible,
#report-dialog .report-dialog-submit-button:focus-visible {
box-shadow: initial;
transition: initial;
}
#report-dialog .report-dialog-issue-button[aria-disabled='true'],
#report-dialog .report-dialog-submit-button[aria-disabled='true'] {
background-color: var(--cookie-dialog-monster-color-tertiary);
border: 1px solid var(--cookie-dialog-monster-color-tertiary);
color: var(--cookie-dialog-monster-color-white);
cursor: not-allowed;
}
#report-dialog .report-dialog-submit-extra-text {
font-family: inherit;
font-size: 14px;
line-height: 1.2;
margin: 0px;
text-align: justify;
}
#report-dialog .report-dialog-submit-text {
font-family: inherit;
font-size: 18px;
line-height: 1.2;
margin: 0px;
text-align: center;
}
#report-dialog .report-dialog-submit-view {
align-items: center;
display: flex;
flex-direction: column;
font-family: Inter, Arial, Helvetica, sans-serif;
gap: 24px;
justify-content: center;
margin-top: 16px;
}
#report-dialog .report-dialog-submit-view[hidden] {
display: none;
}

View File

@ -40,6 +40,12 @@ button[data-variant='large'] {
padding: 8px; padding: 8px;
} }
@media only screen and (max-device-width: 768px) {
button[data-variant='large'] {
justify-content: flex-end;
}
}
button:focus, button:focus,
button:hover { button:hover {
background-color: var(--color-secondary); background-color: var(--color-secondary);
@ -104,11 +110,18 @@ main {
.button-group { .button-group {
display: flex; display: flex;
justify-content: flex-end;
gap: 4px; gap: 4px;
justify-content: flex-end;
margin-bottom: 4px; margin-bottom: 4px;
} }
@media only screen and (max-device-width: 768px) {
.button-group {
display: grid;
grid-template-columns: repeat(2, minmax(0px, 1fr));
}
}
#exclusion-list { #exclusion-list {
font-size: 14px; font-size: 14px;
list-style: none; list-style: none;

View File

@ -11,12 +11,16 @@
body { body {
box-sizing: border-box; box-sizing: border-box;
color: var(--color-tertiary); color: var(--color-tertiary);
display: flex;
flex-direction: column;
font-family: Inter, Arial, Helvetica, sans-serif; font-family: Inter, Arial, Helvetica, sans-serif;
width: 320px; width: 320px;
} }
@media only screen and (max-device-width: 768px) {
body {
width: auto;
}
}
body * { body * {
box-sizing: border-box; box-sizing: border-box;
} }
@ -32,16 +36,22 @@ button {
outline: none; outline: none;
padding: 2px; padding: 2px;
transition: 0.4s; transition: 0.4s;
}
button:focus, &:focus:not(:disabled),
button:hover { &:hover:not(:disabled) {
background-color: var(--color-white); background-color: var(--color-white);
color: var(--color-secondary); color: var(--color-secondary);
}
&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
} }
footer { footer {
background-color: var(--color-secondary); background-color: var(--color-secondary);
flex-shrink: 0;
font-size: 12px; font-size: 12px;
height: 4px; height: 4px;
margin-top: auto; margin-top: auto;
@ -53,13 +63,49 @@ header {
background-color: var(--color-secondary); background-color: var(--color-secondary);
color: var(--color-white); color: var(--color-white);
display: flex; display: flex;
flex-shrink: 0;
font-size: 16px !important; font-size: 16px !important;
height: 48px; height: 48px;
justify-content: space-between; justify-content: space-between;
padding: 0 16px; padding: 0 16px;
& .header-actions {
display: flex;
gap: 8px;
& #report-button:focus:not(:disabled) > svg,
& #report-button:hover:not(:disabled) > svg {
color: var(--color-error);
}
}
} }
main { @media only screen and (max-device-width: 768px) {
main {
margin: 0 auto;
max-width: 320px;
width: 100%;
}
}
main > .banner {
background-color: #f39c12;
color: #c0392b;
margin: 0px;
padding: 16px;
&[aria-hidden='true'] {
display: none;
}
& #issue-banner-url {
color: inherit;
display: inline-block;
vertical-align: middle;
}
}
main > .content {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 16px; gap: 16px;
@ -142,6 +188,208 @@ popup-data-container {
text-align: center; text-align: center;
} }
.report {
font-family: inherit;
font-size: 14px;
line-height: 1.2;
padding: 16px;
& .report-buttons {
margin-top: auto;
}
& .report-form {
display: grid;
gap: 10px;
}
& .report-form-view {
display: flex;
flex-direction: column;
gap: 16px;
}
& .report-form-view[hidden] {
display: none;
}
& .report-input {
all: unset;
border: 1px solid var(--color-tertiary);
border-radius: 4px;
color: var(--color-secondary);
cursor: text;
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 14px;
line-height: 1;
outline: none;
padding: 12px 8px;
}
& .report-input:hover {
border-color: var(--color-secondary);
}
& .report-input:focus {
border-color: var(--color-primary);
}
& .report-input:focus-visible {
box-shadow: initial;
transition: initial;
}
& .report-input::-webkit-scrollbar {
display: none;
}
& .report-input[aria-invalid='true'] {
border-color: var(--color-error);
}
& .report-input[aria-invalid='true'] + .report-input-error {
display: block;
}
& .report-input[aria-multiline='false'] {
-ms-overflow-style: none;
display: flex;
height: 40px;
overflow-x: auto;
scrollbar-width: none;
text-wrap: nowrap;
}
& .report-input[aria-multiline='true'] {
-ms-overflow-style: none;
height: 120px;
overflow-y: auto;
scrollbar-width: none;
}
& .report-input-error {
color: var(--color-error);
display: none;
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 10px;
line-height: 1.2;
}
& .report-input-group {
display: grid;
gap: 4px;
}
& .report-input-label {
color: var(--color-secondary);
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 12px;
line-height: 1.2;
}
& .report-input-label-required {
color: var(--color-error);
}
& .report-cancel-button {
align-items: center;
background-color: var(--color-white);
color: var(--color-secondary);
cursor: pointer;
display: flex;
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 14px;
justify-content: center;
line-height: 1.2;
margin-left: auto;
margin-right: auto;
margin-top: 16px;
outline: none;
padding: 0px;
text-align: center;
}
& .report-cancel-button:focus,
& .report-cancel-button:hover {
color: var(--color-error);
}
& .report-issue-button,
& .report-submit-button {
align-items: center;
background-color: var(--color-secondary);
border: 1px solid var(--color-secondary);
border-radius: 4px;
color: var(--color-white);
cursor: pointer;
display: flex;
font-family: Inter, Arial, Helvetica, sans-serif;
font-size: 14px;
height: 42px;
justify-content: center;
line-height: 1.2;
margin-top: 8px;
outline: none;
padding: 8px 16px;
text-align: center;
width: 100%;
}
& .report-issue-button:focus,
& .report-issue-button:hover,
& .report-submit-button:focus,
& .report-submit-button:hover {
background-color: var(--color-white);
color: var(--color-secondary);
}
& .report-issue-button:focus-visible,
& .report-submit-button:focus-visible {
box-shadow: initial;
transition: initial;
}
& .report-issue-button[aria-disabled='true'],
& .report-submit-button[aria-disabled='true'] {
background-color: var(--color-tertiary);
border: 1px solid var(--color-tertiary);
color: var(--color-white);
cursor: not-allowed;
}
& .report-submit-extra-text {
font-family: inherit;
font-size: 14px;
line-height: 1.2;
margin: 0px;
text-align: justify;
}
& .report-submit-text {
font-family: inherit;
font-size: 18px;
line-height: 1.2;
margin: 0px;
text-align: center;
}
& .report-submit-error-view,
& .report-submit-success-view {
align-items: center;
display: flex;
flex-direction: column;
font-family: Inter, Arial, Helvetica, sans-serif;
gap: 24px;
justify-content: center;
margin-top: 16px;
}
& .report-submit-error-view[hidden],
& .report-submit-success-view[hidden] {
display: none;
}
}
strong { strong {
font-weight: bold; font-weight: bold;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -35,6 +35,6 @@
} }
.image { .image {
@apply self-center max-w-sm md:self-start rounded-lg shadow-2xl shrink-0 w-full; @apply max-w-sm rounded-lg shadow-2xl shrink-0 w-full;
} }
} }

View File

@ -40,6 +40,48 @@
</head> </head>
<body> <body>
<header> <header>
<div class="bg-gray-300 text-secondary" role="banner">
<div class="max-w-5xl mx-auto p-4 text-justify" id="banner-content-preview">
<p class="font-semibold">AN IMPORTANT UPDATE</p>
<p class="mt-2">
On the morning of October 11, 2024, GitHub unexpectedly hid our repository without any
prior notification. This sudden action immediately disrupted all of our API
services...&nbsp;
<span class="font-bold" id="banner-button" role="button" tabindex="0"> Read more </span>
</p>
</div>
<div class="hidden max-w-5xl mx-auto p-4 text-justify" id="banner-content-full">
<p class="font-semibold">AN IMPORTANT UPDATE</p>
<p class="mt-2">
On the morning of October 11, 2024, GitHub unexpectedly hid our repository without any
prior notification. This sudden action immediately disrupted all of our API services, as
they relied on files from the repository that were no longer accessible. Our team
reached out to GitHub support to understand the situation, but we have not yet received
any response. Given the critical impact on our services and the lack of communication
from GitHub, we decided to migrate the entire repository to an alternative platform to
ensure continuity and reliability.
</p>
<p class="mt-2">
We initially migrated the repository, releases, and open issues (excluding discussions)
to GitLab. However, during the migration of issues, GitLab's own spam detection
mechanism mistakenly identified its bot activity as spam, leading to our issues being
hidden. Despite reaching out to GitLab support, we have not yet received a resolution
for this incident. Faced with these ongoing platform limitations and communication
delays, we have opted to move forward with self-hosting our own Git system using Gitea
to ensure full control over our repository and services.
</p>
<p class="mt-2">
We will no longer support platforms that overlook the contributions of our users and the
significant work invested over the last years. Once our GitHub account is reinstated, we
will set up a redirect to guide users to our new, self-hosted repository.
</p>
<p class="mt-2">
Thank you to our community for your patience. Your contributions remain vital to this
project, and we are committed to ensuring its stability and growth in a more secure
environment.
</p>
</div>
</div>
<nav class="bg-secondary text-white"> <nav class="bg-secondary text-white">
<div class="flex items-center max-w-5xl mx-auto p-4"> <div class="flex items-center max-w-5xl mx-auto p-4">
<svg <svg
@ -84,35 +126,41 @@
<p class="font-medium">Cookie Dialog Monster</p> <p class="font-medium">Cookie Dialog Monster</p>
<div class="ml-auto"> <div class="ml-auto">
<div class="flex gap-4 text-white"> <div class="flex gap-4 text-white">
<a class="contents" href="mailto:hello@wanhose.dev" title="Email"> <a class="inline-flex" href="mailto:hello@wanhose.dev" title="Email">
<svg <svg
xmlns="http://www.w3.org/2000/svg" class="h-6 shrink-0 w-6"
class="h-6 w-6" fill="none"
viewBox="0 0 20 20" stroke-linecap="round"
fill="currentColor" stroke-linejoin="round"
stroke-width="2"
stroke="currentColor"
viewBox="0 0 24 24"
> >
<path <circle cx="12" cy="12" r="4"></circle>
fill-rule="evenodd" <path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.92 7.94"></path>
d="M14.243 5.757a6 6 0 10-.986 9.284 1 1 0 111.087 1.678A8 8 0 1118 10a3 3 0 01-4.8 2.401A4 4 0 1114 10a1 1 0 102 0c0-1.537-.586-3.07-1.757-4.243zM12 10a2 2 0 10-4 0 2 2 0 004 0z"
clip-rule="evenodd"
/>
</svg> </svg>
</a> </a>
<a <a
class="contents" class="inline-flex"
href="https://github.com/wanhose/cookie-dialog-monster" href="https://git.wanhose.dev/wanhose/cookie-dialog-monster"
target="_blank" target="_blank"
title="GitHub" title="Gitea"
> >
<svg <svg
class="h-6 w-6" class="h-6 shrink-0 w-6"
xmlns="http://www.w3.org/2000/svg" fill="none"
height="24"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
stroke="currentColor"
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="currentColor" width="24"
> >
<path <circle cx="18" cy="18" r="3"></circle>
d="M10.9,2.1c-4.6,0.5-8.3,4.2-8.8,8.7c-0.5,4.7,2.2,8.9,6.3,10.5C8.7,21.4,9,21.2,9,20.8v-1.6c0,0-0.4,0.1-0.9,0.1 c-1.4,0-2-1.2-2.1-1.9c-0.1-0.4-0.3-0.7-0.6-1C5.1,16.3,5,16.3,5,16.2C5,16,5.3,16,5.4,16c0.6,0,1.1,0.7,1.3,1c0.5,0.8,1.1,1,1.4,1 c0.4,0,0.7-0.1,0.9-0.2c0.1-0.7,0.4-1.4,1-1.8c-2.3-0.5-4-1.8-4-4c0-1.1,0.5-2.2,1.2-3C7.1,8.8,7,8.3,7,7.6C7,7.2,7,6.6,7.3,6 c0,0,1.4,0,2.8,1.3C10.6,7.1,11.3,7,12,7s1.4,0.1,2,0.3C15.3,6,16.8,6,16.8,6C17,6.6,17,7.2,17,7.6c0,0.8-0.1,1.2-0.2,1.4 c0.7,0.8,1.2,1.8,1.2,3c0,2.2-1.7,3.5-4,4c0.6,0.5,1,1.4,1,2.3v2.6c0,0.3,0.3,0.6,0.7,0.5c3.7-1.5,6.3-5.1,6.3-9.3 C22,6.1,16.9,1.4,10.9,2.1z" <circle cx="6" cy="6" r="3"></circle>
/> <path d="M13 6h3a2 2 0 0 1 2 2v7"></path>
<line x1="6" y1="9" x2="6" y2="21"></line>
</svg> </svg>
</a> </a>
</div> </div>
@ -168,8 +216,8 @@
</a> </a>
</div> </div>
</div> </div>
<div class="flex flex-col gap-8 md:flex-row md:gap-20 md:py-20 py-10"> <div class="flex flex-col gap-8 items-center md:flex-row md:gap-20 md:py-20 py-10">
<div class="md:mt-14"> <div>
<h2>A powerful popup to manage all from a single place</h2> <h2>A powerful popup to manage all from a single place</h2>
<p class="mt-8 text-gray-500 text-xl"> <p class="mt-8 text-gray-500 text-xl">
Disable the extension if you would like to accept cookies in a specific page, contribute Disable the extension if you would like to accept cookies in a specific page, contribute
@ -179,9 +227,9 @@
</div> </div>
<img alt="Extension Popup" class="image" src="/images/popup.png" /> <img alt="Extension Popup" class="image" src="/images/popup.png" />
</div> </div>
<div class="flex flex-col-reverse gap-8 md:flex-row md:gap-20 md:py-20 py-10"> <div class="flex flex-col-reverse gap-8 items-center md:flex-row md:gap-20 md:py-20 py-10">
<img alt="Extension Report Button" class="image" src="/images/report.png" /> <img alt="Extension Report Button" class="image" src="/images/report.png" />
<div class="md:mt-14"> <div>
<h2>We are not perfect but we try</h2> <h2>We are not perfect but we try</h2>
<p class="mt-8 text-gray-500 text-xl"> <p class="mt-8 text-gray-500 text-xl">
Report any page that works bad with our extension, just right-click anywhere on the page Report any page that works bad with our extension, just right-click anywhere on the page
@ -194,8 +242,23 @@
</p> </p>
</div> </div>
</div> </div>
<div class="flex flex-col gap-8 md:flex-row md:gap-20 md:py-20 py-10"> <div class="flex flex-col-reverse gap-8 items-center md:flex-row md:gap-20 md:py-20 py-10">
<div class="md:mt-14"> <div>
<h2>Real-time issue tracking</h2>
<p class="mt-8 text-gray-500 text-xl">
Track issues as they happen with real-time GitHub updates. Each report submitted is
instantly recorded on our GitHub issues page, giving our team visibility to work on it
immediately.
</p>
<p class="mt-4 text-gray-500 text-xl">
You can view the progress, add comments, and even watch the repository to stay informed.
</p>
</div>
<img alt="GitHub Issue Tracking" class="image" src="/images/issue.png" />
</div>
<div class="flex flex-col gap-8 items-center md:flex-row md:gap-20 md:py-20 py-10">
<img alt="Extension Options" class="image" src="/images/options.png" />
<div>
<h2>Manage your exclusions</h2> <h2>Manage your exclusions</h2>
<p class="mt-8 text-gray-500 text-xl"> <p class="mt-8 text-gray-500 text-xl">
Clear, import and export your preferences with one click. Users have full control over Clear, import and export your preferences with one click. Users have full control over
@ -206,7 +269,6 @@
implementations or where the extension may cause unintended side effects. implementations or where the extension may cause unintended side effects.
</p> </p>
</div> </div>
<img alt="Extension Options" class="image" src="/images/options.png" />
</div> </div>
<div class="md:py-20 py-10"> <div class="md:py-20 py-10">
<div class="md:text-center"> <div class="md:text-center">
@ -327,8 +389,8 @@
<h3 class="font-medium mt-4 text-lg text-secondary">Open source</h3> <h3 class="font-medium mt-4 text-lg text-secondary">Open source</h3>
<p class="mt-2 text-gray-500"> <p class="mt-2 text-gray-500">
Feel free to contribute to our Feel free to contribute to our
<a href="https://github.com/wanhose/cookie-dialog-monster/pulls" target="_blank"> <a href="https://git.wanhose.dev/wanhose/cookie-dialog-monster/pulls" target="_blank">
GitHub repository GitLab repository
</a> </a>
</p> </p>
</div> </div>
@ -478,7 +540,7 @@
version following version following
<a <a
class="underline" class="underline"
href="https://github.com/wanhose/cookie-dialog-monster/tree/main/packages/browser-extension#installation-for-mozilla-firefox-users" href="https://git.wanhose.dev/wanhose/cookie-dialog-monster/src/branch/main/packages/browser-extension#installation-for-mozilla-firefox-users"
id="firefox-guide-link" id="firefox-guide-link"
target="_blank" target="_blank"
> >
@ -492,7 +554,7 @@
the extension. We recommend you to follow the extension. We recommend you to follow
<a <a
class="underline" class="underline"
href="https://github.com/wanhose/cookie-dialog-monster/tree/main/packages/browser-extension#installation-for-advanced-and-non-listed-browser-users" href="https://git.wanhose.dev/wanhose/cookie-dialog-monster/src/branch/main/packages/browser-extension#installation-for-advanced-and-non-listed-browser-users"
target="_blank" target="_blank"
> >
this guide</a this guide</a
@ -504,19 +566,29 @@
<div class="max-w-5xl mx-auto"> <div class="max-w-5xl mx-auto">
<p class="text-center text-white text-sm"> <p class="text-center text-white text-sm">
An open source project built by you and An open source project built by you and
<a class="underline" href="https://github.com/wanhose" target="_blank"> wanhose</a> <a class="underline" href="https://git.wanhose.com/wanhose" target="_blank"> wanhose</a>
</p> </p>
</div> </div>
</footer> </footer>
<script> <script>
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const bannerButton = document.getElementById('banner-button');
const firefoxGuideLink = document.getElementById('firefox-guide-link'); const firefoxGuideLink = document.getElementById('firefox-guide-link');
const firefoxLink = document.getElementById('firefox-link'); const firefoxLink = document.getElementById('firefox-link');
const isMobile = /Android|Mobi/i.test(navigator.userAgent); const isMobile = /Android|Mobi/i.test(navigator.userAgent);
bannerButton.addEventListener('click', () => {
const bannerContentFull = document.getElementById('banner-content-full');
const bannerContentPreview = document.getElementById('banner-content-preview');
bannerButton.classList.add('hidden');
bannerContentFull.classList.remove('hidden');
bannerContentPreview.classList.add('hidden');
});
if (isMobile) { if (isMobile) {
firefoxGuideLink.href = firefoxGuideLink.href =
'https://github.com/wanhose/cookie-dialog-monster/tree/main/packages/browser-extension#installation-for-mozilla-firefox-mobile-users'; 'https://git.wanhose.dev/wanhose/cookie-dialog-monster/src/branch/main/packages/browser-extension#installation-for-mozilla-firefox-mobile-users';
firefoxLink.href = '/releases/latest-mozilla-mobile.xpi'; firefoxLink.href = '/releases/latest-mozilla-mobile.xpi';
} }
}); });

View File

@ -23,6 +23,7 @@ module.exports = {
'firefox-3': '#fee545', 'firefox-3': '#fee545',
primary: '#3dd9eb', primary: '#3dd9eb',
secondary: '#34495e', secondary: '#34495e',
tertiary: '#6b7280',
}, },
fontFamily: { fontFamily: {
sans: ['Inter', ...defaultTheme.fontFamily.sans], sans: ['Inter', ...defaultTheme.fontFamily.sans],

507
yarn.lock
View File

@ -498,316 +498,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@octokit/app@npm:^14.0.2":
version: 14.1.0
resolution: "@octokit/app@npm:14.1.0"
dependencies:
"@octokit/auth-app": "npm:^6.0.0"
"@octokit/auth-unauthenticated": "npm:^5.0.0"
"@octokit/core": "npm:^5.0.0"
"@octokit/oauth-app": "npm:^6.0.0"
"@octokit/plugin-paginate-rest": "npm:^9.0.0"
"@octokit/types": "npm:^12.0.0"
"@octokit/webhooks": "npm:^12.0.4"
checksum: 10c0/c115209f3c8dd05ec5acb5897f9e914177a07e335a7ffb985133d51302112be98122a1c3e3de05018885657ca4e5c9d42949eeb24b39d5881e80ed6411b81857
languageName: node
linkType: hard
"@octokit/auth-app@npm:^6.0.0":
version: 6.1.1
resolution: "@octokit/auth-app@npm:6.1.1"
dependencies:
"@octokit/auth-oauth-app": "npm:^7.1.0"
"@octokit/auth-oauth-user": "npm:^4.1.0"
"@octokit/request": "npm:^8.3.1"
"@octokit/request-error": "npm:^5.1.0"
"@octokit/types": "npm:^13.1.0"
deprecation: "npm:^2.3.1"
lru-cache: "npm:^10.0.0"
universal-github-app-jwt: "npm:^1.1.2"
universal-user-agent: "npm:^6.0.0"
checksum: 10c0/633fa49ef1d688f1db050fd359d224f5529f0df20e2a5f8f7e78d5f81f33d18cbcde735ea5222b0bcf058b5b93bff88d1dd6f614b9c9443bda5fa0921757cf4f
languageName: node
linkType: hard
"@octokit/auth-oauth-app@npm:^7.0.0, @octokit/auth-oauth-app@npm:^7.1.0":
version: 7.1.0
resolution: "@octokit/auth-oauth-app@npm:7.1.0"
dependencies:
"@octokit/auth-oauth-device": "npm:^6.1.0"
"@octokit/auth-oauth-user": "npm:^4.1.0"
"@octokit/request": "npm:^8.3.1"
"@octokit/types": "npm:^13.0.0"
"@types/btoa-lite": "npm:^1.0.0"
btoa-lite: "npm:^1.0.0"
universal-user-agent: "npm:^6.0.0"
checksum: 10c0/e23c5968426949181beea3ca89bb193885f4ec481b194a0c3bb252b02b1ff3f78908541f4ee6381563cfe6f23ed07e0c0eb33a842b1a6f85301a8266d4d46649
languageName: node
linkType: hard
"@octokit/auth-oauth-device@npm:^6.1.0":
version: 6.1.0
resolution: "@octokit/auth-oauth-device@npm:6.1.0"
dependencies:
"@octokit/oauth-methods": "npm:^4.1.0"
"@octokit/request": "npm:^8.3.1"
"@octokit/types": "npm:^13.0.0"
universal-user-agent: "npm:^6.0.0"
checksum: 10c0/74e17b76f55c8503dc1b4d95e4f52ee49900f7f720983d1725ad29361c9f413d22aa7621e8809ea644bb225686b3ee70f147a9e5944f3c1c1cccba55fa414422
languageName: node
linkType: hard
"@octokit/auth-oauth-user@npm:^4.0.0, @octokit/auth-oauth-user@npm:^4.1.0":
version: 4.1.0
resolution: "@octokit/auth-oauth-user@npm:4.1.0"
dependencies:
"@octokit/auth-oauth-device": "npm:^6.1.0"
"@octokit/oauth-methods": "npm:^4.1.0"
"@octokit/request": "npm:^8.3.1"
"@octokit/types": "npm:^13.0.0"
btoa-lite: "npm:^1.0.0"
universal-user-agent: "npm:^6.0.0"
checksum: 10c0/5d17d1e86ca89d4f2c440de4e5a648a1646818f0683a6230558279d71151a6b01f1228ccc4fc6e3ae24da92fa18810fac7b2bb6e019646f1f46be3928f522e7f
languageName: node
linkType: hard
"@octokit/auth-token@npm:^4.0.0":
version: 4.0.0
resolution: "@octokit/auth-token@npm:4.0.0"
checksum: 10c0/57acaa6c394c5abab2f74e8e1dcf4e7a16b236f713c77a54b8f08e2d14114de94b37946259e33ec2aab0566b26f724c2b71d2602352b59e541a9854897618f3c
languageName: node
linkType: hard
"@octokit/auth-unauthenticated@npm:^5.0.0":
version: 5.0.1
resolution: "@octokit/auth-unauthenticated@npm:5.0.1"
dependencies:
"@octokit/request-error": "npm:^5.0.0"
"@octokit/types": "npm:^12.0.0"
checksum: 10c0/c9cad429981a34021ec9f1fdc238c39eba36807683859a3bffb9dd66abf1ce016c9a2ff31fe09313458e59b37f8fa91522c0e34a1daecefdabcdf23a494fbcc2
languageName: node
linkType: hard
"@octokit/core@npm:^5.0.0":
version: 5.2.0
resolution: "@octokit/core@npm:5.2.0"
dependencies:
"@octokit/auth-token": "npm:^4.0.0"
"@octokit/graphql": "npm:^7.1.0"
"@octokit/request": "npm:^8.3.1"
"@octokit/request-error": "npm:^5.1.0"
"@octokit/types": "npm:^13.0.0"
before-after-hook: "npm:^2.2.0"
universal-user-agent: "npm:^6.0.0"
checksum: 10c0/9dc5cf55b335da382f340ef74c8009c06a1f7157b0530d3ff6cacf179887811352dcd405448e37849d73f17b28970b7817995be2260ce902dad52b91905542f0
languageName: node
linkType: hard
"@octokit/endpoint@npm:^9.0.1":
version: 9.0.5
resolution: "@octokit/endpoint@npm:9.0.5"
dependencies:
"@octokit/types": "npm:^13.1.0"
universal-user-agent: "npm:^6.0.0"
checksum: 10c0/e9bbb2111abe691c146075abb1b6f724a9b77fa8bfefdaaa82b8ebad6c8790e949f2367bb0b79800fef93ad72807513333e83e8ffba389bc85215535f63534d9
languageName: node
linkType: hard
"@octokit/graphql@npm:^7.1.0":
version: 7.1.0
resolution: "@octokit/graphql@npm:7.1.0"
dependencies:
"@octokit/request": "npm:^8.3.0"
"@octokit/types": "npm:^13.0.0"
universal-user-agent: "npm:^6.0.0"
checksum: 10c0/6d50a013d151f416fc837644e394e8b8872da7b17b181da119842ca569b0971e4dfacda55af6c329b51614e436945415dd5bd75eb3652055fdb754bbcd20d9d1
languageName: node
linkType: hard
"@octokit/oauth-app@npm:^6.0.0":
version: 6.1.0
resolution: "@octokit/oauth-app@npm:6.1.0"
dependencies:
"@octokit/auth-oauth-app": "npm:^7.0.0"
"@octokit/auth-oauth-user": "npm:^4.0.0"
"@octokit/auth-unauthenticated": "npm:^5.0.0"
"@octokit/core": "npm:^5.0.0"
"@octokit/oauth-authorization-url": "npm:^6.0.2"
"@octokit/oauth-methods": "npm:^4.0.0"
"@types/aws-lambda": "npm:^8.10.83"
universal-user-agent: "npm:^6.0.0"
checksum: 10c0/9d67ca196eabbb397c677e006d28148d6c5185f88d86e5444c219e43b95e0ecaee5d31807ea24aedb64a76d61c0a53acd8091613e15d10733f41960bd981463c
languageName: node
linkType: hard
"@octokit/oauth-authorization-url@npm:^6.0.2":
version: 6.0.2
resolution: "@octokit/oauth-authorization-url@npm:6.0.2"
checksum: 10c0/8c06e538b3e392f0fa68f3347078c32f92c03474eb214e4e82774513a54c164bac14c228f7dbd79d22a920df1a8b2e0765dd6ee45929bda0b77e5cf7f0d92c71
languageName: node
linkType: hard
"@octokit/oauth-methods@npm:^4.0.0, @octokit/oauth-methods@npm:^4.1.0":
version: 4.1.0
resolution: "@octokit/oauth-methods@npm:4.1.0"
dependencies:
"@octokit/oauth-authorization-url": "npm:^6.0.2"
"@octokit/request": "npm:^8.3.1"
"@octokit/request-error": "npm:^5.1.0"
"@octokit/types": "npm:^13.0.0"
btoa-lite: "npm:^1.0.0"
checksum: 10c0/3ab7ab41e82faebb662bfc4cc20756f008adb37b447386c29ddb09cbac5d1867b1b23f2f8dd268e06dca5ff1c874162e01d475f15634b42e6ab0a95471dcc365
languageName: node
linkType: hard
"@octokit/openapi-types@npm:^20.0.0":
version: 20.0.0
resolution: "@octokit/openapi-types@npm:20.0.0"
checksum: 10c0/5176dcc3b9d182ede3d446750cfa5cf31139624785a73fcf3511e3102a802b4d7cc45e999c27ed91d73fe8b7d718c8c406facb48688926921a71fe603b7db95d
languageName: node
linkType: hard
"@octokit/openapi-types@npm:^22.2.0":
version: 22.2.0
resolution: "@octokit/openapi-types@npm:22.2.0"
checksum: 10c0/a45bfc735611e836df0729f5922bbd5811d401052b972d1e3bc1278a2d2403e00f4552ce9d1f2793f77f167d212da559c5cb9f1b02c935114ad6d898779546ee
languageName: node
linkType: hard
"@octokit/plugin-paginate-graphql@npm:^4.0.0":
version: 4.0.1
resolution: "@octokit/plugin-paginate-graphql@npm:4.0.1"
peerDependencies:
"@octokit/core": ">=5"
checksum: 10c0/d559cdc2b5de107a7da5384b5241d1dfdc1038db1c4a70aca8a450c996315936844e0a1888216fb568c7a272bc6adf6667f897e0976b01e68085663b166cc533
languageName: node
linkType: hard
"@octokit/plugin-paginate-rest@npm:11.3.1":
version: 11.3.1
resolution: "@octokit/plugin-paginate-rest@npm:11.3.1"
dependencies:
"@octokit/types": "npm:^13.5.0"
peerDependencies:
"@octokit/core": 5
checksum: 10c0/72107ff7e459c49d1f13bbe44ac07b073497692eba28cb5ac6dbfa41e0ebc059ad7bccfa3dd45d3165348adcc2ede8ac159f8a9b637389b8e335af16aaa01469
languageName: node
linkType: hard
"@octokit/plugin-paginate-rest@npm:^9.0.0":
version: 9.2.1
resolution: "@octokit/plugin-paginate-rest@npm:9.2.1"
dependencies:
"@octokit/types": "npm:^12.6.0"
peerDependencies:
"@octokit/core": 5
checksum: 10c0/1dc55032a9e0c3e6440080a319975c9e4f189913fbc8870a48048d0c712473ea3d902ba247a37a46d45d502859b2728731a0d285107e4b0fa628d380f87163b4
languageName: node
linkType: hard
"@octokit/plugin-rest-endpoint-methods@npm:13.2.2":
version: 13.2.2
resolution: "@octokit/plugin-rest-endpoint-methods@npm:13.2.2"
dependencies:
"@octokit/types": "npm:^13.5.0"
peerDependencies:
"@octokit/core": ^5
checksum: 10c0/0f2b14b7a185b49908bcc01bcae9849aae2da46c88f500c143d230caa3cd35540839b916e88a4642c60a5499d33e7a37faf1aa42c5bab270cefc10f5d6202893
languageName: node
linkType: hard
"@octokit/plugin-retry@npm:^6.0.0":
version: 6.0.1
resolution: "@octokit/plugin-retry@npm:6.0.1"
dependencies:
"@octokit/request-error": "npm:^5.0.0"
"@octokit/types": "npm:^12.0.0"
bottleneck: "npm:^2.15.3"
peerDependencies:
"@octokit/core": ">=5"
checksum: 10c0/721b5a7949e3defdec5f1b451850ab924162fd2712c9ab59a2aaaad5b9ed6ee2a9447fe82ec1f91086cf23aaaceb14ff4e74de67ba3c63c5029e59c67b50979c
languageName: node
linkType: hard
"@octokit/plugin-throttling@npm:^8.0.0":
version: 8.2.0
resolution: "@octokit/plugin-throttling@npm:8.2.0"
dependencies:
"@octokit/types": "npm:^12.2.0"
bottleneck: "npm:^2.15.3"
peerDependencies:
"@octokit/core": ^5.0.0
checksum: 10c0/e65de9958ac5f29ba473bb969d25738f7466dad1b64e8181199c71438c06a6333ba655bd5194581a24199ca06fc9a6e752d0a4782b554ef603b0acffe9f8bfbd
languageName: node
linkType: hard
"@octokit/request-error@npm:^5.0.0, @octokit/request-error@npm:^5.1.0":
version: 5.1.0
resolution: "@octokit/request-error@npm:5.1.0"
dependencies:
"@octokit/types": "npm:^13.1.0"
deprecation: "npm:^2.0.0"
once: "npm:^1.4.0"
checksum: 10c0/61e688abce17dd020ea1e343470b9758f294bfe5432c5cb24bdb5b9b10f90ecec1ecaaa13b48df9288409e0da14252f6579a20f609af155bd61dc778718b7738
languageName: node
linkType: hard
"@octokit/request@npm:^8.3.0, @octokit/request@npm:^8.3.1":
version: 8.4.0
resolution: "@octokit/request@npm:8.4.0"
dependencies:
"@octokit/endpoint": "npm:^9.0.1"
"@octokit/request-error": "npm:^5.1.0"
"@octokit/types": "npm:^13.1.0"
universal-user-agent: "npm:^6.0.0"
checksum: 10c0/b857782ac2ff5387e9cc502759de73ea642c498c97d06ad2ecd8a395e4b9532d9f3bc3fc460e0d3d0e8f0d43c917a90c493e43766d37782b3979d3afffbf1b4b
languageName: node
linkType: hard
"@octokit/types@npm:^12.0.0, @octokit/types@npm:^12.2.0, @octokit/types@npm:^12.6.0":
version: 12.6.0
resolution: "@octokit/types@npm:12.6.0"
dependencies:
"@octokit/openapi-types": "npm:^20.0.0"
checksum: 10c0/0bea58bda46c93287f5a80a0e52bc60e7dc7136b8a38c3569d63d073fb9df4a56acdb9d9bdba9978f37c374a4a6e3e52886ef5b08cace048adb0012cacef942c
languageName: node
linkType: hard
"@octokit/types@npm:^13.0.0, @octokit/types@npm:^13.1.0, @octokit/types@npm:^13.5.0":
version: 13.5.0
resolution: "@octokit/types@npm:13.5.0"
dependencies:
"@octokit/openapi-types": "npm:^22.2.0"
checksum: 10c0/355ebc6776ce23feace1b1be0927cdda758790fda83068109c4f27b354dcd43d0447d4dc24e5eafdb596465469ea1baed23f3fd63adfec508cc375ccd1dcb0a3
languageName: node
linkType: hard
"@octokit/webhooks-methods@npm:^4.1.0":
version: 4.1.0
resolution: "@octokit/webhooks-methods@npm:4.1.0"
checksum: 10c0/153b344b4b20b48fdf89225f482bd9aa612998c28e43d032756d5a2ec7ebf117922fb6a95ee7c0a985cab6924fa4de3378c60e9ff41e384498b8cb7aad3771f2
languageName: node
linkType: hard
"@octokit/webhooks-types@npm:7.4.0":
version: 7.4.0
resolution: "@octokit/webhooks-types@npm:7.4.0"
checksum: 10c0/c2f06bdee4cb3f8f9e685a5a0289bd59673954b9bd25701480ba204ea23333f9bcc4a6f757f563ae5a1490f58eace8ebbc7aa8a1737c276ccc1cf5c3e2fe2ebe
languageName: node
linkType: hard
"@octokit/webhooks@npm:^12.0.4":
version: 12.2.0
resolution: "@octokit/webhooks@npm:12.2.0"
dependencies:
"@octokit/request-error": "npm:^5.0.0"
"@octokit/webhooks-methods": "npm:^4.1.0"
"@octokit/webhooks-types": "npm:7.4.0"
aggregate-error: "npm:^3.1.0"
checksum: 10c0/d22c55e99726c32d55b9faf8cde02274c3f6cd82992a5cedf795de401656cc716ff151b0dd6e4173d12dc335583944415613132a9dbf18ee6ffa0d550479a1c2
languageName: node
linkType: hard
"@pkgjs/parseargs@npm:^0.11.0": "@pkgjs/parseargs@npm:^0.11.0":
version: 0.11.0 version: 0.11.0
resolution: "@pkgjs/parseargs@npm:0.11.0" resolution: "@pkgjs/parseargs@npm:0.11.0"
@ -857,20 +547,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/aws-lambda@npm:^8.10.83":
version: 8.10.137
resolution: "@types/aws-lambda@npm:8.10.137"
checksum: 10c0/32272f8e9dfa88987cbc68e999554225d07282c3a884d769cdec7116fcec1f7e716914a9ac0d8afd79cf6c955b09e7bcfa6258dda6daa3f532c7eb97bf47bff1
languageName: node
linkType: hard
"@types/btoa-lite@npm:^1.0.0":
version: 1.0.2
resolution: "@types/btoa-lite@npm:1.0.2"
checksum: 10c0/daffbb47e4fe6493df70d83878b550adab48bab2f02b3591a59367af3ecebf34c971e070479ab68d83ca59cbeefbc61a50d9a7552f639dc908706183e0222bab
languageName: node
linkType: hard
"@types/conventional-commits-parser@npm:^5.0.0": "@types/conventional-commits-parser@npm:^5.0.0":
version: 5.0.0 version: 5.0.0
resolution: "@types/conventional-commits-parser@npm:5.0.0" resolution: "@types/conventional-commits-parser@npm:5.0.0"
@ -894,15 +570,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/jsonwebtoken@npm:^9.0.0":
version: 9.0.6
resolution: "@types/jsonwebtoken@npm:9.0.6"
dependencies:
"@types/node": "npm:*"
checksum: 10c0/9c29e3896e5fb6056e54d87514643e59e0cfb966ae25171a107776270195bba955f0373e98c8ed6450c145b18984f5df9cf0fcac360f382cec3c7c4d3510b202
languageName: node
linkType: hard
"@types/node-fetch@npm:2.6.11": "@types/node-fetch@npm:2.6.11":
version: 2.6.11 version: 2.6.11
resolution: "@types/node-fetch@npm:2.6.11" resolution: "@types/node-fetch@npm:2.6.11"
@ -1159,7 +826,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"aggregate-error@npm:^3.0.0, aggregate-error@npm:^3.1.0": "aggregate-error@npm:^3.0.0":
version: 3.1.0 version: 3.1.0
resolution: "aggregate-error@npm:3.1.0" resolution: "aggregate-error@npm:3.1.0"
dependencies: dependencies:
@ -1323,7 +990,6 @@ __metadata:
fastify: "npm:^4.26.2" fastify: "npm:^4.26.2"
node-fetch: "npm:^2.7.0" node-fetch: "npm:^2.7.0"
nodemon: "npm:^3.1.0" nodemon: "npm:^3.1.0"
octokit: "npm:^3.2.1"
rimraf: "npm:^5.0.5" rimraf: "npm:^5.0.5"
ts-node: "npm:^10.9.2" ts-node: "npm:^10.9.2"
tsconfig-paths: "npm:^4.2.0" tsconfig-paths: "npm:^4.2.0"
@ -1422,13 +1088,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"before-after-hook@npm:^2.2.0":
version: 2.2.3
resolution: "before-after-hook@npm:2.2.3"
checksum: 10c0/0488c4ae12df758ca9d49b3bb27b47fd559677965c52cae7b335784724fb8bf96c42b6e5ba7d7afcbc31facb0e294c3ef717cc41c5bc2f7bd9e76f8b90acd31c
languageName: node
linkType: hard
"binary-extensions@npm:^2.0.0": "binary-extensions@npm:^2.0.0":
version: 2.3.0 version: 2.3.0
resolution: "binary-extensions@npm:2.3.0" resolution: "binary-extensions@npm:2.3.0"
@ -1436,13 +1095,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"bottleneck@npm:^2.15.3":
version: 2.19.5
resolution: "bottleneck@npm:2.19.5"
checksum: 10c0/b0f72e45b2e0f56a21ba720183f16bef8e693452fb0495d997fa354e42904353a94bd8fd429868e6751bc85e54b6755190519eed5a0ae0a94a5185209ae7c6d0
languageName: node
linkType: hard
"boxen@npm:7.0.0": "boxen@npm:7.0.0":
version: 7.0.0 version: 7.0.0
resolution: "boxen@npm:7.0.0" resolution: "boxen@npm:7.0.0"
@ -1500,20 +1152,6 @@ __metadata:
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"btoa-lite@npm:^1.0.0":
version: 1.0.0
resolution: "btoa-lite@npm:1.0.0"
checksum: 10c0/7a4f0568ae3c915464650f98fde7901ae07b13a333a614515a0c86876b3528670fafece28dfef9745d971a613bb83341823afb0c20c6f318b384c1e364b9eb95
languageName: node
linkType: hard
"buffer-equal-constant-time@npm:1.0.1":
version: 1.0.1
resolution: "buffer-equal-constant-time@npm:1.0.1"
checksum: 10c0/fb2294e64d23c573d0dd1f1e7a466c3e978fe94a4e0f8183937912ca374619773bef8e2aceb854129d2efecbbc515bbd0cc78d2734a3e3031edb0888531bbc8e
languageName: node
linkType: hard
"buffer-from@npm:^1.0.0": "buffer-from@npm:^1.0.0":
version: 1.1.2 version: 1.1.2
resolution: "buffer-from@npm:1.1.2" resolution: "buffer-from@npm:1.1.2"
@ -2013,13 +1651,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"deprecation@npm:^2.0.0, deprecation@npm:^2.3.1":
version: 2.3.1
resolution: "deprecation@npm:2.3.1"
checksum: 10c0/23d688ba66b74d09b908c40a76179418acbeeb0bfdf218c8075c58ad8d0c315130cb91aa3dffb623aa3a411a3569ce56c6460de6c8d69071c17fe6dd2442f032
languageName: node
linkType: hard
"didyoumean@npm:^1.2.2": "didyoumean@npm:^1.2.2":
version: 1.2.2 version: 1.2.2
resolution: "didyoumean@npm:1.2.2" resolution: "didyoumean@npm:1.2.2"
@ -2085,15 +1716,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"ecdsa-sig-formatter@npm:1.0.11":
version: 1.0.11
resolution: "ecdsa-sig-formatter@npm:1.0.11"
dependencies:
safe-buffer: "npm:^5.0.1"
checksum: 10c0/ebfbf19d4b8be938f4dd4a83b8788385da353d63307ede301a9252f9f7f88672e76f2191618fd8edfc2f24679236064176fab0b78131b161ee73daa37125408c
languageName: node
linkType: hard
"emoji-regex@npm:^10.3.0": "emoji-regex@npm:^10.3.0":
version: 10.3.0 version: 10.3.0
resolution: "emoji-regex@npm:10.3.0" resolution: "emoji-regex@npm:10.3.0"
@ -3276,45 +2898,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"jsonwebtoken@npm:^9.0.2":
version: 9.0.2
resolution: "jsonwebtoken@npm:9.0.2"
dependencies:
jws: "npm:^3.2.2"
lodash.includes: "npm:^4.3.0"
lodash.isboolean: "npm:^3.0.3"
lodash.isinteger: "npm:^4.0.4"
lodash.isnumber: "npm:^3.0.3"
lodash.isplainobject: "npm:^4.0.6"
lodash.isstring: "npm:^4.0.1"
lodash.once: "npm:^4.0.0"
ms: "npm:^2.1.1"
semver: "npm:^7.5.4"
checksum: 10c0/d287a29814895e866db2e5a0209ce730cbc158441a0e5a70d5e940eb0d28ab7498c6bf45029cc8b479639bca94056e9a7f254e2cdb92a2f5750c7f358657a131
languageName: node
linkType: hard
"jwa@npm:^1.4.1":
version: 1.4.1
resolution: "jwa@npm:1.4.1"
dependencies:
buffer-equal-constant-time: "npm:1.0.1"
ecdsa-sig-formatter: "npm:1.0.11"
safe-buffer: "npm:^5.0.1"
checksum: 10c0/5c533540bf38702e73cf14765805a94027c66a0aa8b16bc3e89d8d905e61a4ce2791e87e21be97d1293a5ee9d4f3e5e47737e671768265ca4f25706db551d5e9
languageName: node
linkType: hard
"jws@npm:^3.2.2":
version: 3.2.2
resolution: "jws@npm:3.2.2"
dependencies:
jwa: "npm:^1.4.1"
safe-buffer: "npm:^5.0.1"
checksum: 10c0/e770704533d92df358adad7d1261fdecad4d7b66fa153ba80d047e03ca0f1f73007ce5ed3fbc04d2eba09ba6e7e6e645f351e08e5ab51614df1b0aa4f384dfff
languageName: node
linkType: hard
"keyv@npm:^4.5.3": "keyv@npm:^4.5.3":
version: 4.5.4 version: 4.5.4
resolution: "keyv@npm:4.5.4" resolution: "keyv@npm:4.5.4"
@ -3432,34 +3015,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"lodash.includes@npm:^4.3.0":
version: 4.3.0
resolution: "lodash.includes@npm:4.3.0"
checksum: 10c0/7ca498b9b75bf602d04e48c0adb842dfc7d90f77bcb2a91a2b2be34a723ad24bc1c8b3683ec6b2552a90f216c723cdea530ddb11a3320e08fa38265703978f4b
languageName: node
linkType: hard
"lodash.isboolean@npm:^3.0.3":
version: 3.0.3
resolution: "lodash.isboolean@npm:3.0.3"
checksum: 10c0/0aac604c1ef7e72f9a6b798e5b676606042401dd58e49f051df3cc1e3adb497b3d7695635a5cbec4ae5f66456b951fdabe7d6b387055f13267cde521f10ec7f7
languageName: node
linkType: hard
"lodash.isinteger@npm:^4.0.4":
version: 4.0.4
resolution: "lodash.isinteger@npm:4.0.4"
checksum: 10c0/4c3e023a2373bf65bf366d3b8605b97ec830bca702a926939bcaa53f8e02789b6a176e7f166b082f9365bfec4121bfeb52e86e9040cb8d450e64c858583f61b7
languageName: node
linkType: hard
"lodash.isnumber@npm:^3.0.3":
version: 3.0.3
resolution: "lodash.isnumber@npm:3.0.3"
checksum: 10c0/2d01530513a1ee4f72dd79528444db4e6360588adcb0e2ff663db2b3f642d4bb3d687051ae1115751ca9082db4fdef675160071226ca6bbf5f0c123dbf0aa12d
languageName: node
linkType: hard
"lodash.isplainobject@npm:^4.0.6": "lodash.isplainobject@npm:^4.0.6":
version: 4.0.6 version: 4.0.6
resolution: "lodash.isplainobject@npm:4.0.6" resolution: "lodash.isplainobject@npm:4.0.6"
@ -3467,13 +3022,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"lodash.isstring@npm:^4.0.1":
version: 4.0.1
resolution: "lodash.isstring@npm:4.0.1"
checksum: 10c0/09eaf980a283f9eef58ef95b30ec7fee61df4d6bf4aba3b5f096869cc58f24c9da17900febc8ffd67819b4e29de29793190e88dc96983db92d84c95fa85d1c92
languageName: node
linkType: hard
"lodash.kebabcase@npm:^4.1.1": "lodash.kebabcase@npm:^4.1.1":
version: 4.1.1 version: 4.1.1
resolution: "lodash.kebabcase@npm:4.1.1" resolution: "lodash.kebabcase@npm:4.1.1"
@ -3495,13 +3043,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"lodash.once@npm:^4.0.0":
version: 4.1.1
resolution: "lodash.once@npm:4.1.1"
checksum: 10c0/46a9a0a66c45dd812fcc016e46605d85ad599fe87d71a02f6736220554b52ffbe82e79a483ad40f52a8a95755b0d1077fba259da8bfb6694a7abbf4a48f1fc04
languageName: node
linkType: hard
"lodash.snakecase@npm:^4.1.1": "lodash.snakecase@npm:^4.1.1":
version: 4.1.1 version: 4.1.1
resolution: "lodash.snakecase@npm:4.1.1" resolution: "lodash.snakecase@npm:4.1.1"
@ -3552,7 +3093,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"lru-cache@npm:^10.0.0, lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0":
version: 10.2.2 version: 10.2.2
resolution: "lru-cache@npm:10.2.2" resolution: "lru-cache@npm:10.2.2"
checksum: 10c0/402d31094335851220d0b00985084288136136992979d0e015f0f1697e15d1c86052d7d53ae86b614e5b058425606efffc6969a31a091085d7a2b80a8a1e26d6 checksum: 10c0/402d31094335851220d0b00985084288136136992979d0e015f0f1697e15d1c86052d7d53ae86b614e5b058425606efffc6969a31a091085d7a2b80a8a1e26d6
@ -3833,13 +3374,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"ms@npm:^2.1.1":
version: 2.1.3
resolution: "ms@npm:2.1.3"
checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48
languageName: node
linkType: hard
"mz@npm:^2.7.0": "mz@npm:^2.7.0":
version: 2.7.0 version: 2.7.0
resolution: "mz@npm:2.7.0" resolution: "mz@npm:2.7.0"
@ -4006,24 +3540,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"octokit@npm:^3.2.1":
version: 3.2.1
resolution: "octokit@npm:3.2.1"
dependencies:
"@octokit/app": "npm:^14.0.2"
"@octokit/core": "npm:^5.0.0"
"@octokit/oauth-app": "npm:^6.0.0"
"@octokit/plugin-paginate-graphql": "npm:^4.0.0"
"@octokit/plugin-paginate-rest": "npm:11.3.1"
"@octokit/plugin-rest-endpoint-methods": "npm:13.2.2"
"@octokit/plugin-retry": "npm:^6.0.0"
"@octokit/plugin-throttling": "npm:^8.0.0"
"@octokit/request-error": "npm:^5.0.0"
"@octokit/types": "npm:^13.0.0"
checksum: 10c0/475575a30b351f2578f19f4d7c284c3928a0fd87f553a903436a6728d4d647ce93c8633e1f93cc4efe84ef9fcbfd9740f4198ec573323890084aa39ccf392a87
languageName: node
linkType: hard
"on-exit-leak-free@npm:^2.1.0": "on-exit-leak-free@npm:^2.1.0":
version: 2.1.2 version: 2.1.2
resolution: "on-exit-leak-free@npm:2.1.2" resolution: "on-exit-leak-free@npm:2.1.2"
@ -4038,7 +3554,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"once@npm:^1.3.0, once@npm:^1.4.0": "once@npm:^1.3.0":
version: 1.4.0 version: 1.4.0
resolution: "once@npm:1.4.0" resolution: "once@npm:1.4.0"
dependencies: dependencies:
@ -5473,23 +4989,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"universal-github-app-jwt@npm:^1.1.2":
version: 1.1.2
resolution: "universal-github-app-jwt@npm:1.1.2"
dependencies:
"@types/jsonwebtoken": "npm:^9.0.0"
jsonwebtoken: "npm:^9.0.2"
checksum: 10c0/061d2a52c25f0a09a5ae40167e6006ba89510df9934070996d8ca3019afd34f7f28fbb74a93d1627beb4209faf04ec9173f0dc9ff351ee2ec42ab76cff389a80
languageName: node
linkType: hard
"universal-user-agent@npm:^6.0.0":
version: 6.0.1
resolution: "universal-user-agent@npm:6.0.1"
checksum: 10c0/5c9c46ffe19a975e11e6443640ed4c9e0ce48fcc7203325757a8414ac49940ebb0f4667f2b1fa561489d1eb22cb2d05a0f7c82ec20c5cba42e58e188fb19b187
languageName: node
linkType: hard
"update-check@npm:1.5.4": "update-check@npm:1.5.4":
version: 1.5.4 version: 1.5.4
resolution: "update-check@npm:1.5.4" resolution: "update-check@npm:1.5.4"