From a3b1d7fb7cc7a1f9db5c7c6cfab3924c4e6d10b6 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 17 Feb 2024 11:01:21 -0600 Subject: [PATCH 001/121] Use a brew as a theme, three ways. This has been implemented three different ways to allow for comparison and discussion - /api/css/:id : This returns the style frontmatter of the referenced document as a text/css document. /api/theme/:id : This returns an object with the reference'd object's theme and style frontmatter. /api/csstheme/:id : This returns the stylye frontmatter of the referenced document as a text/css document and adds the theme as an @import ( if not using the legacy renderer ) --- server/homebrew.api.js | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 20e13ec71..a972895ae 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -205,6 +205,60 @@ const api = { res.status(200).send(saved); }, + getBrewTheme : async (req, res)=>{ + req.brew.text = req.brew.text.replaceAll('\r\n', '\n'); + if(req.brew.text.startsWith('```metadata')) { + const index = req.brew.text.indexOf('```\n\n'); + const metadataSection = req.brew.text.slice(12, index - 1); + const metadata = yaml.load(metadataSection); + Object.assign(req.brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); + req.brew.text = req.brew.text.slice(index + 5); + } + if(req.brew.text.startsWith('```css')) { + const index = req.brew.text.indexOf('```\n\n'); + req.brew.style = req.brew.text.slice(7, index - 1); + req.brew.text = req.brew.text.slice(index + 5); + } + return res.status(200).send(JSON.stringify({ + parent : req.brew.theme, + theme : req.brew.style + })); + }, + getBrewThemeAsCSS : async (req, res)=>{ + req.brew.text = req.brew.text.replaceAll('\r\n', '\n'); + if(req.brew.text.startsWith('```metadata')) { + const index = req.brew.text.indexOf('```\n\n'); + const metadataSection = req.brew.text.slice(12, index - 1); + const metadata = yaml.load(metadataSection); + Object.assign(req.brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); + req.brew.text = req.brew.text.slice(index + 5); + } + if(req.brew.text.startsWith('```css')) { + const index = req.brew.text.indexOf('```\n\n'); + req.brew.style = req.brew.text.slice(7, index - 1); + req.brew.text = req.brew.text.slice(index + 5); + } + res.setHeader('Content-Type', 'text/css'); + return res.status(200).send(req.brew.style); + }, + getBrewThemeWithCSS : async (req, res)=>{ + req.brew.text = req.brew.text.replaceAll('\r\n', '\n'); + if(req.brew.text.startsWith('```metadata')) { + const index = req.brew.text.indexOf('```\n\n'); + const metadataSection = req.brew.text.slice(12, index - 1); + const metadata = yaml.load(metadataSection); + Object.assign(req.brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); + req.brew.text = req.brew.text.slice(index + 5); + } + if(req.brew.text.startsWith('```css')) { + const index = req.brew.text.indexOf('```\n\n'); + req.brew.style = req.brew.text.slice(7, index - 1); + req.brew.text = req.brew.text.slice(index + 5); + } + res.setHeader('Content-Type', 'text/css'); + const parentThemeImport = `@import /themes/${req.brew.renderer}/${req.brew.theme}/styles.css\n\n`; + return res.status(200).send(`${req.brew.renderer != 'legacy' ? '' : parentThemeImport}${req.brew.style}`); + }, updateBrew : async (req, res)=>{ // Initialize brew from request and body, destructure query params, and set the initial value for the after-save method const brewFromClient = api.excludePropsFromUpdate(req.body); @@ -365,5 +419,9 @@ router.put('/api/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api router.put('/api/update/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); router.delete('/api/:id', asyncHandler(api.deleteBrew)); router.get('/api/remove/:id', asyncHandler(api.deleteBrew)); +router.get('/api/theme/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.getBrewTheme)); +router.get('/api/css/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.getBrewThemeAsCSS)); +router.get('/api/csstheme/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.getBrewThemeWithCSS)); + module.exports = api; From 8e48df5de16f02edeb3488f21db759409351101d Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 18 Feb 2024 12:45:14 -0600 Subject: [PATCH 002/121] Partial Code coverage for new endpoints --- server/homebrew.api.js | 14 +++++--- server/homebrew.api.spec.js | 72 +++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index a972895ae..49ab43893 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -219,10 +219,10 @@ const api = { req.brew.style = req.brew.text.slice(7, index - 1); req.brew.text = req.brew.text.slice(index + 5); } - return res.status(200).send(JSON.stringify({ + return res.status(200).send({ parent : req.brew.theme, theme : req.brew.style - })); + }); }, getBrewThemeAsCSS : async (req, res)=>{ req.brew.text = req.brew.text.replaceAll('\r\n', '\n'); @@ -238,7 +238,9 @@ const api = { req.brew.style = req.brew.text.slice(7, index - 1); req.brew.text = req.brew.text.slice(index + 5); } - res.setHeader('Content-Type', 'text/css'); + if(res.hasOwnProperty('set')) { + res.set('Content-Type', 'text/css'); + } return res.status(200).send(req.brew.style); }, getBrewThemeWithCSS : async (req, res)=>{ @@ -255,9 +257,11 @@ const api = { req.brew.style = req.brew.text.slice(7, index - 1); req.brew.text = req.brew.text.slice(index + 5); } - res.setHeader('Content-Type', 'text/css'); + if(res.hasOwnProperty('set')) { + res.set('Content-Type', 'text/css'); + } const parentThemeImport = `@import /themes/${req.brew.renderer}/${req.brew.theme}/styles.css\n\n`; - return res.status(200).send(`${req.brew.renderer != 'legacy' ? '' : parentThemeImport}${req.brew.style}`); + return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}${req.brew.style}`); }, updateBrew : async (req, res)=>{ // Initialize brew from request and body, destructure query params, and set the initial value for the after-save method diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 55a8c414f..cc8ae8044 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -569,6 +569,78 @@ brew`); }); }); + describe('getBrewTheme', ()=>{ + it('should collect parent theme and brew style', async ()=>{ + const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); + model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', style: 'I Have a style!' })); + const brewResults = { + authors : [], + createdAt : undefined, + description : '', + editId : undefined, + gDrive : false, + lang : 'en', + pageCount : 1, + published : false, + renderer : 'legacy', + shareId : undefined, + style : 'I Have a style!', + systems : [], + tags : [], + text : '', + theme : '5ePHB', + thumbnail : '', + title : 'test brew', + trashed : false, + updatedAt : undefined, + views : 0 + }; + const fn = api.getBrew('share', true); + const req = { brew: {} }; + const next = jest.fn(); + await fn(req, null, next); + + api.getBrewTheme(req, res); + const sent = res.send.mock.calls[0][0]; + expect(req.brew).toStrictEqual(brewResults); + expect(res.status).toHaveBeenCalledWith(200); + expect(sent.parent).toBe('5ePHB'); + expect(sent.theme).toBe('I Have a style!'); + }); + }); + + describe('getBrewAsThemeCSS', ()=>{ + it('should collect the brew style - returning as css', async ()=>{ + const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); + model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', style: 'I Have a style!' })); + const fn = api.getBrew('share', true); + const req = { brew: {} }; + const next = jest.fn(); + await fn(req, null, next); + + api.getBrewThemeAsCSS(req, res); + const sent = res.send.mock.calls[0][0]; + expect(sent).toBe('I Have a style!'); + expect(res.status).toHaveBeenCalledWith(200); + }); + }); + + describe('getBrewThemeWithCSS', ()=>{ + it('should collect parent theme and brew style - returning as css with parent imported.', async ()=>{ + const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); + model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', style: 'I Have a style!' })); + const fn = api.getBrew('share', true); + const req = { brew: {} }; + const next = jest.fn(); + await fn(req, null, next); + + api.getBrewThemeWithCSS(req, res); + const sent = res.send.mock.calls[0][0]; + expect(sent).toBe(`@import /themes/V3/5ePHB/styles.css\n\nI Have a style!`); + expect(res.status).toHaveBeenCalledWith(200); + }); + }); + describe('deleteBrew', ()=>{ it('should handle case where fetching the brew returns an error', async ()=>{ api.getBrew = jest.fn(()=>async ()=>{ throw { message: 'err', HBErrorCode: '02' }; }); From e2ef9b812245a8d4528089ecc0387153ac2e59ce Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 20 Feb 2024 16:44:17 -0600 Subject: [PATCH 003/121] Report Theme title with CSS This adds a comment/field ( depending on endpoint ) that reports the name of the Brew being used as a theming source. --- server/homebrew.api.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 49ab43893..e99b1b1d9 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -220,8 +220,9 @@ const api = { req.brew.text = req.brew.text.slice(index + 5); } return res.status(200).send({ - parent : req.brew.theme, - theme : req.brew.style + parent : req.brew.theme, + theme : req.brew.style, + themeName : req.brew.title }); }, getBrewThemeAsCSS : async (req, res)=>{ @@ -241,7 +242,7 @@ const api = { if(res.hasOwnProperty('set')) { res.set('Content-Type', 'text/css'); } - return res.status(200).send(req.brew.style); + return res.status(200).send(`// From Theme: ${req.brew.title}\n\n${req.brew.style}`); }, getBrewThemeWithCSS : async (req, res)=>{ req.brew.text = req.brew.text.replaceAll('\r\n', '\n'); @@ -260,7 +261,7 @@ const api = { if(res.hasOwnProperty('set')) { res.set('Content-Type', 'text/css'); } - const parentThemeImport = `@import /themes/${req.brew.renderer}/${req.brew.theme}/styles.css\n\n`; + const parentThemeImport = `// From Theme: ${req.brew.title}\n\n@import /themes/${req.brew.renderer}/${req.brew.theme}/styles.css\n\n`; return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}${req.brew.style}`); }, updateBrew : async (req, res)=>{ From c319d6bcfa45f9ee6b9fecbdba4d3e17fcbec695 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 20 Feb 2024 23:15:37 -0600 Subject: [PATCH 004/121] Consolidate and add theme parent walking This consolidates the style/theme endpoint to a singular method, adds interpretation of static themes, and allow parent theme recursion. I am not 100% sure this will order styles correctly. --- server/homebrew.api.js | 106 +++++++++++++++----------------- server/homebrew.api.spec.js | 118 ++++++++++++++++++------------------ 2 files changed, 108 insertions(+), 116 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index e99b1b1d9..f77c429e2 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -11,6 +11,19 @@ const { nanoid } = require('nanoid'); const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); +const themes = require('../themes/themes.json'); + +const isStaticTheme = (engine, themeName)=>{ + if(!themes.hasOwnProperty(engine)) { + return undefined; + } + if(themes[engine].hasOwnProperty(themeName)) { + return themes[engine][themeName].baseTheme; + } else { + return undefined; + } +}; + // const getTopBrews = (cb) => { // HomebrewModel.find().sort({ views: -1 }).limit(5).exec(function(err, brews) { // cb(brews); @@ -19,6 +32,22 @@ const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); const MAX_TITLE_LENGTH = 100; +const splitTextStyleAndMetadata = (brew)=>{ + brew.text = brew.text.replaceAll('\r\n', '\n'); + if(brew.text.startsWith('```metadata')) { + const index = brew.text.indexOf('```\n\n'); + const metadataSection = brew.text.slice(12, index - 1); + const metadata = yaml.load(metadataSection); + Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); + brew.text = brew.text.slice(index + 5); + } + if(brew.text.startsWith('```css')) { + const index = brew.text.indexOf('```\n\n'); + brew.style = brew.text.slice(7, index - 1); + brew.text = brew.text.slice(index + 5); + } +}; + const api = { homebrewApi : router, getId : (req)=>{ @@ -40,6 +69,7 @@ const api = { getBrew : (accessType, stubOnly = false)=>{ // Create middleware with the accessType passed in as part of the scope return async (req, res, next)=>{ + // Get relevant IDs for the brew const { id, googleId } = api.getId(req); @@ -205,65 +235,29 @@ const api = { res.status(200).send(saved); }, - getBrewTheme : async (req, res)=>{ - req.brew.text = req.brew.text.replaceAll('\r\n', '\n'); - if(req.brew.text.startsWith('```metadata')) { - const index = req.brew.text.indexOf('```\n\n'); - const metadataSection = req.brew.text.slice(12, index - 1); - const metadata = yaml.load(metadataSection); - Object.assign(req.brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); - req.brew.text = req.brew.text.slice(index + 5); - } - if(req.brew.text.startsWith('```css')) { - const index = req.brew.text.indexOf('```\n\n'); - req.brew.style = req.brew.text.slice(7, index - 1); - req.brew.text = req.brew.text.slice(index + 5); - } - return res.status(200).send({ - parent : req.brew.theme, - theme : req.brew.style, - themeName : req.brew.title - }); - }, - getBrewThemeAsCSS : async (req, res)=>{ - req.brew.text = req.brew.text.replaceAll('\r\n', '\n'); - if(req.brew.text.startsWith('```metadata')) { - const index = req.brew.text.indexOf('```\n\n'); - const metadataSection = req.brew.text.slice(12, index - 1); - const metadata = yaml.load(metadataSection); - Object.assign(req.brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); - req.brew.text = req.brew.text.slice(index + 5); - } - if(req.brew.text.startsWith('```css')) { - const index = req.brew.text.indexOf('```\n\n'); - req.brew.style = req.brew.text.slice(7, index - 1); - req.brew.text = req.brew.text.slice(index + 5); - } - if(res.hasOwnProperty('set')) { - res.set('Content-Type', 'text/css'); - } - return res.status(200).send(`// From Theme: ${req.brew.title}\n\n${req.brew.style}`); - }, getBrewThemeWithCSS : async (req, res)=>{ - req.brew.text = req.brew.text.replaceAll('\r\n', '\n'); - if(req.brew.text.startsWith('```metadata')) { - const index = req.brew.text.indexOf('```\n\n'); - const metadataSection = req.brew.text.slice(12, index - 1); - const metadata = yaml.load(metadataSection); - Object.assign(req.brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); - req.brew.text = req.brew.text.slice(index + 5); - } - if(req.brew.text.startsWith('```css')) { - const index = req.brew.text.indexOf('```\n\n'); - req.brew.style = req.brew.text.slice(7, index - 1); - req.brew.text = req.brew.text.slice(index + 5); - } + const brew = req.brew; + splitTextStyleAndMetadata(brew); if(res.hasOwnProperty('set')) { res.set('Content-Type', 'text/css'); } - const parentThemeImport = `// From Theme: ${req.brew.title}\n\n@import /themes/${req.brew.renderer}/${req.brew.theme}/styles.css\n\n`; + const staticTheme = `/api/css/${req.brew.renderer}/${req.brew.theme}/styles.css`; + const userTheme = `/api/css/${req.brew.theme.slice(1)}`; + const parentThemeImport = `// From Theme: ${req.brew.title}\n\n@import ${req.brew.theme[0] != '#' ? staticTheme : userTheme}\n\n`; return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}${req.brew.style}`); }, + getStaticTheme : async(req, res)=>{ + const themeParent = isStaticTheme(req.params.engine, req.params.id); + if(themeParent === undefined){ + res.status(404).send(`Invalid Theme - Engine: ${req.params.engine}, Name: ${req.params.id}`); + } else { + if(res.hasOwnProperty('set')) { + res.set('Content-Type', 'text/css'); + } + const parentTheme = themeParent ? `@import /api/css/${req.params.engine}/${themeParent}\n` : ''; + return res.status(200).send(`${parentTheme}@import /themes/${req.params.engine}/${req.params.id}\n`); + } + }, updateBrew : async (req, res)=>{ // Initialize brew from request and body, destructure query params, and set the initial value for the after-save method const brewFromClient = api.excludePropsFromUpdate(req.body); @@ -424,9 +418,7 @@ router.put('/api/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api router.put('/api/update/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); router.delete('/api/:id', asyncHandler(api.deleteBrew)); router.get('/api/remove/:id', asyncHandler(api.deleteBrew)); -router.get('/api/theme/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.getBrewTheme)); -router.get('/api/css/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.getBrewThemeAsCSS)); -router.get('/api/csstheme/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.getBrewThemeWithCSS)); - +router.get('/api/css/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.getBrewThemeWithCSS)); +router.get('/api/css/:engine/:id/', asyncHandler(api.getStaticTheme)); module.exports = api; diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index cc8ae8044..760e1ae75 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -569,64 +569,8 @@ brew`); }); }); - describe('getBrewTheme', ()=>{ - it('should collect parent theme and brew style', async ()=>{ - const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); - model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', style: 'I Have a style!' })); - const brewResults = { - authors : [], - createdAt : undefined, - description : '', - editId : undefined, - gDrive : false, - lang : 'en', - pageCount : 1, - published : false, - renderer : 'legacy', - shareId : undefined, - style : 'I Have a style!', - systems : [], - tags : [], - text : '', - theme : '5ePHB', - thumbnail : '', - title : 'test brew', - trashed : false, - updatedAt : undefined, - views : 0 - }; - const fn = api.getBrew('share', true); - const req = { brew: {} }; - const next = jest.fn(); - await fn(req, null, next); - - api.getBrewTheme(req, res); - const sent = res.send.mock.calls[0][0]; - expect(req.brew).toStrictEqual(brewResults); - expect(res.status).toHaveBeenCalledWith(200); - expect(sent.parent).toBe('5ePHB'); - expect(sent.theme).toBe('I Have a style!'); - }); - }); - - describe('getBrewAsThemeCSS', ()=>{ - it('should collect the brew style - returning as css', async ()=>{ - const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); - model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', style: 'I Have a style!' })); - const fn = api.getBrew('share', true); - const req = { brew: {} }; - const next = jest.fn(); - await fn(req, null, next); - - api.getBrewThemeAsCSS(req, res); - const sent = res.send.mock.calls[0][0]; - expect(sent).toBe('I Have a style!'); - expect(res.status).toHaveBeenCalledWith(200); - }); - }); - - describe('getBrewThemeWithCSS', ()=>{ - it('should collect parent theme and brew style - returning as css with parent imported.', async ()=>{ + describe('getBrewThemeWithStaticParent', ()=>{ + it('should collect parent theme and brew style - returning as css with static parent imported.', async ()=>{ const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', style: 'I Have a style!' })); const fn = api.getBrew('share', true); @@ -636,11 +580,67 @@ brew`); api.getBrewThemeWithCSS(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe(`@import /themes/V3/5ePHB/styles.css\n\nI Have a style!`); + expect(sent).toBe(`// From Theme: test brew\n\n@import /api/css/V3/5ePHB/styles.css\n\nI Have a style!`); expect(res.status).toHaveBeenCalledWith(200); }); }); + describe('getBrewThemeWithUserParent', ()=>{ + it('should collect parent theme and brew style - returning as css with user-theme parent imported.', async ()=>{ + const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); + model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', theme: '#IamATheme', style: 'I Have a style!' })); + const fn = api.getBrew('share', true); + const req = { brew: {} }; + const next = jest.fn(); + await fn(req, null, next); + + api.getBrewThemeWithCSS(req, res); + const sent = res.send.mock.calls[0][0]; + expect(sent).toBe(`// From Theme: test brew\n\n@import /api/css/IamATheme\n\nI Have a style!`); + expect(res.status).toHaveBeenCalledWith(200); + }); + }); + + describe('getStaticTheme', ()=>{ + it('should return an import of the theme without including a parent.', async ()=>{ + const req = { + params : { + engine : 'V3', + id : '5ePHB' + } + }; + api.getStaticTheme(req, res); + const sent = res.send.mock.calls[0][0]; + expect(sent).toBe('@import /themes/V3/5ePHB\n'); + expect(res.status).toHaveBeenCalledWith(200); + }); + it('should return an import of the theme including a parent.', async ()=>{ + const req = { + params : { + engine : 'V3', + id : '5eDMG' + } + }; + api.getStaticTheme(req, res); + const sent = res.send.mock.calls[0][0]; + expect(sent).toBe('@import /api/css/V3/5ePHB\n@import /themes/V3/5eDMG\n'); + expect(res.status).toHaveBeenCalledWith(200); + }); + it('should fail for an invalid static theme.', async()=>{ + const req = { + params : { + engine : 'V3', + id : '5eDMGGGG' + } + }; + api.getStaticTheme(req, res); + const sent = res.send.mock.calls[0][0]; + expect(sent).toBe('Invalid Theme - Engine: V3, Name: 5eDMGGGG'); + expect(res.status).toHaveBeenCalledWith(404); + }); + }); + + describe('deleteBrew', ()=>{ it('should handle case where fetching the brew returns an error', async ()=>{ api.getBrew = jest.fn(()=>async ()=>{ throw { message: 'err', HBErrorCode: '02' }; }); From ae2bb3a02857bba2ff0b74d55c19866e91908661 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 20 Feb 2024 23:26:09 -0600 Subject: [PATCH 005/121] Add missing style.css --- server/homebrew.api.js | 2 +- server/homebrew.api.spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index f77c429e2..36b885cb0 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -255,7 +255,7 @@ const api = { res.set('Content-Type', 'text/css'); } const parentTheme = themeParent ? `@import /api/css/${req.params.engine}/${themeParent}\n` : ''; - return res.status(200).send(`${parentTheme}@import /themes/${req.params.engine}/${req.params.id}\n`); + return res.status(200).send(`${parentTheme}@import /themes/${req.params.engine}/${req.params.id}/style.css\n`); } }, updateBrew : async (req, res)=>{ diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 760e1ae75..c82ce5227 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -611,7 +611,7 @@ brew`); }; api.getStaticTheme(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe('@import /themes/V3/5ePHB\n'); + expect(sent).toBe('@import /themes/V3/5ePHB/style.css\n'); expect(res.status).toHaveBeenCalledWith(200); }); it('should return an import of the theme including a parent.', async ()=>{ @@ -623,7 +623,7 @@ brew`); }; api.getStaticTheme(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe('@import /api/css/V3/5ePHB\n@import /themes/V3/5eDMG\n'); + expect(sent).toBe('@import /api/css/V3/5ePHB\n@import /themes/V3/5eDMG/style.css\n'); expect(res.status).toHaveBeenCalledWith(200); }); it('should fail for an invalid static theme.', async()=>{ From f60090e5fa866be8e5e5124f802c02e91185e942 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Thu, 22 Feb 2024 21:12:56 -0600 Subject: [PATCH 006/121] Update Theme Picker to use Brews tagged as a theme This updates the theme picker to include brews tagged as themes owned by the user. Some supporting functions were updated. User themes are loaded on /edit and added to the request. --- .../editor/metadataEditor/metadataEditor.jsx | 16 ++++++--- config/default.json | 1 + server/app.js | 33 ++++++++++++++++++- server/homebrew.model.js | 4 +-- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 074879b05..58c44ded9 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -8,6 +8,8 @@ const request = require('../../utils/request-middleware.js'); const Nav = require('naturalcrit/nav/nav.jsx'); const Combobox = require('client/components/combobox.jsx'); const StringArrayEditor = require('../stringArrayEditor/stringArrayEditor.jsx'); +const HomebrewModel = require('../../../../server/homebrew.model.js').model; + const Themes = require('themes/themes.json'); const validations = require('./validations.js'); @@ -192,20 +194,23 @@ const MetadataEditor = createClass({ renderThemeDropdown : function(){ if(!global.enable_themes) return; + const mergedThemes = { ...Themes, ...this.props.metadata.userThemes }; + const listThemes = (renderer)=>{ - return _.map(_.values(Themes[renderer]), (theme)=>{ - return
this.handleTheme(theme)} title={''}> - {`${theme.renderer} : ${theme.name}`} + return _.map(_.values(mergedThemes[renderer]), (theme)=>{ + const preview = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; + return
this.handleTheme(theme)} title={''}> + {`${renderer} : ${theme.name}`}
{`${theme.name}`} preview
- +
; }); }; - const currentTheme = Themes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme]; + const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme]; let dropdown; if(this.props.metadata.renderer == 'legacy') { @@ -223,6 +228,7 @@ const MetadataEditor = createClass({
{/*listThemes('Legacy')*/} {listThemes('V3')} + {listThemes('Brew')} ; } diff --git a/config/default.json b/config/default.json index 70c90593e..12b35e6cf 100644 --- a/config/default.json +++ b/config/default.json @@ -4,6 +4,7 @@ "secret" : "secret", "web_port" : 8000, "enable_v3" : true, + "enable_themes" : true, "local_environments" : ["docker", "local"], "publicUrl" : "https://homebrewery.naturalcrit.com" } diff --git a/server/app.js b/server/app.js index fc5d4a035..af842f2bf 100644 --- a/server/app.js +++ b/server/app.js @@ -42,6 +42,36 @@ const sanitizeBrew = (brew, accessType)=>{ return brew; }; +const getUsersBrewThemes = async (username)=>{ + const fields = [ + 'title', + 'tags', + 'editId', + 'thumbnail' + ]; + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] } }) //lean() converts results to JSObjects + .catch((error)=>{throw 'Can not find brews';}); + + const userThemes = { + Brew : { + + } + }; + + brews.forEach((brew)=>{ + userThemes.Brew[brew.editId] = { + name : brew.title, + renderer : 'V3', + baseTheme : false, + baseSnippets : false, + path : `#${brew.editId}`, + thumbnail : brew.thumbnail + }; + }); + + return userThemes; +}; + app.use('/', serveCompressedStaticAssets(`build`)); app.use(require('./middleware/content-negotiation.js')); app.use(require('body-parser').json({ limit: '25mb' })); @@ -278,7 +308,7 @@ app.get('/user/:username', async (req, res, next)=>{ }); //Edit Page -app.get('/edit/:id', asyncHandler(getBrew('edit')), (req, res, next)=>{ +app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; req.ogMeta = { ...defaultMetaTags, @@ -288,6 +318,7 @@ app.get('/edit/:id', asyncHandler(getBrew('edit')), (req, res, next)=>{ type : 'article' }; + req.brew.userThemes = await getUsersBrewThemes(req.account.username); sanitizeBrew(req.brew, 'edit'); splitTextStyleAndMetadata(req.brew); res.header('Cache-Control', 'no-cache, no-store'); //reload the latest saved brew when pressing back button, not the cached version before save. diff --git a/server/homebrew.model.js b/server/homebrew.model.js index 36c9aa192..c8db8fdcc 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -50,8 +50,8 @@ HomebrewSchema.statics.get = async function(query, fields=null){ return brew; }; -HomebrewSchema.statics.getByUser = async function(username, allowAccess=false, fields=null){ - const query = { authors: username, published: true }; +HomebrewSchema.statics.getByUser = async function(username, allowAccess=false, fields=null, filter=null){ + const query = { authors: username, published: true, ...filter }; if(allowAccess){ delete query.published; } From f9307986cd9f519848cbac62093b23b37b684d7d Mon Sep 17 00:00:00 2001 From: David Bolack Date: Thu, 22 Feb 2024 23:06:40 -0600 Subject: [PATCH 007/121] WIP @import statements are just not working. Uploaded for other eyes. --- client/homebrew/brewRenderer/brewRenderer.jsx | 17 ++++++++++++---- server/app.js | 8 +++++++- server/homebrew.api.js | 20 +++++++++---------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 9208a2b90..f2216c52b 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -176,10 +176,19 @@ const BrewRenderer = (props)=>{ document.dispatchEvent(new MouseEvent('click')); }; - const rendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; + let rendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; const themePath = props.theme ?? '5ePHB'; const baseThemePath = Themes[rendererPath][themePath].baseTheme; + // Override static theme values if a Brew theme. + + if(themePath[0] == '#') { + themePath.slice(1); + rendererPath = ''; + } else { + rendererPath += '/'; + } + return ( <> {/*render dummy page while iFrame is mounting.*/} @@ -206,11 +215,11 @@ const BrewRenderer = (props)=>{ - + {baseThemePath && - + } - + {/* Apply CSS from Style tab and render pages from Markdown tab */} {state.isMounted diff --git a/server/app.js b/server/app.js index af842f2bf..7d1eaf577 100644 --- a/server/app.js +++ b/server/app.js @@ -9,7 +9,7 @@ const yaml = require('js-yaml'); const app = express(); const config = require('./config.js'); -const { homebrewApi, getBrew } = require('./homebrew.api.js'); +const { homebrewApi, getBrew, getBrewThemeWithCSS, getStaticTheme} = require('./homebrew.api.js'); const GoogleActions = require('./googleActions.js'); const serveCompressedStaticAssets = require('./static-assets.mv.js'); const sanitizeFilename = require('sanitize-filename'); @@ -120,6 +120,12 @@ app.get('/robots.txt', (req, res)=>{ return res.sendFile(`robots.txt`, { root: process.cwd() }); }); +// Theme + +app.get('/css/:id', asyncHandler(getBrew('edit', true)), asyncHandler(getBrewThemeWithCSS)); +app.get('/css/:engine/:id/', asyncHandler(getStaticTheme)); + + //Home page app.get('/', (req, res, next)=>{ req.brew = { diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 36b885cb0..f01c7320c 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -238,12 +238,12 @@ const api = { getBrewThemeWithCSS : async (req, res)=>{ const brew = req.brew; splitTextStyleAndMetadata(brew); - if(res.hasOwnProperty('set')) { - res.set('Content-Type', 'text/css'); - } + // if(res.hasOwnProperty('set')) { + // res.set('Content-Type', 'text/css'); + // } const staticTheme = `/api/css/${req.brew.renderer}/${req.brew.theme}/styles.css`; const userTheme = `/api/css/${req.brew.theme.slice(1)}`; - const parentThemeImport = `// From Theme: ${req.brew.title}\n\n@import ${req.brew.theme[0] != '#' ? staticTheme : userTheme}\n\n`; + const parentThemeImport = `@import url(\"${req.brew.theme[0] != '#' ? staticTheme : userTheme}\");\n\n// From Theme: ${req.brew.title}\n\n`; return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}${req.brew.style}`); }, getStaticTheme : async(req, res)=>{ @@ -251,11 +251,11 @@ const api = { if(themeParent === undefined){ res.status(404).send(`Invalid Theme - Engine: ${req.params.engine}, Name: ${req.params.id}`); } else { - if(res.hasOwnProperty('set')) { - res.set('Content-Type', 'text/css'); - } - const parentTheme = themeParent ? `@import /api/css/${req.params.engine}/${themeParent}\n` : ''; - return res.status(200).send(`${parentTheme}@import /themes/${req.params.engine}/${req.params.id}/style.css\n`); + // if(res.hasOwnProperty('set')) { + // res.set('Content-Type', 'text/css'); + // } + const parentTheme = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n` : ''; + return res.status(200).send(`${parentTheme}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n`); } }, updateBrew : async (req, res)=>{ @@ -418,7 +418,5 @@ router.put('/api/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api router.put('/api/update/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); router.delete('/api/:id', asyncHandler(api.deleteBrew)); router.get('/api/remove/:id', asyncHandler(api.deleteBrew)); -router.get('/api/css/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.getBrewThemeWithCSS)); -router.get('/api/css/:engine/:id/', asyncHandler(api.getStaticTheme)); module.exports = api; From 3e66647f9ff2318575c4f1923da7984ef8214c32 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 23 Feb 2024 14:43:29 -0600 Subject: [PATCH 008/121] Fix @import loading on Chrome. --- server/app.js | 2 +- server/homebrew.api.js | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/server/app.js b/server/app.js index 7d1eaf577..38e4f2112 100644 --- a/server/app.js +++ b/server/app.js @@ -9,7 +9,7 @@ const yaml = require('js-yaml'); const app = express(); const config = require('./config.js'); -const { homebrewApi, getBrew, getBrewThemeWithCSS, getStaticTheme} = require('./homebrew.api.js'); +const { homebrewApi, getBrew, getBrewThemeWithCSS, getStaticTheme } = require('./homebrew.api.js'); const GoogleActions = require('./googleActions.js'); const serveCompressedStaticAssets = require('./static-assets.mv.js'); const sanitizeFilename = require('sanitize-filename'); diff --git a/server/homebrew.api.js b/server/homebrew.api.js index f01c7320c..feeecfbbc 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -238,12 +238,10 @@ const api = { getBrewThemeWithCSS : async (req, res)=>{ const brew = req.brew; splitTextStyleAndMetadata(brew); - // if(res.hasOwnProperty('set')) { - // res.set('Content-Type', 'text/css'); - // } + res.set('Content-Type', 'text/css'); const staticTheme = `/api/css/${req.brew.renderer}/${req.brew.theme}/styles.css`; const userTheme = `/api/css/${req.brew.theme.slice(1)}`; - const parentThemeImport = `@import url(\"${req.brew.theme[0] != '#' ? staticTheme : userTheme}\");\n\n// From Theme: ${req.brew.title}\n\n`; + const parentThemeImport = `@import url(\"${req.brew.theme[0] != '#' ? staticTheme : userTheme}\");\n\n/* From Brew: ${req.brew.title}*/\n\n`; return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}${req.brew.style}`); }, getStaticTheme : async(req, res)=>{ @@ -251,11 +249,10 @@ const api = { if(themeParent === undefined){ res.status(404).send(`Invalid Theme - Engine: ${req.params.engine}, Name: ${req.params.id}`); } else { - // if(res.hasOwnProperty('set')) { - // res.set('Content-Type', 'text/css'); - // } - const parentTheme = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n` : ''; - return res.status(200).send(`${parentTheme}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n`); + res.setHeader('Content-Type', 'text/css'); + res.setHeader('Cache-Control', 'public, max-age: 43200, must-revalidate'); + const parentTheme = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n/* Static Theme ${themes[req.params.engine][themeParent].name} */\n` : ''; + return res.status(200).send(`${parentTheme}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n/* Static Theme ${themes[req.params.engine][req.params.id].name} */\n`); } }, updateBrew : async (req, res)=>{ From 2456432844c990772ba01979e91862e7834085c0 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 23 Feb 2024 17:12:54 -0600 Subject: [PATCH 009/121] Exclude self from brew themes list to prevent circular ref. --- server/app.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/server/app.js b/server/app.js index 38e4f2112..f55296c8a 100644 --- a/server/app.js +++ b/server/app.js @@ -42,7 +42,7 @@ const sanitizeBrew = (brew, accessType)=>{ return brew; }; -const getUsersBrewThemes = async (username)=>{ +const getUsersBrewThemes = async (username,id)=>{ const fields = [ 'title', 'tags', @@ -59,14 +59,16 @@ const getUsersBrewThemes = async (username)=>{ }; brews.forEach((brew)=>{ - userThemes.Brew[brew.editId] = { - name : brew.title, - renderer : 'V3', - baseTheme : false, - baseSnippets : false, - path : `#${brew.editId}`, - thumbnail : brew.thumbnail - }; + if(id!=brew.editId) { + userThemes.Brew[brew.editId] = { + name : brew.title, + renderer : 'V3', + baseTheme : false, + baseSnippets : false, + path : `#${brew.editId}`, + thumbnail : brew.thumbnail + }; + } }); return userThemes; @@ -324,7 +326,7 @@ app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ type : 'article' }; - req.brew.userThemes = await getUsersBrewThemes(req.account.username); + req.brew.userThemes = await getUsersBrewThemes(req.account.username, req.brew.editId); sanitizeBrew(req.brew, 'edit'); splitTextStyleAndMetadata(req.brew); res.header('Cache-Control', 'no-cache, no-store'); //reload the latest saved brew when pressing back button, not the cached version before save. From 7b3a1eb4ffab50a1de6841e57f06e00b17a099a5 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 27 Feb 2024 13:41:51 -0600 Subject: [PATCH 010/121] Functional user theme loading though noising console --- client/homebrew/brewRenderer/brewRenderer.jsx | 28 ++++++++-- client/homebrew/editor/editor.jsx | 1 + .../editor/metadataEditor/metadataEditor.jsx | 10 ++-- .../homebrew/editor/snippetbar/snippetbar.jsx | 2 +- client/homebrew/pages/editPage/editPage.jsx | 6 ++ server/app.js | 45 +++------------ server/homebrew.api.js | 56 ++++++++++++++++++- 7 files changed, 99 insertions(+), 49 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 55116dea1..a9aefed07 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -14,7 +14,7 @@ const NotificationPopup = require('./notificationPopup/notificationPopup.jsx'); const Frame = require('react-frame-component').default; const dedent = require('dedent-tabs').default; -const Themes = require('themes/themes.json'); +const staticThemes = require('themes/themes.json'); const PAGE_HEIGHT = 1056; @@ -182,18 +182,34 @@ const BrewRenderer = (props)=>{ }; let rendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; - const themePath = props.theme ?? '5ePHB'; - const baseThemePath = Themes[rendererPath][themePath].baseTheme; + let baseRendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; + const blankRendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; + if(props.theme[0] === '#') { + rendererPath = 'Brew'; + } + let themePath = props.theme ?? '5ePHB'; + console.log(`props.userThemes`); + console.log(props); + console.log(`props.userThemes`); + const Themes = { ...staticThemes, ...props.userThemes }; + let baseThemePath = Themes[rendererPath][themePath]?.baseTheme; // Override static theme values if a Brew theme. if(themePath[0] == '#') { - themePath.slice(1); + themePath = themePath.slice(1); rendererPath = ''; } else { rendererPath += '/'; } + if(baseThemePath && baseThemePath[0] == '#') { + baseThemePath = baseThemePath.slice(1); + baseRendererPath = ''; + } else { + baseRendererPath += '/'; + } + return ( <> {/*render dummy page while iFrame is mounting.*/} @@ -220,9 +236,9 @@ const BrewRenderer = (props)=>{ - + {baseThemePath && - + } diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index d79d2ce4e..5791c4ee3 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -378,6 +378,7 @@ const Editor = createClass({ showEditButtons={this.props.showEditButtons} renderer={this.props.renderer} theme={this.props.brew.theme} + userThemes={this.props.brew.userThemes} undo={this.undo} redo={this.redo} foldCode={this.foldCode} diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 58c44ded9..963ebd1f7 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -38,6 +38,7 @@ const MetadataEditor = createClass({ authors : [], systems : [], renderer : 'legacy', + themeClass : 'V3', theme : '5ePHB', lang : 'en' }, @@ -110,8 +111,9 @@ const MetadataEditor = createClass({ }); }, - handleTheme : function(theme){ + handleTheme : function(theme, themeClass){ this.props.metadata.renderer = theme.renderer; + this.props.metadata.themeClass = themeClass; this.props.metadata.theme = theme.path; this.props.onChange(this.props.metadata); }, @@ -199,7 +201,7 @@ const MetadataEditor = createClass({ const listThemes = (renderer)=>{ return _.map(_.values(mergedThemes[renderer]), (theme)=>{ const preview = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; - return
this.handleTheme(theme)} title={''}> + return
this.handleTheme(theme, renderer)} title={''}> {`${renderer} : ${theme.name}`}
@@ -210,7 +212,7 @@ const MetadataEditor = createClass({ }); }; - const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme]; + const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.themeClass?this.props.metadata.themeClass:this.props.metadata.renderer)}`][this.props.metadata.theme]; let dropdown; if(this.props.metadata.renderer == 'legacy') { @@ -224,7 +226,7 @@ const MetadataEditor = createClass({ dropdown =
- {`${_.upperFirst(currentTheme.renderer)} : ${currentTheme.name}`} + {`${_.upperFirst(this.props.metadata.themeClass?this.props.metadata.themeClass:this.props.metadata.renderer)} : ${currentTheme.name}`}
{/*listThemes('Legacy')*/} {listThemes('V3')} diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 75fe0d736..cb7570a44 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -84,7 +84,7 @@ const Snippetbar = createClass({ compileSnippets : function(rendererPath, themePath, snippets) { let compiledSnippets = snippets; - const baseSnippetsPath = Themes[rendererPath][themePath].baseSnippets; + const baseSnippetsPath = themePath[0] != '#' ? Themes[rendererPath][themePath].baseSnippets : false; const objB = _.keyBy(compiledSnippets, 'groupName'); diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index d5af310b5..a061d33b8 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -388,6 +388,10 @@ const EditPage = createClass({ return
{this.renderNavbar()} + {console.log('state')} + {console.log(this.state)} + {console.log('props')} + {console.log(this.props)}
@@ -407,6 +411,8 @@ const EditPage = createClass({ theme={this.state.brew.theme} errors={this.state.htmlErrors} lang={this.state.brew.lang} + userThemes={this.props.brew.userThemes} + themeClass={this.state.brew.themeClass} currentEditorPage={this.state.currentEditorPage} /> diff --git a/server/app.js b/server/app.js index f55296c8a..3ecaa2df9 100644 --- a/server/app.js +++ b/server/app.js @@ -42,38 +42,6 @@ const sanitizeBrew = (brew, accessType)=>{ return brew; }; -const getUsersBrewThemes = async (username,id)=>{ - const fields = [ - 'title', - 'tags', - 'editId', - 'thumbnail' - ]; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] } }) //lean() converts results to JSObjects - .catch((error)=>{throw 'Can not find brews';}); - - const userThemes = { - Brew : { - - } - }; - - brews.forEach((brew)=>{ - if(id!=brew.editId) { - userThemes.Brew[brew.editId] = { - name : brew.title, - renderer : 'V3', - baseTheme : false, - baseSnippets : false, - path : `#${brew.editId}`, - thumbnail : brew.thumbnail - }; - } - }); - - return userThemes; -}; - app.use('/', serveCompressedStaticAssets(`build`)); app.use(require('./middleware/content-negotiation.js')); app.use(require('body-parser').json({ limit: '25mb' })); @@ -318,6 +286,9 @@ app.get('/user/:username', async (req, res, next)=>{ //Edit Page app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; + console.log('edit'); + console.log(req); + console.log('edit'); req.ogMeta = { ...defaultMetaTags, title : req.brew.title || 'Untitled Brew', @@ -326,7 +297,6 @@ app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ type : 'article' }; - req.brew.userThemes = await getUsersBrewThemes(req.account.username, req.brew.editId); sanitizeBrew(req.brew, 'edit'); splitTextStyleAndMetadata(req.brew); res.header('Cache-Control', 'no-cache, no-store'); //reload the latest saved brew when pressing back button, not the cached version before save. @@ -344,7 +314,7 @@ app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{ style : req.brew.style, renderer : req.brew.renderer, theme : req.brew.theme, - tags : req.brew.tags + tags : req.brew.tags, }; req.brew = _.defaults(brew, DEFAULT_BREW); @@ -378,13 +348,15 @@ app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, r await HomebrewModel.increaseView({ shareId: brew.shareId }); } }; + req.brew.userThemes = await getUsersBrewThemes(req.account.username, req.brew.editId); sanitizeBrew(req.brew, 'share'); splitTextStyleAndMetadata(req.brew); return next(); })); //Print Page -app.get('/print/:id', asyncHandler(getBrew('share')), (req, res, next)=>{ +app.get('/print/:id', asyncHandler(getBrew('share')), async (req, res, next)=>{ + req.brew.userThemes = await getUsersBrewThemes(req.account.username, req.brew.editId); sanitizeBrew(req.brew, 'share'); splitTextStyleAndMetadata(req.brew); next(); @@ -477,7 +449,8 @@ const renderPage = async (req, res)=>{ enable_v3 : config.get('enable_v3'), enable_themes : config.get('enable_themes'), config : configuration, - ogMeta : req.ogMeta + ogMeta : req.ogMeta, + userThemes : req.userThemes }; const title = req.brew ? req.brew.title : ''; const page = await templateFn('homebrew', title, props) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index feeecfbbc..7a896b9e0 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -46,8 +46,54 @@ const splitTextStyleAndMetadata = (brew)=>{ brew.style = brew.text.slice(7, index - 1); brew.text = brew.text.slice(index + 5); } + console.log(brew.theme); }; +const getUsersBrewThemes = async (username, id)=>{ + console.log(username); + console.log(id); + const fields = [ + 'title', + 'tags', + 'editId', + 'thumbnail', + 'textBin' + ]; + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] } }) //lean() converts results to JSObjects + .catch((error)=>{throw 'Can not find brews';}); + + const userThemes = { + Brew : { + + } + }; + + console.log(`Length of user brews ${brews.size}`); + + brews.forEach(async (brew)=>{ + b = await HomebrewModel.get({ editId: brew.editId }, ['textBin']); + splitTextStyleAndMetadata(b); + console.log(`whee!!!! ${b.theme}`); + console.log(id); + console.log(brew.editId); + if(id!=brew.editId) { + + userThemes.Brew[`#${brew.editId}`] = { + name : brew.title, + renderer : 'V3', + baseTheme : b.theme, + baseSnippets : false, + path : `#${brew.editId}`, + thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' + }; + console.log(`Wheee! ${userThemes.Brew[`#${brew.editId}`].baseTheme}`); + } + }); + + return userThemes; +}; + + const api = { homebrewApi : router, getId : (req)=>{ @@ -119,11 +165,14 @@ const api = { throw { name: 'BrewLoad Error', message: 'Brew not found', status: 404, HBErrorCode: '05', accessType: accessType, brewId: id }; } + const userID = accessType === 'edit' ? req.account.username : stub.authors.split(',')[0]; + // Clean up brew: fill in missing fields with defaults / fix old invalid values if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields + stub.userThemes = await getUsersBrewThemes(userID, id); } req.brew = stub ?? {}; @@ -239,8 +288,8 @@ const api = { const brew = req.brew; splitTextStyleAndMetadata(brew); res.set('Content-Type', 'text/css'); - const staticTheme = `/api/css/${req.brew.renderer}/${req.brew.theme}/styles.css`; - const userTheme = `/api/css/${req.brew.theme.slice(1)}`; + const staticTheme = `/css/${req.brew.renderer}/${req.brew.theme}`; + const userTheme = `/css/${req.brew.theme.slice(1)}`; const parentThemeImport = `@import url(\"${req.brew.theme[0] != '#' ? staticTheme : userTheme}\");\n\n/* From Brew: ${req.brew.title}*/\n\n`; return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}${req.brew.style}`); }, @@ -273,6 +322,9 @@ const api = { brew.title = brew.title.trim(); brew.description = brew.description.trim() || ''; brew.text = api.mergeBrewText(brew); + const userID = req?.account?.username ? req.account.username : brew.authors.split(',')[0]; + brew.userThemes = await getUsersBrewThemes(userID, brew.editId); + if(brew.googleId && removeFromGoogle) { // If the google id exists and we're removing it from google, set afterSave to delete the google brew and mark the brew's google id as undefined From 4f4659b0e2490a7db355dd21c9bb99006f9d54d7 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 27 Feb 2024 13:57:58 -0600 Subject: [PATCH 011/121] Cleaned up noise in homebrew.api.js --- server/homebrew.api.js | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 7a896b9e0..6475e7a26 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -46,12 +46,9 @@ const splitTextStyleAndMetadata = (brew)=>{ brew.style = brew.text.slice(7, index - 1); brew.text = brew.text.slice(index + 5); } - console.log(brew.theme); }; const getUsersBrewThemes = async (username, id)=>{ - console.log(username); - console.log(id); const fields = [ 'title', 'tags', @@ -59,7 +56,7 @@ const getUsersBrewThemes = async (username, id)=>{ 'thumbnail', 'textBin' ]; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] } }) //lean() converts results to JSObjects + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects .catch((error)=>{throw 'Can not find brews';}); const userThemes = { @@ -68,26 +65,17 @@ const getUsersBrewThemes = async (username, id)=>{ } }; - console.log(`Length of user brews ${brews.size}`); - brews.forEach(async (brew)=>{ - b = await HomebrewModel.get({ editId: brew.editId }, ['textBin']); - splitTextStyleAndMetadata(b); - console.log(`whee!!!! ${b.theme}`); - console.log(id); - console.log(brew.editId); - if(id!=brew.editId) { - - userThemes.Brew[`#${brew.editId}`] = { - name : brew.title, - renderer : 'V3', - baseTheme : b.theme, - baseSnippets : false, - path : `#${brew.editId}`, - thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' - }; - console.log(`Wheee! ${userThemes.Brew[`#${brew.editId}`].baseTheme}`); - } + const brewTheme = await HomebrewModel.get({ editId: brew.editId }, ['textBin']); + splitTextStyleAndMetadata(brewTheme); + userThemes.Brew[`#${brew.editId}`] = { + name : brew.title, + renderer : 'V3', + baseTheme : brewTheme.theme, + baseSnippets : false, + path : `#${brew.editId}`, + thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' + }; }); return userThemes; From 50c9d95ce0e24b709b66d41d467bd8eca857317b Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 27 Feb 2024 17:30:14 -0600 Subject: [PATCH 012/121] WIP trying to debug theme selection. --- client/homebrew/editor/editor.jsx | 3 +++ .../editor/metadataEditor/metadataEditor.jsx | 1 - client/homebrew/pages/editPage/editPage.jsx | 13 ++++++------- server/app.js | 3 --- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 5791c4ee3..471682393 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -339,6 +339,9 @@ const Editor = createClass({ view={this.state.view} style={{ display: 'none' }} rerenderParent={this.rerenderParent} /> + {console.log('Metadata')} + {console.log(this.props)} + {console.log('Metadata')} {this.renderNavbar()} - {console.log('state')} - {console.log(this.state)} - {console.log('props')} - {console.log(this.props)}
@@ -411,8 +411,7 @@ const EditPage = createClass({ theme={this.state.brew.theme} errors={this.state.htmlErrors} lang={this.state.brew.lang} - userThemes={this.props.brew.userThemes} - themeClass={this.state.brew.themeClass} + userThemes={this.state.brew.userThemes} currentEditorPage={this.state.currentEditorPage} /> diff --git a/server/app.js b/server/app.js index 3ecaa2df9..b31524933 100644 --- a/server/app.js +++ b/server/app.js @@ -286,9 +286,6 @@ app.get('/user/:username', async (req, res, next)=>{ //Edit Page app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; - console.log('edit'); - console.log(req); - console.log('edit'); req.ogMeta = { ...defaultMetaTags, title : req.brew.title || 'Untitled Brew', From 56851f2c2d87d390e1d51554018206a5af6fb1aa Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 27 Feb 2024 19:33:33 -0600 Subject: [PATCH 013/121] Edit working - with noise. --- .../editor/metadataEditor/metadataEditor.jsx | 5 ++++- server/app.js | 3 +++ server/homebrew.api.js | 17 ++++++++++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 179dc553f..805ec6737 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -211,7 +211,10 @@ const MetadataEditor = createClass({ }); }; - const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.themeClass?this.props.metadata.themeClass:this.props.metadata.renderer)}`][this.props.metadata.theme]; + const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.theme[0] === '#' ? 'Brew' : this.props.metadata.renderer)}`][this.props.metadata.theme]; + console.log('currentTheme'); + console.log(this.props.metadata.themeClass); + console.log('currentTheme'); let dropdown; if(this.props.metadata.renderer == 'legacy') { diff --git a/server/app.js b/server/app.js index b31524933..55ab52e13 100644 --- a/server/app.js +++ b/server/app.js @@ -286,6 +286,9 @@ app.get('/user/:username', async (req, res, next)=>{ //Edit Page app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; + console.log('Load Edit'); + console.log(req.brew); + console.log('Load Edit'); req.ogMeta = { ...defaultMetaTags, title : req.brew.title || 'Untitled Brew', diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 6475e7a26..b4d70a7a1 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -49,6 +49,9 @@ const splitTextStyleAndMetadata = (brew)=>{ }; const getUsersBrewThemes = async (username, id)=>{ + console.log('getUsersBrewThemes'); + console.log(username); + console.log(id); const fields = [ 'title', 'tags', @@ -56,6 +59,7 @@ const getUsersBrewThemes = async (username, id)=>{ 'thumbnail', 'textBin' ]; + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects .catch((error)=>{throw 'Can not find brews';}); @@ -65,7 +69,7 @@ const getUsersBrewThemes = async (username, id)=>{ } }; - brews.forEach(async (brew)=>{ + for await (const brew of brews) { const brewTheme = await HomebrewModel.get({ editId: brew.editId }, ['textBin']); splitTextStyleAndMetadata(brewTheme); userThemes.Brew[`#${brew.editId}`] = { @@ -76,8 +80,9 @@ const getUsersBrewThemes = async (username, id)=>{ path : `#${brew.editId}`, thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' }; - }); + }; + console.log('getUsersBrewThemes end'); return userThemes; }; @@ -156,13 +161,19 @@ const api = { const userID = accessType === 'edit' ? req.account.username : stub.authors.split(',')[0]; // Clean up brew: fill in missing fields with defaults / fix old invalid values + const userThemes = await getUsersBrewThemes(userID, id); if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields - stub.userThemes = await getUsersBrewThemes(userID, id); + stub.userThemes = userThemes; } + + console.log('stub.userThemes'); + console.log(stub.userThemes); + console.log(stub.userThemes); + console.log('stub.userThemes'); req.brew = stub ?? {}; next(); }; From 7384cdc241568d24ff5e3ac077d1093da91708e1 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 27 Feb 2024 20:20:43 -0600 Subject: [PATCH 014/121] My god it works --- client/homebrew/pages/printPage/printPage.jsx | 51 ++++++++++++++----- server/app.js | 2 - server/homebrew.api.js | 6 ++- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/client/homebrew/pages/printPage/printPage.jsx b/client/homebrew/pages/printPage/printPage.jsx index 083410804..7d162eb59 100644 --- a/client/homebrew/pages/printPage/printPage.jsx +++ b/client/homebrew/pages/printPage/printPage.jsx @@ -7,7 +7,7 @@ const { Meta } = require('vitreum/headtags'); const MarkdownLegacy = require('naturalcrit/markdownLegacy.js'); const Markdown = require('naturalcrit/markdown.js'); -const Themes = require('themes/themes.json'); +const staticThemes = require('themes/themes.json'); const BREWKEY = 'homebrewery-new'; const STYLEKEY = 'homebrewery-new-style'; @@ -30,11 +30,12 @@ const PrintPage = createClass({ getInitialState : function() { return { brew : { - text : this.props.brew.text || '', - style : this.props.brew.style || undefined, - renderer : this.props.brew.renderer || 'legacy', - theme : this.props.brew.theme || '5ePHB', - lang : this.props.brew.lang || 'en' + text : this.props.brew.text || '', + style : this.props.brew.style || undefined, + renderer : this.props.brew.renderer || 'legacy', + theme : this.props.brew.theme || '5ePHB', + lang : this.props.brew.lang || 'en', + userThemes : this.props.brew.userThemes } }; }, @@ -90,17 +91,43 @@ const PrintPage = createClass({ }, render : function(){ - const rendererPath = this.state.brew.renderer == 'V3' ? 'V3' : 'Legacy'; - const themePath = this.state.brew.theme ?? '5ePHB'; - const baseThemePath = Themes[rendererPath][themePath].baseTheme; + let rendererPath = this.state.brew.renderer == 'V3' ? 'V3' : 'Legacy'; + let baseRendererPath = this.state.brew.renderer == 'V3' ? 'V3' : 'Legacy'; + const blankRendererPath = this.state.brew.renderer == 'V3' ? 'V3' : 'Legacy'; + if(this.state.brew.theme[0] === '#') { + rendererPath = 'Brew'; + } + let themePath = this.state.brew.theme ?? '5ePHB'; + console.log(`this.state.brew.userThemes`); + console.log(this.state.brew); + console.log(`this.state.brew.userThemes`); + const Themes = { ...staticThemes, ...this.state.brew.userThemes }; + let baseThemePath = Themes[rendererPath][themePath]?.baseTheme; + + // Override static theme values if a Brew theme. + + if(themePath[0] == '#') { + themePath = themePath.slice(1); + rendererPath = ''; + } else { + rendererPath += '/'; + } + + if(baseThemePath && baseThemePath[0] == '#') { + baseThemePath = baseThemePath.slice(1); + baseRendererPath = ''; + } else { + baseRendererPath += '/'; + } + return
- + {baseThemePath && - + } - + {/* Apply CSS from Style tab */} {this.renderStyle()}
diff --git a/server/app.js b/server/app.js index 55ab52e13..4bd753c2d 100644 --- a/server/app.js +++ b/server/app.js @@ -348,7 +348,6 @@ app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, r await HomebrewModel.increaseView({ shareId: brew.shareId }); } }; - req.brew.userThemes = await getUsersBrewThemes(req.account.username, req.brew.editId); sanitizeBrew(req.brew, 'share'); splitTextStyleAndMetadata(req.brew); return next(); @@ -356,7 +355,6 @@ app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, r //Print Page app.get('/print/:id', asyncHandler(getBrew('share')), async (req, res, next)=>{ - req.brew.userThemes = await getUsersBrewThemes(req.account.username, req.brew.editId); sanitizeBrew(req.brew, 'share'); splitTextStyleAndMetadata(req.brew); next(); diff --git a/server/homebrew.api.js b/server/homebrew.api.js index b4d70a7a1..dff9da7a9 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -158,7 +158,11 @@ const api = { throw { name: 'BrewLoad Error', message: 'Brew not found', status: 404, HBErrorCode: '05', accessType: accessType, brewId: id }; } - const userID = accessType === 'edit' ? req.account.username : stub.authors.split(',')[0]; + console.log(`print`); + console.log(accessType); + console.log(stub); + console.log(`print`); + const userID = accessType === 'edit' ? req.account.username : stub.authors[0]; // Clean up brew: fill in missing fields with defaults / fix old invalid values const userThemes = await getUsersBrewThemes(userID, id); From 8f15887c033fa286b67abf06cd0688d42ebb8446 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 27 Feb 2024 20:51:59 -0600 Subject: [PATCH 015/121] Cleanup of console logging --- client/homebrew/brewRenderer/brewRenderer.jsx | 3 --- client/homebrew/editor/editor.jsx | 3 --- .../editor/metadataEditor/metadataEditor.jsx | 3 --- client/homebrew/pages/editPage/editPage.jsx | 3 --- client/homebrew/pages/printPage/printPage.jsx | 3 --- server/app.js | 3 --- server/homebrew.api.js | 13 ------------- 7 files changed, 31 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index a9aefed07..1f52f993e 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -188,9 +188,6 @@ const BrewRenderer = (props)=>{ rendererPath = 'Brew'; } let themePath = props.theme ?? '5ePHB'; - console.log(`props.userThemes`); - console.log(props); - console.log(`props.userThemes`); const Themes = { ...staticThemes, ...props.userThemes }; let baseThemePath = Themes[rendererPath][themePath]?.baseTheme; diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 471682393..5791c4ee3 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -339,9 +339,6 @@ const Editor = createClass({ view={this.state.view} style={{ display: 'none' }} rerenderParent={this.rerenderParent} /> - {console.log('Metadata')} - {console.log(this.props)} - {console.log('Metadata')} { //Edit Page app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; - console.log('Load Edit'); - console.log(req.brew); - console.log('Load Edit'); req.ogMeta = { ...defaultMetaTags, title : req.brew.title || 'Untitled Brew', diff --git a/server/homebrew.api.js b/server/homebrew.api.js index dff9da7a9..fa4a5de1d 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -49,9 +49,6 @@ const splitTextStyleAndMetadata = (brew)=>{ }; const getUsersBrewThemes = async (username, id)=>{ - console.log('getUsersBrewThemes'); - console.log(username); - console.log(id); const fields = [ 'title', 'tags', @@ -82,7 +79,6 @@ const getUsersBrewThemes = async (username, id)=>{ }; }; - console.log('getUsersBrewThemes end'); return userThemes; }; @@ -158,10 +154,6 @@ const api = { throw { name: 'BrewLoad Error', message: 'Brew not found', status: 404, HBErrorCode: '05', accessType: accessType, brewId: id }; } - console.log(`print`); - console.log(accessType); - console.log(stub); - console.log(`print`); const userID = accessType === 'edit' ? req.account.username : stub.authors[0]; // Clean up brew: fill in missing fields with defaults / fix old invalid values @@ -173,11 +165,6 @@ const api = { stub.userThemes = userThemes; } - - console.log('stub.userThemes'); - console.log(stub.userThemes); - console.log(stub.userThemes); - console.log('stub.userThemes'); req.brew = stub ?? {}; next(); }; From 562daf9b0493d1831145a26bf11217297bb442d8 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 27 Feb 2024 21:13:22 -0600 Subject: [PATCH 016/121] Handle some statics --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index fa4a5de1d..12991a4ca 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -277,7 +277,7 @@ const api = { getBrewThemeWithCSS : async (req, res)=>{ const brew = req.brew; splitTextStyleAndMetadata(brew); - res.set('Content-Type', 'text/css'); + res.setHeader('Content-Type', 'text/css'); const staticTheme = `/css/${req.brew.renderer}/${req.brew.theme}`; const userTheme = `/css/${req.brew.theme.slice(1)}`; const parentThemeImport = `@import url(\"${req.brew.theme[0] != '#' ? staticTheme : userTheme}\");\n\n/* From Brew: ${req.brew.title}*/\n\n`; From 544bc9bd01dd5c36af4433bef85c16dbf71ce9f2 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 28 Feb 2024 08:32:15 -0600 Subject: [PATCH 017/121] Catch bad assumption in unlogged saves --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 12991a4ca..1147d3504 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -154,7 +154,7 @@ const api = { throw { name: 'BrewLoad Error', message: 'Brew not found', status: 404, HBErrorCode: '05', accessType: accessType, brewId: id }; } - const userID = accessType === 'edit' ? req.account.username : stub.authors[0]; + const userID = req?.account?.username && (accessType === 'edit') ? req.account.username : stub.authors[0]; // Clean up brew: fill in missing fields with defaults / fix old invalid values const userThemes = await getUsersBrewThemes(userID, id); From 753b3befad7f9c55b780341ed102f96fd6a711e0 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 28 Feb 2024 14:53:40 -0600 Subject: [PATCH 018/121] Fix issue with empty theme ( /faq ) --- client/homebrew/brewRenderer/brewRenderer.jsx | 2 +- config/default.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 1f52f993e..84d0d21dd 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -184,7 +184,7 @@ const BrewRenderer = (props)=>{ let rendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; let baseRendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; const blankRendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; - if(props.theme[0] === '#') { + if(props?.theme && (props?.theme[0] === '#')) { rendererPath = 'Brew'; } let themePath = props.theme ?? '5ePHB'; diff --git a/config/default.json b/config/default.json index 12b35e6cf..35459a022 100644 --- a/config/default.json +++ b/config/default.json @@ -6,5 +6,6 @@ "enable_v3" : true, "enable_themes" : true, "local_environments" : ["docker", "local"], - "publicUrl" : "https://homebrewery.naturalcrit.com" + "publicUrl" : "https://homebrewery.naturalcrit.com", + "mongodb_uri" : "mongodb://127.0.0.1/homebrewery3" } From 4f90f92b38d8382316b435ae974b56d455af0962 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 28 Feb 2024 15:08:00 -0600 Subject: [PATCH 019/121] Additional theme based error checking. --- client/homebrew/brewRenderer/brewRenderer.jsx | 4 ++-- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 3 ++- client/homebrew/editor/snippetbar/snippetbar.jsx | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 84d0d21dd..6e97ec092 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -193,14 +193,14 @@ const BrewRenderer = (props)=>{ // Override static theme values if a Brew theme. - if(themePath[0] == '#') { + if(themePath && themePath[0] === '#') { themePath = themePath.slice(1); rendererPath = ''; } else { rendererPath += '/'; } - if(baseThemePath && baseThemePath[0] == '#') { + if(baseThemePath && baseThemePath[0] === '#') { baseThemePath = baseThemePath.slice(1); baseRendererPath = ''; } else { diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index fadd5dd6c..573fb00c3 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -211,7 +211,8 @@ const MetadataEditor = createClass({ }); }; - const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.theme[0] === '#' ? 'Brew' : this.props.metadata.renderer)}`][this.props.metadata.theme]; + const currentThemePath = this.props.metadata?.theme && this.props.metadata.theme[0] === '#' ? 'Brew' : this.props.metadata.renderer; + const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme]; let dropdown; if(this.props.metadata.renderer == 'legacy') { diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index cb7570a44..4c7f4a200 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -84,7 +84,7 @@ const Snippetbar = createClass({ compileSnippets : function(rendererPath, themePath, snippets) { let compiledSnippets = snippets; - const baseSnippetsPath = themePath[0] != '#' ? Themes[rendererPath][themePath].baseSnippets : false; + const baseSnippetsPath = themePath && (themePath[0] === '#') ? false : Themes[rendererPath][themePath].baseSnippets; const objB = _.keyBy(compiledSnippets, 'groupName'); From a54fb98d4e938bfb79e9de317a4695fff15f1163 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 10:28:09 -0600 Subject: [PATCH 020/121] Additional debugging --- client/homebrew/pages/newPage/newPage.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 9877651c2..9fd82b282 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -150,7 +150,7 @@ const NewPage = createClass({ } brew.pageCount=((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1; - + console.log('Running post.'); const res = await request .post(`/api${this.state.saveGoogle ? '?saveToGoogle=true' : ''}`) .send(brew) @@ -158,7 +158,9 @@ const NewPage = createClass({ console.log(err); this.setState({ isSaving: false, error: err }); }); - if(!res) return; + console.log('Post completed'); + if(!res) return; + console.log('Had results!'); brew = res.body; localStorage.removeItem(BREWKEY); From 79a42911538b923caadcef2c9c84e5a6ebb1bcaa Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 10:37:10 -0600 Subject: [PATCH 021/121] More debug --- client/homebrew/pages/newPage/newPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 9fd82b282..1510564b6 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -166,7 +166,7 @@ const NewPage = createClass({ localStorage.removeItem(BREWKEY); localStorage.removeItem(STYLEKEY); localStorage.removeItem(METAKEY); - window.location = `/edit/${brew.editId}`; + //window.location = `/edit/${brew.editId}`; }, renderSaveButton : function(){ From 6f6a06c8c30787d4b6a209cf4066b81ac4939143 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 11:00:43 -0600 Subject: [PATCH 022/121] More debug --- client/homebrew/pages/newPage/newPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 1510564b6..9fd82b282 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -166,7 +166,7 @@ const NewPage = createClass({ localStorage.removeItem(BREWKEY); localStorage.removeItem(STYLEKEY); localStorage.removeItem(METAKEY); - //window.location = `/edit/${brew.editId}`; + window.location = `/edit/${brew.editId}`; }, renderSaveButton : function(){ From 17f78169f203713fa15852b309efa731bded6cb6 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 12:03:27 -0600 Subject: [PATCH 023/121] More debug --- server/homebrew.api.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 1147d3504..1fa92a84d 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -57,15 +57,19 @@ const getUsersBrewThemes = async (username, id)=>{ 'textBin' ]; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects - .catch((error)=>{throw 'Can not find brews';}); - const userThemes = { Brew : { } }; + if(!username || !id) { + return userThemes; + } + + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects + .catch((error)=>{throw 'Can not find brews';}); + for await (const brew of brews) { const brewTheme = await HomebrewModel.get({ editId: brew.editId }, ['textBin']); splitTextStyleAndMetadata(brewTheme); From 18aa453bb02e05337e717614ddad062b1b298c71 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 12:38:00 -0600 Subject: [PATCH 024/121] Rearrange and leverage getBrew --- config/default.json | 1 - server/homebrew.api.js | 83 +++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/config/default.json b/config/default.json index 35459a022..f16008a00 100644 --- a/config/default.json +++ b/config/default.json @@ -7,5 +7,4 @@ "enable_themes" : true, "local_environments" : ["docker", "local"], "publicUrl" : "https://homebrewery.naturalcrit.com", - "mongodb_uri" : "mongodb://127.0.0.1/homebrewery3" } diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 1fa92a84d..649bd27c2 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -48,45 +48,6 @@ const splitTextStyleAndMetadata = (brew)=>{ } }; -const getUsersBrewThemes = async (username, id)=>{ - const fields = [ - 'title', - 'tags', - 'editId', - 'thumbnail', - 'textBin' - ]; - - const userThemes = { - Brew : { - - } - }; - - if(!username || !id) { - return userThemes; - } - - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects - .catch((error)=>{throw 'Can not find brews';}); - - for await (const brew of brews) { - const brewTheme = await HomebrewModel.get({ editId: brew.editId }, ['textBin']); - splitTextStyleAndMetadata(brewTheme); - userThemes.Brew[`#${brew.editId}`] = { - name : brew.title, - renderer : 'V3', - baseTheme : brewTheme.theme, - baseSnippets : false, - path : `#${brew.editId}`, - thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' - }; - }; - - return userThemes; -}; - - const api = { homebrewApi : router, getId : (req)=>{ @@ -105,6 +66,46 @@ const api = { } return { id, googleId }; }, + getUsersBrewThemes : async (username, id, req, res, next)=>{ + const fields = [ + 'title', + 'tags', + 'editId', + 'thumbnail', + 'textBin' + ]; + + const userThemes = { + Brew : { + + } + }; + + if(!username || !id) { + return userThemes; + } + + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects + .catch((error)=>{throw 'Can not find brews';}); + + for await (const brew of brews) { + api.getBrew('themes', req=req, res=res, next=next); + const brewTheme = req.brew; + if(brewTheme) { + splitTextStyleAndMetadata(brewTheme); + userThemes.Brew[`#${brew.editId}`] = { + name : brew.title, + renderer : 'V3', + baseTheme : brewTheme.theme, + baseSnippets : false, + path : `#${brew.editId}`, + thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' + }; + } + }; + + return userThemes; + }, getBrew : (accessType, stubOnly = false)=>{ // Create middleware with the accessType passed in as part of the scope return async (req, res, next)=>{ @@ -161,7 +162,7 @@ const api = { const userID = req?.account?.username && (accessType === 'edit') ? req.account.username : stub.authors[0]; // Clean up brew: fill in missing fields with defaults / fix old invalid values - const userThemes = await getUsersBrewThemes(userID, id); + const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : ''; if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings @@ -317,7 +318,7 @@ const api = { brew.description = brew.description.trim() || ''; brew.text = api.mergeBrewText(brew); const userID = req?.account?.username ? req.account.username : brew.authors.split(',')[0]; - brew.userThemes = await getUsersBrewThemes(userID, brew.editId); + brew.userThemes = await api.getUsersBrewThemes(userID, brew.editId, req, res, null); if(brew.googleId && removeFromGoogle) { From ac4c84e7a4da50f7927c798d9b8d1a5c46883584 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 12:44:20 -0600 Subject: [PATCH 025/121] config file fix --- config/default.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/default.json b/config/default.json index f16008a00..12b35e6cf 100644 --- a/config/default.json +++ b/config/default.json @@ -6,5 +6,5 @@ "enable_v3" : true, "enable_themes" : true, "local_environments" : ["docker", "local"], - "publicUrl" : "https://homebrewery.naturalcrit.com", + "publicUrl" : "https://homebrewery.naturalcrit.com" } From 695324832c428c10e465c6e1058aa472a7c7189c Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 12:56:33 -0600 Subject: [PATCH 026/121] more heroku debug --- server/homebrew.api.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 649bd27c2..a924214e6 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -103,7 +103,8 @@ const api = { }; } }; - + console.log('We found themes!'); + console.log(userThemes); return userThemes; }, getBrew : (accessType, stubOnly = false)=>{ @@ -163,6 +164,7 @@ const api = { // Clean up brew: fill in missing fields with defaults / fix old invalid values const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : ''; + console('Made it past userThemes'); if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings From 0dbf6453ac124e08dbfc488c54d98477969441d6 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:04:03 -0600 Subject: [PATCH 027/121] more heroku debug --- server/homebrew.api.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index a924214e6..78fc1b810 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -162,6 +162,7 @@ const api = { const userID = req?.account?.username && (accessType === 'edit') ? req.account.username : stub.authors[0]; + console.log('Preparing to load user themes.'); // Clean up brew: fill in missing fields with defaults / fix old invalid values const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : ''; console('Made it past userThemes'); From 0580e45af961949d488626f5df40ab3476826fe9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:11:49 -0600 Subject: [PATCH 028/121] more heroku debug --- server/homebrew.api.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 78fc1b810..d5d9b5602 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -85,8 +85,10 @@ const api = { return userThemes; } + console.log(`Looking for Theme Brews for ${username} that aren't ${id}`); const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects .catch((error)=>{throw 'Can not find brews';}); + console.log(brews); for await (const brew of brews) { api.getBrew('themes', req=req, res=res, next=next); From 2aaae95e8947ba20bb78c30903139d07c99ac9cd Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:16:57 -0600 Subject: [PATCH 029/121] more heroku debug --- server/homebrew.api.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index d5d9b5602..c2535e973 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -72,7 +72,8 @@ const api = { 'tags', 'editId', 'thumbnail', - 'textBin' + 'textBin', + 'text' ]; const userThemes = { @@ -86,7 +87,7 @@ const api = { } console.log(`Looking for Theme Brews for ${username} that aren't ${id}`); - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }}) //lean() converts results to JSObjects .catch((error)=>{throw 'Can not find brews';}); console.log(brews); From 317b80bf4dd340c58102b5e5da8439e3310e101f Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:20:57 -0600 Subject: [PATCH 030/121] more heroku debug --- server/homebrew.api.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index c2535e973..0716878f3 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -87,13 +87,15 @@ const api = { } console.log(`Looking for Theme Brews for ${username} that aren't ${id}`); - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }}) //lean() converts results to JSObjects + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects .catch((error)=>{throw 'Can not find brews';}); console.log(brews); for await (const brew of brews) { - api.getBrew('themes', req=req, res=res, next=next); + const foo = api.getBrew('themes', req=req, res=res, next=next); const brewTheme = req.brew; + console.log(req); + console.log(foo); if(brewTheme) { splitTextStyleAndMetadata(brewTheme); userThemes.Brew[`#${brew.editId}`] = { @@ -168,7 +170,7 @@ const api = { console.log('Preparing to load user themes.'); // Clean up brew: fill in missing fields with defaults / fix old invalid values const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : ''; - console('Made it past userThemes'); + console.log('Made it past userThemes'); if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings From 1dc73a951ed3dce6bcca28caefdce237252dbe08 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:35:08 -0600 Subject: [PATCH 031/121] more heroku debug --- server/homebrew.api.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 0716878f3..558465f39 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -86,16 +86,12 @@ const api = { return userThemes; } - console.log(`Looking for Theme Brews for ${username} that aren't ${id}`); const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects .catch((error)=>{throw 'Can not find brews';}); - console.log(brews); for await (const brew of brews) { const foo = api.getBrew('themes', req=req, res=res, next=next); const brewTheme = req.brew; - console.log(req); - console.log(foo); if(brewTheme) { splitTextStyleAndMetadata(brewTheme); userThemes.Brew[`#${brew.editId}`] = { @@ -108,8 +104,6 @@ const api = { }; } }; - console.log('We found themes!'); - console.log(userThemes); return userThemes; }, getBrew : (accessType, stubOnly = false)=>{ @@ -167,10 +161,8 @@ const api = { const userID = req?.account?.username && (accessType === 'edit') ? req.account.username : stub.authors[0]; - console.log('Preparing to load user themes.'); // Clean up brew: fill in missing fields with defaults / fix old invalid values const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : ''; - console.log('Made it past userThemes'); if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings From 8765bc800d27b630ae81444135a0072812de22a9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:38:48 -0600 Subject: [PATCH 032/121] more heroku debug --- server/homebrew.api.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 558465f39..ffd857da7 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -86,9 +86,10 @@ const api = { return userThemes; } - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme', 'type:theme', 'type:Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects .catch((error)=>{throw 'Can not find brews';}); + console.log(brews); for await (const brew of brews) { const foo = api.getBrew('themes', req=req, res=res, next=next); const brewTheme = req.brew; From e639a32822068f7a3dd1b79756245cd88712ce25 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:41:58 -0600 Subject: [PATCH 033/121] more heroku debug --- server/homebrew.api.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index ffd857da7..421c606dd 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -90,6 +90,7 @@ const api = { .catch((error)=>{throw 'Can not find brews';}); console.log(brews); + console.log(brews.length); for await (const brew of brews) { const foo = api.getBrew('themes', req=req, res=res, next=next); const brewTheme = req.brew; From 00cfd427b122b8b4b0ea120d5337782bfb936958 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:47:40 -0600 Subject: [PATCH 034/121] more heroku debug --- server/homebrew.api.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 421c606dd..1c13eb316 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -89,8 +89,6 @@ const api = { const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme', 'type:theme', 'type:Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects .catch((error)=>{throw 'Can not find brews';}); - console.log(brews); - console.log(brews.length); for await (const brew of brews) { const foo = api.getBrew('themes', req=req, res=res, next=next); const brewTheme = req.brew; @@ -164,7 +162,8 @@ const api = { const userID = req?.account?.username && (accessType === 'edit') ? req.account.username : stub.authors[0]; // Clean up brew: fill in missing fields with defaults / fix old invalid values - const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : ''; + const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : {}; + console.log(userThemes); if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings From dfca664f6ea3dd0dfcfdfbb6bcadf0f73d3e19f3 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:53:54 -0600 Subject: [PATCH 035/121] more heroku debug --- server/homebrew.api.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 1c13eb316..1168084aa 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -82,10 +82,6 @@ const api = { } }; - if(!username || !id) { - return userThemes; - } - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme', 'type:theme', 'type:Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects .catch((error)=>{throw 'Can not find brews';}); From 870cbc103dd4af53398d1b030012657e216feb35 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:57:32 -0600 Subject: [PATCH 036/121] more heroku debug --- server/homebrew.api.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 1168084aa..07698800a 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -88,6 +88,9 @@ const api = { for await (const brew of brews) { const foo = api.getBrew('themes', req=req, res=res, next=next); const brewTheme = req.brew; + console.log(`Looking at themes.`); + console.log(brewTheme); + console.log(`Looked at themes.`); if(brewTheme) { splitTextStyleAndMetadata(brewTheme); userThemes.Brew[`#${brew.editId}`] = { From e2ba0ec0599bcaad896f059a5ce7f70ac3617192 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 13:59:36 -0600 Subject: [PATCH 037/121] more heroku debug --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 07698800a..d5746e242 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -89,7 +89,7 @@ const api = { const foo = api.getBrew('themes', req=req, res=res, next=next); const brewTheme = req.brew; console.log(`Looking at themes.`); - console.log(brewTheme); + console.log(foo); console.log(`Looked at themes.`); if(brewTheme) { splitTextStyleAndMetadata(brewTheme); From 47ea2f6ed7658783b3b043ae2174ccd064bc0797 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 14:04:16 -0600 Subject: [PATCH 038/121] more heroku debug --- server/homebrew.api.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index d5746e242..f342735e2 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -170,6 +170,10 @@ const api = { stub.userThemes = userThemes; } + if ( accessType == 'themes' ) { + console.log('Themes loaded'); + console.log(stub); + } req.brew = stub ?? {}; next(); }; From 9adafbd473807a8574827b62f792514b081fc59a Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 14:12:13 -0600 Subject: [PATCH 039/121] more heroku debug --- server/homebrew.api.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index f342735e2..c053fdbdb 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -86,10 +86,10 @@ const api = { .catch((error)=>{throw 'Can not find brews';}); for await (const brew of brews) { - const foo = api.getBrew('themes', req=req, res=res, next=next); + api.getBrew('themes', req=req, res=res, next=next); const brewTheme = req.brew; console.log(`Looking at themes.`); - console.log(foo); + console.log(req); console.log(`Looked at themes.`); if(brewTheme) { splitTextStyleAndMetadata(brewTheme); @@ -111,6 +111,7 @@ const api = { // Get relevant IDs for the brew const { id, googleId } = api.getId(req); + console.log(`id: ${id}`); // Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine. let stub = await HomebrewModel.get(accessType === 'edit' ? { editId: id } : { shareId: id }) From 87502f4249c294fcf575a086108b23ccfef2540e Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 18:55:12 -0600 Subject: [PATCH 040/121] Heavy rework for usertheme parents. --- client/homebrew/brewRenderer/brewRenderer.jsx | 8 ++-- client/homebrew/pages/printPage/printPage.jsx | 9 ++-- server/app.js | 3 +- server/homebrew.api.js | 43 ++++++++----------- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index edc43b040..2d6040e7c 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -200,13 +200,15 @@ const BrewRenderer = (props)=>{ rendererPath += '/'; } - if(baseThemePath && baseThemePath[0] === '#') { - baseThemePath = baseThemePath.slice(1); + if(rendererPath == '') { + baseThemePath = 'Brew'; baseRendererPath = ''; } else { baseRendererPath += '/'; } + const staticOrUserParent = props?.theme[0] == '#' ? `/cssParent/${themePath}` : `/css/${baseRendererPath}${baseThemePath}`; + return ( <> {/*render dummy page while iFrame is mounting.*/} @@ -235,7 +237,7 @@ const BrewRenderer = (props)=>{
{baseThemePath && - + } diff --git a/client/homebrew/pages/printPage/printPage.jsx b/client/homebrew/pages/printPage/printPage.jsx index ea409bd43..954d16e0b 100644 --- a/client/homebrew/pages/printPage/printPage.jsx +++ b/client/homebrew/pages/printPage/printPage.jsx @@ -110,19 +110,20 @@ const PrintPage = createClass({ rendererPath += '/'; } - if(baseThemePath && baseThemePath[0] == '#') { - baseThemePath = baseThemePath.slice(1); + if(rendererPath == '') { + baseThemePath = 'Brew'; baseRendererPath = ''; } else { baseRendererPath += '/'; } - + + const staticOrUserParent = this.state.brew.theme[0] == '#' ? `/cssParent/${themePath}` : `/css/${baseRendererPath}${baseThemePath}`; return
{baseThemePath && - + } {/* Apply CSS from Style tab */} diff --git a/server/app.js b/server/app.js index 91798d808..b0fe3f465 100644 --- a/server/app.js +++ b/server/app.js @@ -9,7 +9,7 @@ const yaml = require('js-yaml'); const app = express(); const config = require('./config.js'); -const { homebrewApi, getBrew, getBrewThemeWithCSS, getStaticTheme } = require('./homebrew.api.js'); +const { homebrewApi, getBrew, getBrewThemeWithCSS, getStaticTheme, getBrewThemeParent } = require('./homebrew.api.js'); const GoogleActions = require('./googleActions.js'); const serveCompressedStaticAssets = require('./static-assets.mv.js'); const sanitizeFilename = require('sanitize-filename'); @@ -94,6 +94,7 @@ app.get('/robots.txt', (req, res)=>{ app.get('/css/:id', asyncHandler(getBrew('edit', true)), asyncHandler(getBrewThemeWithCSS)); app.get('/css/:engine/:id/', asyncHandler(getStaticTheme)); +app.get('/cssParent/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeParent)); //Home page diff --git a/server/homebrew.api.js b/server/homebrew.api.js index c053fdbdb..b2f5f941c 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -86,23 +86,15 @@ const api = { .catch((error)=>{throw 'Can not find brews';}); for await (const brew of brews) { - api.getBrew('themes', req=req, res=res, next=next); - const brewTheme = req.brew; - console.log(`Looking at themes.`); - console.log(req); - console.log(`Looked at themes.`); - if(brewTheme) { - splitTextStyleAndMetadata(brewTheme); - userThemes.Brew[`#${brew.editId}`] = { - name : brew.title, - renderer : 'V3', - baseTheme : brewTheme.theme, - baseSnippets : false, - path : `#${brew.editId}`, - thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' - }; - } - }; + userThemes.Brew[`#${brew.editId}`] = { + name : brew.title, + renderer : 'V3', + baseTheme : '', + baseSnippets : false, + path : `#${brew.editId}`, + thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' + }; + } return userThemes; }, getBrew : (accessType, stubOnly = false)=>{ @@ -111,10 +103,9 @@ const api = { // Get relevant IDs for the brew const { id, googleId } = api.getId(req); - console.log(`id: ${id}`); // Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine. - let stub = await HomebrewModel.get(accessType === 'edit' ? { editId: id } : { shareId: id }) + let stub = await HomebrewModel.get((accessType === 'edit') || (accessType === 'theme') ? { editId: id } : { shareId: id }) .catch((err)=>{ if(googleId) { console.warn(`Unable to find document stub for ${accessType}Id ${id}`); @@ -163,7 +154,6 @@ const api = { // Clean up brew: fill in missing fields with defaults / fix old invalid values const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : {}; - console.log(userThemes); if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings @@ -171,10 +161,6 @@ const api = { stub.userThemes = userThemes; } - if ( accessType == 'themes' ) { - console.log('Themes loaded'); - console.log(stub); - } req.brew = stub ?? {}; next(); }; @@ -293,6 +279,15 @@ const api = { const parentThemeImport = `@import url(\"${req.brew.theme[0] != '#' ? staticTheme : userTheme}\");\n\n/* From Brew: ${req.brew.title}*/\n\n`; return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}${req.brew.style}`); }, + getBrewThemeParent : async (req, res)=>{ + const brew = req.brew; + splitTextStyleAndMetadata(brew); + res.setHeader('Content-Type', 'text/css'); + const staticTheme = `/css/${req.brew.renderer}/${req.brew.theme}`; + const userTheme = `/css/${req.brew.theme.slice(1)}`; + const parentThemeImport = `@import url(\"${req.brew.theme[0] != '#' ? staticTheme : userTheme}\");\n\n/* From Brew: ${req.brew.title}*/\n\n`; + return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}`); + }, getStaticTheme : async(req, res)=>{ const themeParent = isStaticTheme(req.params.engine, req.params.id); if(themeParent === undefined){ From d9dade718131e2d1f8b45c345fc5f4da94975d45 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 19:04:12 -0600 Subject: [PATCH 041/121] Fix User Brew display label in metadata editor --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 573fb00c3..d402d9955 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -226,7 +226,7 @@ const MetadataEditor = createClass({ dropdown =
- {`${_.upperFirst(this.props.metadata.themeClass?this.props.metadata.themeClass:this.props.metadata.renderer)} : ${currentTheme.name}`} + {`${_.upperFirst(currentThemePath)} : ${currentTheme.name}`}
{/*listThemes('Legacy')*/} {listThemes('V3')} From 33933ef21297d4dc3913a0c327b9ba7115316e34 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 19:14:16 -0600 Subject: [PATCH 042/121] Attempted fix on access --- server/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/app.js b/server/app.js index b0fe3f465..d6c56c68b 100644 --- a/server/app.js +++ b/server/app.js @@ -92,7 +92,7 @@ app.get('/robots.txt', (req, res)=>{ // Theme -app.get('/css/:id', asyncHandler(getBrew('edit', true)), asyncHandler(getBrewThemeWithCSS)); +app.get('/css/:id', asyncHandler(getBrew('theme', true)), asyncHandler(getBrewThemeWithCSS)); app.get('/css/:engine/:id/', asyncHandler(getStaticTheme)); app.get('/cssParent/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeParent)); From a666c8def342c1d35a5718b75ff92ab159436174 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 19:20:16 -0600 Subject: [PATCH 043/121] Heroku debug --- server/homebrew.api.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index b2f5f941c..658c0fea0 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -271,6 +271,8 @@ const api = { res.status(200).send(saved); }, getBrewThemeWithCSS : async (req, res)=>{ + console.log('I made it out!'); + console.log(req.brew); const brew = req.brew; splitTextStyleAndMetadata(brew); res.setHeader('Content-Type', 'text/css'); From 1ac510af3dcfcc71ae9a133494be1bf8f978be79 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 19:24:16 -0600 Subject: [PATCH 044/121] Heroku debug --- server/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/app.js b/server/app.js index d6c56c68b..faf557e61 100644 --- a/server/app.js +++ b/server/app.js @@ -92,7 +92,7 @@ app.get('/robots.txt', (req, res)=>{ // Theme -app.get('/css/:id', asyncHandler(getBrew('theme', true)), asyncHandler(getBrewThemeWithCSS)); +app.get('/css/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeWithCSS)); app.get('/css/:engine/:id/', asyncHandler(getStaticTheme)); app.get('/cssParent/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeParent)); From eb4ecf853b43b4979bed6646924f11dd6e3d9152 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 22:50:24 -0600 Subject: [PATCH 045/121] Fix Jest issues I was able to understand --- client/homebrew/brewRenderer/brewRenderer.jsx | 2 +- client/homebrew/pages/printPage/printPage.jsx | 2 +- server/homebrew.api.js | 6 +++--- server/homebrew.api.spec.js | 9 +++++---- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 2d3e5136e..9ab09301b 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -207,7 +207,7 @@ const BrewRenderer = (props)=>{ baseRendererPath += '/'; } - const staticOrUserParent = props?.theme[0] == '#' ? `/cssParent/${themePath}` : `/css/${baseRendererPath}${baseThemePath}`; + const staticOrUserParent = (props.theme && props?.theme[0] == '#') ? `/cssParent/${themePath}` : `/css/${baseRendererPath}${baseThemePath}`; return ( <> diff --git a/client/homebrew/pages/printPage/printPage.jsx b/client/homebrew/pages/printPage/printPage.jsx index cfd3c2318..d9ff2ca1a 100644 --- a/client/homebrew/pages/printPage/printPage.jsx +++ b/client/homebrew/pages/printPage/printPage.jsx @@ -117,7 +117,7 @@ const PrintPage = createClass({ baseRendererPath += '/'; } - const staticOrUserParent = this.state.brew.theme[0] == '#' ? `/cssParent/${themePath}` : `/css/${baseRendererPath}${baseThemePath}`; + const staticOrUserParent = (this.state.brew.theme && this.state.brew?.theme[0] == '#') ? `/cssParent/${themePath}` : `/css/${baseRendererPath}${baseThemePath}`; return
diff --git a/server/homebrew.api.js b/server/homebrew.api.js index b2f5f941c..af5ef259e 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -82,8 +82,7 @@ const api = { } }; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme', 'type:theme', 'type:Theme'] }, editId: { $ne: id } }) //lean() converts results to JSObjects - .catch((error)=>{throw 'Can not find brews';}); + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme', 'type:theme', 'type:Theme'] }, editId: { $ne: id } }); for await (const brew of brews) { userThemes.Brew[`#${brew.editId}`] = { @@ -150,7 +149,8 @@ const api = { throw { name: 'BrewLoad Error', message: 'Brew not found', status: 404, HBErrorCode: '05', accessType: accessType, brewId: id }; } - const userID = req?.account?.username && (accessType === 'edit') ? req.account.username : stub.authors[0]; + const mainAuthor = stub.authors ? stub.authors[0] : ''; + const userID = req?.account?.username && (accessType === 'edit') ? req.account.username : mainAuthor; // Clean up brew: fill in missing fields with defaults / fix old invalid values const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : {}; diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index c82ce5227..c0c2619a2 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -45,8 +45,9 @@ describe('Tests for api', ()=>{ model.mockImplementation((brew)=>modelBrew(brew)); res = { - status : jest.fn(()=>res), - send : jest.fn(()=>{}) + status : jest.fn(()=>res), + send : jest.fn(()=>{}), + setHeader : jest.fn(()=>{}) }; api = require('./homebrew.api'); @@ -611,7 +612,7 @@ brew`); }; api.getStaticTheme(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe('@import /themes/V3/5ePHB/style.css\n'); + expect(sent).toBe('@import url("/themes/V3/5ePHB/style.css");\n/* Static Theme 5e PHB */\n'); expect(res.status).toHaveBeenCalledWith(200); }); it('should return an import of the theme including a parent.', async ()=>{ @@ -623,7 +624,7 @@ brew`); }; api.getStaticTheme(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe('@import /api/css/V3/5ePHB\n@import /themes/V3/5eDMG/style.css\n'); + expect(sent).toBe('@import url("/css/V3/5ePHB");\n/* Static Theme 5e PHB */\n@import url("/themes/V3/5eDMG/style.css");\n/* Static Theme 5e DMG */\n'); expect(res.status).toHaveBeenCalledWith(200); }); it('should fail for an invalid static theme.', async()=>{ From e487f9a9517a035f9aa4edc909835f771853d2b6 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 6 Mar 2024 23:27:43 -0600 Subject: [PATCH 046/121] Fix remaining jest issues --- package-lock.json | 922 ++++++++++++++++-------------------- package.json | 14 +- server/homebrew.api.js | 24 +- server/homebrew.api.spec.js | 7 +- 4 files changed, 425 insertions(+), 542 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4ab132c11..9f39b3bd5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,9 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.24.0", - "@babel/plugin-transform-runtime": "^7.24.0", - "@babel/preset-env": "^7.24.0", + "@babel/core": "^7.23.9", + "@babel/plugin-transform-runtime": "^7.23.9", + "@babel/preset-env": "^7.23.9", "@babel/preset-react": "^7.23.3", "@googleapis/drive": "^8.7.0", "body-parser": "^1.20.2", @@ -22,7 +22,7 @@ "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", "expr-eval": "^2.0.2", - "express": "^4.18.3", + "express": "^4.18.2", "express-async-handler": "^1.2.0", "express-static-gzip": "2.1.7", "fs-extra": "11.2.0", @@ -36,13 +36,13 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.2.1", + "mongoose": "^8.2.0", "nanoid": "3.3.4", "nconf": "^0.12.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-frame-component": "^4.1.3", - "react-router-dom": "6.22.2", + "react-router-dom": "6.22.1", "sanitize-filename": "1.6.3", "superagent": "^8.1.2", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" @@ -50,7 +50,7 @@ "devDependencies": { "eslint": "^8.57.0", "eslint-plugin-jest": "^27.9.0", - "eslint-plugin-react": "^7.34.0", + "eslint-plugin-react": "^7.33.2", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", "postcss-less": "^6.0.0", @@ -107,20 +107,20 @@ } }, "node_modules/@babel/core": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", - "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.0", - "@babel/parser": "^7.24.0", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.0", - "@babel/types": "^7.24.0", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -340,9 +340,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "engines": { "node": ">=6.9.0" } @@ -450,13 +450,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.0.tgz", - "integrity": "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", + "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.0", - "@babel/types": "^7.24.0" + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" @@ -476,9 +476,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", - "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", + "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1242,13 +1242,13 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.0.tgz", - "integrity": "sha512-y/yKMm7buHpFFXfxVFS4Vk1ToRJDilIa6fKRioB9Vjichv58TDGXTvqV0dN7plobAmTW5eSEGXDngE+Mm+uO+w==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-parameters": "^7.23.3" }, @@ -1456,12 +1456,12 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.0.tgz", - "integrity": "sha512-zc0GA5IitLKJrSfXlXmp8KDqLrnGECK7YRfQBmEKg1NmBOQ7e+KuclBEKJgzifQeUYLdNiAw4B4bjyvzWVLiSA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.9.tgz", + "integrity": "sha512-A7clW3a0aSjm3ONU9o2HAILSegJCYlEZmOhmBRReVtIpY/Z/p7yIZ+wR41Z+UipwdGuqwtID/V/dOdZXjwi9gQ==", "dependencies": { "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.22.5", "babel-plugin-polyfill-corejs2": "^0.4.8", "babel-plugin-polyfill-corejs3": "^0.9.0", "babel-plugin-polyfill-regenerator": "^0.5.5", @@ -1605,13 +1605,13 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz", - "integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-plugin-utils": "^7.22.5", "@babel/helper-validator-option": "^7.23.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", @@ -1664,7 +1664,7 @@ "@babel/plugin-transform-new-target": "^7.23.3", "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", "@babel/plugin-transform-numeric-separator": "^7.23.4", - "@babel/plugin-transform-object-rest-spread": "^7.24.0", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", "@babel/plugin-transform-object-super": "^7.23.3", "@babel/plugin-transform-optional-catch-binding": "^7.23.4", "@babel/plugin-transform-optional-chaining": "^7.23.4", @@ -1746,22 +1746,22 @@ } }, "node_modules/@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", - "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/generator": "^7.23.6", @@ -1769,8 +1769,8 @@ "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1779,9 +1779,9 @@ } }, "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", @@ -2838,9 +2838,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz", - "integrity": "sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.1.tgz", + "integrity": "sha512-zcU0gM3z+3iqj8UX45AmWY810l3oUmXM7uH4dt5xtzvMhRtYVhKGOmgOd1877dOPPepfCjUv57w+syamWIYe7w==", "engines": { "node": ">=14.0.0" } @@ -3371,16 +3371,13 @@ } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3392,15 +3389,15 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", "is-string": "^1.0.7" }, "engines": { @@ -3427,34 +3424,15 @@ "node": ">=0.10.0" } }, - "node_modules/array.prototype.findlast": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.4.tgz", - "integrity": "sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -3464,44 +3442,30 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, "node_modules/array.prototype.tosorted": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", - "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.1.0", - "es-shim-unscopables": "^1.0.2" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", "dev": true, "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", "is-shared-array-buffer": "^1.0.2" }, "engines": { @@ -3621,13 +3585,10 @@ } }, "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, "engines": { "node": ">= 0.4" }, @@ -4376,18 +4337,12 @@ "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==" }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5168,29 +5123,12 @@ "node": ">=0.10.0" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", "dev": true, "dependencies": { - "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" }, @@ -5514,52 +5452,50 @@ } }, "node_modules/es-abstract": { - "version": "1.22.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz", - "integrity": "sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", "dev": true, "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "hasown": "^2.0.1", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.3", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", + "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "object-inspect": "^1.12.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.5", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.10" }, "engines": { "node": ">= 0.4" @@ -5568,72 +5504,49 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/es-iterator-helpers": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.17.tgz", - "integrity": "sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.13.tgz", + "integrity": "sha512-LK3VGwzvaPWobO8xzXXGRUOGw8Dcjyfk62CsY/wfHN75CwsJPbuypOYJxK6g5RyEL8YDjIWcl6jgd8foO6mmrA==", "dev": true, "dependencies": { "asynciterator.prototype": "^1.0.0", - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.4", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.3", + "es-set-tostringtag": "^2.0.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.2.1", "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.2", + "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" + "internal-slot": "^1.0.5", + "iterator.prototype": "^1.1.0", + "safe-array-concat": "^1.0.0" } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", "dev": true, "dependencies": { - "hasown": "^2.0.0" + "has": "^1.0.3" } }, "node_modules/es-to-primitive": { @@ -5755,29 +5668,27 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.0.tgz", - "integrity": "sha512-MeVXdReleBTdkz/bvcQMSnCXGi+c9kvy51IpinjnJgutl3YTHWsDdke7Z1ufZpGfDG8xduBDKyjtB9JH1eBKIQ==", + "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", "dev": true, "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlast": "^1.2.4", - "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", - "array.prototype.tosorted": "^1.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.17", + "es-iterator-helpers": "^1.0.12", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7", - "object.hasown": "^1.1.3", - "object.values": "^1.1.7", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", + "resolve": "^2.0.0-next.4", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.10" + "string.prototype.matchall": "^4.0.8" }, "engines": { "node": ">=4" @@ -5799,12 +5710,12 @@ } }, "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", "dev": true, "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -6132,13 +6043,13 @@ "integrity": "sha512-4EMSHGOPSwAfBiibw3ndnP0AvjDWLsMvGOvWEZ2F96IGk0bIVdjQisOHxReSkE13mHcfbuCiXw+G4y0zv6N8Eg==" }, "node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -6185,6 +6096,29 @@ "serve-static": "^1.14.1" } }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/express/node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -6206,6 +6140,20 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -6570,23 +6518,20 @@ } }, "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -6652,18 +6597,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", + "function-bind": "^1.1.1", + "has": "^1.0.3", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" + "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6691,14 +6632,13 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -6906,6 +6846,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -6974,20 +6915,21 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, "dependencies": { - "es-define-property": "^1.0.0" + "get-intrinsic": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", "engines": { "node": ">= 0.4" }, @@ -7007,12 +6949,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, "dependencies": { - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7090,17 +7032,6 @@ "minimalistic-assert": "^1.0.1" } }, - "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/hexoid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", @@ -7432,13 +7363,13 @@ } }, "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "dev": true, "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", "side-channel": "^1.0.4" }, "engines": { @@ -7476,16 +7407,14 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7569,11 +7498,11 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dependencies": { - "hasown": "^2.0.0" + "has": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7718,9 +7647,9 @@ } }, "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true, "engines": { "node": ">= 0.4" @@ -7807,15 +7736,12 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" + "call-bind": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7863,12 +7789,16 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", "dev": true, "dependencies": { - "which-typed-array": "^1.1.14" + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -8064,16 +7994,16 @@ } }, "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.0.tgz", + "integrity": "sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw==", "dev": true, "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", + "define-properties": "^1.1.4", + "get-intrinsic": "^1.1.3", "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" + "has-tostringtag": "^1.0.0", + "reflect.getprototypeof": "^1.0.3" } }, "node_modules/jest": { @@ -10529,9 +10459,9 @@ } }, "node_modules/mongoose": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.2.1.tgz", - "integrity": "sha512-UgZZbXSJH0pdU936qj3FyVI+sBsMoGowFnL5R/RYrA50ayn6+ZYdVr8ehsRgNxRcMYwoNld5XzHIfkFRJTePEw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.2.0.tgz", + "integrity": "sha512-la93n6zCYRbPS+c5N9oTDAktvREy5OT9OCljp1Tah0y3+p8UPMTAoabWaLZMdzYruOtF9/9GRf6MasaZjiZP1A==", "dependencies": { "bson": "^6.2.0", "kareem": "2.5.1", @@ -11072,9 +11002,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -11100,13 +11030,13 @@ } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, @@ -11118,28 +11048,28 @@ } }, "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" @@ -11149,13 +11079,13 @@ } }, "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", "dev": true, "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -11173,14 +11103,14 @@ } }, "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" @@ -11552,15 +11482,6 @@ "node": ">=0.10.0" } }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -11958,11 +11879,11 @@ "dev": true }, "node_modules/react-router": { - "version": "6.22.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.2.tgz", - "integrity": "sha512-YD3Dzprzpcq+tBMHBS822tCjnWD3iIZbTeSXMY9LPSG541EfoBGyZ3bS25KEnaZjLcmQpw2AVLkFyfgXY8uvcw==", + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.1.tgz", + "integrity": "sha512-0pdoRGwLtemnJqn1K0XHUbnKiX0S4X8CgvVVmHGOWmofESj31msHo/1YiqcJWK7Wxfq2a4uvvtS01KAQyWK/CQ==", "dependencies": { - "@remix-run/router": "1.15.2" + "@remix-run/router": "1.15.1" }, "engines": { "node": ">=14.0.0" @@ -11972,12 +11893,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.22.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.2.tgz", - "integrity": "sha512-WgqxD2qySEIBPZ3w0sHH+PUAiamDeszls9tzqMPBDA1YYVucTBXLU7+gtRfcSnhe92A3glPnvSxK2dhNoAVOIQ==", + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.1.tgz", + "integrity": "sha512-iwMyyyrbL7zkKY7MRjOVRy+TMnS/OPusaFVxM2P11x9dzSzGmLsebkCvYirGq0DWB9K9hOspHYYtDz33gE5Duw==", "dependencies": { - "@remix-run/router": "1.15.2", - "react-router": "6.22.2" + "@remix-run/router": "1.15.1", + "react-router": "6.22.1" }, "engines": { "node": ">=14.0.0" @@ -12122,16 +12043,15 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", - "integrity": "sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.3.tgz", + "integrity": "sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0", - "get-intrinsic": "^1.2.3", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.1", "globalthis": "^1.0.3", "which-builtin-type": "^1.1.3" }, @@ -12207,15 +12127,14 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -12424,13 +12343,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -12475,18 +12394,15 @@ } }, "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", "is-regex": "^1.1.4" }, - "engines": { - "node": ">= 0.4" - }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12580,37 +12496,6 @@ "node": ">= 0.8.0" } }, - "node_modules/set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", - "dependencies": { - "define-data-property": "^1.1.2", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -13264,19 +13149,18 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", "side-channel": "^1.0.4" }, "funding": { @@ -13284,14 +13168,14 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" @@ -13301,28 +13185,28 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14066,30 +13950,29 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.2", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" }, "engines": { "node": ">= 0.4" @@ -14099,17 +13982,16 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" }, "engines": { "node": ">= 0.4" @@ -14119,20 +14001,14 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.2", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "is-typed-array": "^1.1.9" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14980,16 +14856,16 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", - "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" diff --git a/package.json b/package.json index 9b9b17ca0..b44d1cc4d 100644 --- a/package.json +++ b/package.json @@ -80,9 +80,9 @@ ] }, "dependencies": { - "@babel/core": "^7.24.0", - "@babel/plugin-transform-runtime": "^7.24.0", - "@babel/preset-env": "^7.24.0", + "@babel/core": "^7.23.9", + "@babel/plugin-transform-runtime": "^7.23.9", + "@babel/preset-env": "^7.23.9", "@babel/preset-react": "^7.23.3", "@googleapis/drive": "^8.7.0", "body-parser": "^1.20.2", @@ -92,7 +92,7 @@ "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", "expr-eval": "^2.0.2", - "express": "^4.18.3", + "express": "^4.18.2", "express-async-handler": "^1.2.0", "express-static-gzip": "2.1.7", "fs-extra": "11.2.0", @@ -106,13 +106,13 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.2.1", + "mongoose": "^8.2.0", "nanoid": "3.3.4", "nconf": "^0.12.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-frame-component": "^4.1.3", - "react-router-dom": "6.22.2", + "react-router-dom": "6.22.1", "sanitize-filename": "1.6.3", "superagent": "^8.1.2", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" @@ -120,7 +120,7 @@ "devDependencies": { "eslint": "^8.57.0", "eslint-plugin-jest": "^27.9.0", - "eslint-plugin-react": "^7.34.0", + "eslint-plugin-react": "^7.33.2", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", "postcss-less": "^6.0.0", diff --git a/server/homebrew.api.js b/server/homebrew.api.js index af5ef259e..cb9176a72 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -9,6 +9,7 @@ const yaml = require('js-yaml'); const asyncHandler = require('express-async-handler'); const { nanoid } = require('nanoid'); + const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); const themes = require('../themes/themes.json'); @@ -66,7 +67,7 @@ const api = { } return { id, googleId }; }, - getUsersBrewThemes : async (username, id, req, res, next)=>{ + getUsersBrewThemes : async (username, id)=>{ const fields = [ 'title', 'tags', @@ -84,16 +85,19 @@ const api = { const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme', 'type:theme', 'type:Theme'] }, editId: { $ne: id } }); - for await (const brew of brews) { - userThemes.Brew[`#${brew.editId}`] = { - name : brew.title, - renderer : 'V3', - baseTheme : '', - baseSnippets : false, - path : `#${brew.editId}`, - thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' - }; + if(brews) { + for await (const brew of brews) { + userThemes.Brew[`#${brew.editId}`] = { + name : brew.title, + renderer : 'V3', + baseTheme : '', + baseSnippets : false, + path : `#${brew.editId}`, + thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' + }; + } } + return userThemes; }, getBrew : (accessType, stubOnly = false)=>{ diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index c0c2619a2..9c9813a91 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -287,6 +287,9 @@ describe('Tests for api', ()=>{ thumbnail : '', textBin : undefined, version : undefined, + userThemes : { + Brew: {} + }, createdAt : undefined, gDrive : false, style : undefined, @@ -581,7 +584,7 @@ brew`); api.getBrewThemeWithCSS(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe(`// From Theme: test brew\n\n@import /api/css/V3/5ePHB/styles.css\n\nI Have a style!`); + expect(sent).toBe(`@import url("/css/V3/5ePHB");\n\n/* From Brew: test brew*/\n\nI Have a style!`); expect(res.status).toHaveBeenCalledWith(200); }); }); @@ -597,7 +600,7 @@ brew`); api.getBrewThemeWithCSS(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe(`// From Theme: test brew\n\n@import /api/css/IamATheme\n\nI Have a style!`); + expect(sent).toBe(`@import url("/css/IamATheme");\n\n/* From Brew: test brew*/\n\nI Have a style!`); expect(res.status).toHaveBeenCalledWith(200); }); }); From f2f32c35eacc36c4b25559d29f604213eb2f5da2 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 10 Mar 2024 11:54:48 -0500 Subject: [PATCH 047/121] Ensure shared pages work with user themes. --- client/homebrew/pages/sharePage/sharePage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 981ad0126..07a1940fb 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -81,7 +81,7 @@ const SharePage = createClass({
- +
; } From 3dde6a098cccaff29813fa063297dcafcde59f02 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 6 May 2024 12:12:46 -0500 Subject: [PATCH 048/121] Test code to reduce duplicate theme loading This shorts out loading of 5ePHB and/or blank from getBrewThemeParent --- server/homebrew.api.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index d0966194c..fff9784b6 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -290,6 +290,8 @@ const api = { getBrewThemeParent : async (req, res)=>{ const brew = req.brew; splitTextStyleAndMetadata(brew); + // Test Hard Ignoring 5ePHB and 5eBlank due to being used for editor theming. + if((req.brew.theme == '5ePHB') ||(req.brew.theme == 'Blank')) return res.status(200).send(''); res.setHeader('Content-Type', 'text/css'); const staticTheme = `/css/${req.brew.renderer}/${req.brew.theme}`; const userTheme = `/css/${req.brew.theme.slice(1)}`; From c9d416fec0f445bf1b7a353b4db244a90ba02b2b Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 6 May 2024 19:39:27 -0500 Subject: [PATCH 049/121] Small User Brew theme changes. Move the Static Theme shortcut to getBrewThemeWithCSS to drop an unneeded URL load. Change the comment in the CSS to refer to the shareURL for the theme instead of its name if it is a user theme. --- server/homebrew.api.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index fff9784b6..b87efe8d0 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -8,6 +8,7 @@ const Markdown = require('../shared/naturalcrit/markdown.js'); const yaml = require('js-yaml'); const asyncHandler = require('express-async-handler'); const { nanoid } = require('nanoid'); +var url = require('url'); const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); @@ -282,21 +283,21 @@ const api = { const brew = req.brew; splitTextStyleAndMetadata(brew); res.setHeader('Content-Type', 'text/css'); - const staticTheme = `/css/${req.brew.renderer}/${req.brew.theme}`; - const userTheme = `/css/${req.brew.theme.slice(1)}`; - const parentThemeImport = `@import url(\"${req.brew.theme[0] != '#' ? staticTheme : userTheme}\");\n\n/* From Brew: ${req.brew.title}*/\n\n`; - return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}${req.brew.style}`); + const themePath = req.brew.theme[0] != '#' ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme.slice(1)}`; + // Drop Parent theme if it has already been loaded. + // This assumes the continued use of the V3/5ePHB and V3/Blank themes for the app. + const parentThemeImport = ((req.brew.theme != '5ePHB') && (req.brew.theme != 'Blank')) ? `@import url(\"${themePath}\");\n\n`:''; + const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; + return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}${req.brew.style}`); }, getBrewThemeParent : async (req, res)=>{ const brew = req.brew; splitTextStyleAndMetadata(brew); - // Test Hard Ignoring 5ePHB and 5eBlank due to being used for editor theming. - if((req.brew.theme == '5ePHB') ||(req.brew.theme == 'Blank')) return res.status(200).send(''); res.setHeader('Content-Type', 'text/css'); - const staticTheme = `/css/${req.brew.renderer}/${req.brew.theme}`; - const userTheme = `/css/${req.brew.theme.slice(1)}`; - const parentThemeImport = `@import url(\"${req.brew.theme[0] != '#' ? staticTheme : userTheme}\");\n\n/* From Brew: ${req.brew.title}*/\n\n`; - return res.status(200).send(`${req.brew.renderer == 'legacy' ? '' : parentThemeImport}`); + const themePath = req.brew.theme[0] != '#' ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme.slice(1)}`; + const parentThemeImport = `@import url(\"${themePath}\");\n\n`; + const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; + return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}{themeLocationComment}`); }, getStaticTheme : async(req, res)=>{ const themeParent = isStaticTheme(req.params.engine, req.params.id); From 9f04c34b064532203191f701ba87f9509bca303e Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 6 May 2024 20:07:33 -0500 Subject: [PATCH 050/121] Missed $ --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index b87efe8d0..1342d0e57 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -297,7 +297,7 @@ const api = { const themePath = req.brew.theme[0] != '#' ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme.slice(1)}`; const parentThemeImport = `@import url(\"${themePath}\");\n\n`; const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; - return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}{themeLocationComment}`); + return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}`); }, getStaticTheme : async(req, res)=>{ const themeParent = isStaticTheme(req.params.engine, req.params.id); From f936b8b12bde21a209b668bdd68eeacf8f7da1b9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 6 May 2024 20:28:46 -0500 Subject: [PATCH 051/121] Update User brew endpoint tests --- server/homebrew.api.spec.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index f5379f43f..e55866477 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -588,15 +588,15 @@ brew`); describe('getBrewThemeWithStaticParent', ()=>{ it('should collect parent theme and brew style - returning as css with static parent imported.', async ()=>{ const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); - model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', style: 'I Have a style!' })); + model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', theme: '5eDMG', shareId: 'iAmAUserTheme', style: 'I Have a style!' })); const fn = api.getBrew('share', true); - const req = { brew: {} }; + const req = { brew: {}, get: ()=>{return 'localhost';}, protocol: 'https' }; const next = jest.fn(); await fn(req, null, next); api.getBrewThemeWithCSS(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe(`@import url("/css/V3/5ePHB");\n\n/* From Brew: test brew*/\n\nI Have a style!`); + expect(sent).toBe(`@import url("/css/V3/5eDMG");\n\n/* From Brew: https://localhost/share/iAmAUserTheme */\n\nI Have a style!`); expect(res.status).toHaveBeenCalledWith(200); }); }); @@ -604,15 +604,15 @@ brew`); describe('getBrewThemeWithUserParent', ()=>{ it('should collect parent theme and brew style - returning as css with user-theme parent imported.', async ()=>{ const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); - model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', theme: '#IamATheme', style: 'I Have a style!' })); + model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', shareId: 'iAmAUserTheme', theme: '#IamATheme', style: 'I Have a style!' })); const fn = api.getBrew('share', true); - const req = { brew: {} }; + const req = { brew: {}, get: ()=>{return 'localhost';}, protocol: 'https' }; const next = jest.fn(); await fn(req, null, next); api.getBrewThemeWithCSS(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe(`@import url("/css/IamATheme");\n\n/* From Brew: test brew*/\n\nI Have a style!`); + expect(sent).toBe(`@import url("/css/IamATheme");\n\n/* From Brew: https://localhost/share/iAmAUserTheme */\n\nI Have a style!`); expect(res.status).toHaveBeenCalledWith(200); }); }); From 295fea7581b7840808f11a5bbb021d21fbad842e Mon Sep 17 00:00:00 2001 From: Gazook89 Date: Tue, 7 May 2024 11:00:20 -0500 Subject: [PATCH 052/121] Add dropdownTexture for user theme options If a user theme document has a thumbnail, this will include that thumbnail as a dropdown texture in the options. --- .../editor/metadataEditor/metadataEditor.jsx | 5 +++- .../editor/metadataEditor/metadataEditor.less | 25 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index d402d9955..61efa81c1 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -200,9 +200,12 @@ const MetadataEditor = createClass({ const listThemes = (renderer)=>{ return _.map(_.values(mergedThemes[renderer]), (theme)=>{ const preview = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; + const texture = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`; return
this.handleTheme(theme, renderer)} title={''}> {`${renderer} : ${theme.name}`} - +
+ +
{`${theme.name}`} preview
diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 7f7ce3060..23e6f4415 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -230,14 +230,23 @@ &:hover > .preview { opacity: 1; } - >img { - mask-image : linear-gradient(90deg, transparent, black 20%); - -webkit-mask-image : linear-gradient(90deg, transparent, black 20%); - position : absolute; - right : 0; - top : 0px; - width : 50%; - height : 100%; + .texture-container { + position: absolute; + width: 100%; + height: 100%; + min-height: 100%; + top: 0; + left: 0; + overflow: hidden; + > img { + mask-image : linear-gradient(90deg, transparent, black 20%); + -webkit-mask-image : linear-gradient(90deg, transparent, black 20%); + position : absolute; + right : 0; + top : 0px; + width : 50%; + min-height: 100%; + } } } } From 872ee339da31d0848363db1790feb291bc157541 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 7 May 2024 12:13:57 -0500 Subject: [PATCH 053/121] Clean up console logs Eliminate erroronous theme pulldown texture load. --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 2 +- client/homebrew/pages/newPage/newPage.jsx | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index d402d9955..3de011f50 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -202,7 +202,7 @@ const MetadataEditor = createClass({ const preview = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; return
this.handleTheme(theme, renderer)} title={''}> {`${renderer} : ${theme.name}`} - +
{`${theme.name}`} preview
diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 9fd82b282..e6809bb22 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -139,8 +139,6 @@ const NewPage = createClass({ isSaving : true }); - console.log('saving new brew'); - let brew = this.state.brew; // Split out CSS to Style if CSS codefence exists if(brew.text.startsWith('```css') && brew.text.indexOf('```\n\n') > 0) { @@ -150,17 +148,13 @@ const NewPage = createClass({ } brew.pageCount=((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1; - console.log('Running post.'); const res = await request .post(`/api${this.state.saveGoogle ? '?saveToGoogle=true' : ''}`) .send(brew) .catch((err)=>{ - console.log(err); this.setState({ isSaving: false, error: err }); }); - console.log('Post completed'); if(!res) return; - console.log('Had results!'); brew = res.body; localStorage.removeItem(BREWKEY); From 65495b4e7c59e326ebf5598fdeb5d4de02e31622 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 8 May 2024 12:51:10 -0500 Subject: [PATCH 054/121] Prevent Legacy renderer brews from being listed as themes. --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 1342d0e57..fcf2507ee 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -84,7 +84,7 @@ const api = { } }; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme', 'type:theme', 'type:Theme'] }, editId: { $ne: id } }); + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme', 'type:theme', 'type:Theme'] }, editId: { $ne: id }, renderer: { $ne: 'Legacy' } }); if(brews) { for await (const brew of brews) { From b6c2f96b823621aee06af4b5a9683796613ec89d Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 10 May 2024 01:40:01 -0400 Subject: [PATCH 055/121] Change tag filtering for theme detection to require meta prefix --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index fcf2507ee..bfe847a38 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -84,7 +84,7 @@ const api = { } }; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['theme', 'Theme', 'type:theme', 'type:Theme'] }, editId: { $ne: id }, renderer: { $ne: 'Legacy' } }); + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] }, editId: { $ne: id }, renderer: { $ne: 'Legacy' } }); if(brews) { for await (const brew of brews) { From 8c5f4e06058db9c8323c61d1c815ab9aed8543f5 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 13 May 2024 11:14:35 -0500 Subject: [PATCH 056/121] Brew Theme Fixes. This adds the User Brew themes, where applicible, to the /new path. This adds a semi-graceful failure to the metadata panel when a Brew Theme is declared as used but is not present. More gracefully handles loading with themes not present. --- client/homebrew/brewRenderer/brewRenderer.jsx | 3 +-- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 3 ++- client/homebrew/pages/printPage/printPage.jsx | 2 +- server/app.js | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 9ab09301b..e1eed42d2 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -189,7 +189,7 @@ const BrewRenderer = (props)=>{ } let themePath = props.theme ?? '5ePHB'; const Themes = { ...staticThemes, ...props.userThemes }; - let baseThemePath = Themes[rendererPath][themePath]?.baseTheme; + let baseThemePath = (themePath && themePath[0] !== '#') ? Themes[rendererPath][themePath]?.baseTheme : 'Brew'; // Override static theme values if a Brew theme. @@ -201,7 +201,6 @@ const BrewRenderer = (props)=>{ } if(rendererPath == '') { - baseThemePath = 'Brew'; baseRendererPath = ''; } else { baseRendererPath += '/'; diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 61efa81c1..93dcd11c8 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -215,7 +215,8 @@ const MetadataEditor = createClass({ }; const currentThemePath = this.props.metadata?.theme && this.props.metadata.theme[0] === '#' ? 'Brew' : this.props.metadata.renderer; - const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme]; +// const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme]; + const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`].hasOwnProperty(this.props.metadata.theme) ? mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme] : { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme.slice(1)}`}; let dropdown; if(this.props.metadata.renderer == 'legacy') { diff --git a/client/homebrew/pages/printPage/printPage.jsx b/client/homebrew/pages/printPage/printPage.jsx index d9ff2ca1a..c21807343 100644 --- a/client/homebrew/pages/printPage/printPage.jsx +++ b/client/homebrew/pages/printPage/printPage.jsx @@ -99,7 +99,7 @@ const PrintPage = createClass({ } let themePath = this.state.brew.theme ?? '5ePHB'; const Themes = { ...staticThemes, ...this.state.brew.userThemes }; - let baseThemePath = Themes[rendererPath][themePath]?.baseTheme; + let baseThemePath = (themePath && themePath[0] !== '#') ? Themes[rendererPath][themePath]?.baseTheme : 'Brew'; // Override static theme values if a Brew theme. diff --git a/server/app.js b/server/app.js index e5b802c72..8a8b67b50 100644 --- a/server/app.js +++ b/server/app.js @@ -300,6 +300,7 @@ app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{ renderer : req.brew.renderer, theme : req.brew.theme, tags : req.brew.tags, + userThemes : req.brew.userThemes }; req.brew = _.defaults(brew, DEFAULT_BREW); From 66e39d9c65a075e4cad0c60a7d6783f67f403100 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 13 May 2024 22:24:41 -0500 Subject: [PATCH 057/121] Update Theme Selector display For User/Brew Themes, display the first author instead of Brew/V3 in the first column. --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 4 ++-- server/homebrew.api.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 93dcd11c8..7cc5257f3 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -202,7 +202,7 @@ const MetadataEditor = createClass({ const preview = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; const texture = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`; return
this.handleTheme(theme, renderer)} title={''}> - {`${renderer} : ${theme.name}`} + {`${theme?.author ? theme.author : renderer} : ${theme.name}`}
@@ -230,7 +230,7 @@ const MetadataEditor = createClass({ dropdown =
- {`${_.upperFirst(currentThemePath)} : ${currentTheme.name}`} + {`${currentTheme?.author ? currentTheme.author : _.upperFirst(currentThemePath)} : ${currentTheme.name}`}
{/*listThemes('Legacy')*/} {listThemes('V3')} diff --git a/server/homebrew.api.js b/server/homebrew.api.js index bfe847a38..8b0f35147 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -75,7 +75,8 @@ const api = { 'editId', 'thumbnail', 'textBin', - 'text' + 'text', + 'authors' ]; const userThemes = { @@ -93,6 +94,7 @@ const api = { renderer : 'V3', baseTheme : '', baseSnippets : false, + author : brew.authors[0], path : `#${brew.editId}`, thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' }; From 69f01b282a316c6297110fe66db372c26c5b585a Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 13 May 2024 22:33:58 -0500 Subject: [PATCH 058/121] CSS Tweaks for Theme Selector Add 5e-Cleric's suggestsions to acvoid the title overflowing over the preview. --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 2 +- client/homebrew/editor/metadataEditor/metadataEditor.less | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 7cc5257f3..586658050 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -202,7 +202,7 @@ const MetadataEditor = createClass({ const preview = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; const texture = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`; return
this.handleTheme(theme, renderer)} title={''}> - {`${theme?.author ? theme.author : renderer} : ${theme.name}`} +

{`${theme?.author ? theme.author : renderer} : ${theme.name}`}

diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.less b/client/homebrew/editor/metadataEditor/metadataEditor.less index 23e6f4415..b157890b1 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.less +++ b/client/homebrew/editor/metadataEditor/metadataEditor.less @@ -191,6 +191,13 @@ color : white; } } + .navDropdown .item > p { + width: 45%; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + height: 1.1em; + } .navDropdown { box-shadow : 0px 5px 10px rgba(0, 0, 0, 0.3); position : absolute; From c6f62142e1fadb4ee6f4c9ed864e84e04f543948 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 17 May 2024 20:53:06 -0500 Subject: [PATCH 059/121] Change the ID used for User Brews to the shareId for future-proofing. --- server/homebrew.api.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 8b0f35147..66adb3267 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -72,7 +72,7 @@ const api = { const fields = [ 'title', 'tags', - 'editId', + 'shareId', 'thumbnail', 'textBin', 'text', @@ -85,17 +85,17 @@ const api = { } }; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] }, editId: { $ne: id }, renderer: { $ne: 'Legacy' } }); + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] }, shareId: { $ne: id }, renderer: { $ne: 'Legacy' } }); if(brews) { for await (const brew of brews) { - userThemes.Brew[`#${brew.editId}`] = { + userThemes.Brew[`#${brew.shareId}`] = { name : brew.title, renderer : 'V3', baseTheme : '', baseSnippets : false, author : brew.authors[0], - path : `#${brew.editId}`, + path : `#${brew.shareId}`, thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' }; } @@ -111,7 +111,7 @@ const api = { const { id, googleId } = api.getId(req); // Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine. - let stub = await HomebrewModel.get((accessType === 'edit') || (accessType === 'theme') ? { editId: id } : { shareId: id }) + let stub = await HomebrewModel.get((accessType === 'edit') ? { editId: id } : { shareId: id }) .catch((err)=>{ if(googleId) { console.warn(`Unable to find document stub for ${accessType}Id ${id}`); From 54d2709d6a14be69c42a12e43d7d00fd5245bf86 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 20 May 2024 17:58:22 -0500 Subject: [PATCH 060/121] Merge --- client/homebrew/brewRenderer/brewRenderer.jsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 97542a58c..7d50e0e3f 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -14,14 +14,10 @@ const NotificationPopup = require('./notificationPopup/notificationPopup.jsx'); const Frame = require('react-frame-component').default; const dedent = require('dedent-tabs').default; -<<<<<<< HEAD -const staticThemes = require('themes/themes.json'); -======= const DOMPurify = require('dompurify'); const purifyConfig = { FORCE_BODY: true, SANITIZE_DOM: false }; -const Themes = require('themes/themes.json'); ->>>>>>> master +const staticThemes = require('themes/themes.json'); const PAGE_HEIGHT = 1056; From 6464f35ce916899caf05f29fa6fbf49980bccf03 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 31 May 2024 22:40:22 -0500 Subject: [PATCH 061/121] Forgot to run npm install after merge --- package-lock.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 145809f3e..74d1260fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "cookie-parser": "^1.4.6", "create-react-class": "^15.7.0", "dedent-tabs": "^0.10.3", - "dompurify": "^3.1.1", + "dompurify": "^3.1.4", "expr-eval": "^2.0.2", "express": "^4.19.2", "express-async-handler": "^1.2.0", @@ -44,7 +44,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-frame-component": "^4.1.3", - "react-router-dom": "6.23.0", + "react-router-dom": "6.23.1", "sanitize-filename": "1.6.3", "superagent": "^9.0.2", "vitreum": "git+https://git@github.com/calculuschild/vitreum.git" @@ -2824,9 +2824,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.0.tgz", - "integrity": "sha512-Quz1KOffeEf/zwkCBM3kBtH4ZoZ+pT3xIXBG4PPW/XFtDP7EGhtTiC2+gpL9GnR7+Qdet5Oa6cYSvwKYg6kN9Q==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", + "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", "engines": { "node": ">=14.0.0" } @@ -11565,11 +11565,11 @@ "dev": true }, "node_modules/react-router": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.0.tgz", - "integrity": "sha512-wPMZ8S2TuPadH0sF5irFGjkNLIcRvOSaEe7v+JER8508dyJumm6XZB1u5kztlX0RVq6AzRVndzqcUh6sFIauzA==", + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", + "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", "dependencies": { - "@remix-run/router": "1.16.0" + "@remix-run/router": "1.16.1" }, "engines": { "node": ">=14.0.0" @@ -11579,12 +11579,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.0.tgz", - "integrity": "sha512-Q9YaSYvubwgbal2c9DJKfx6hTNoBp3iJDsl+Duva/DwxoJH+OTXkxGpql4iUK2sla/8z4RpjAm6EWx1qUDuopQ==", + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", + "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", "dependencies": { - "@remix-run/router": "1.16.0", - "react-router": "6.23.0" + "@remix-run/router": "1.16.1", + "react-router": "6.23.1" }, "engines": { "node": ">=14.0.0" From 7a349ae26dd8faa831bc580dda2967eebda43d4c Mon Sep 17 00:00:00 2001 From: David Bolack Date: Thu, 13 Jun 2024 18:13:32 -0500 Subject: [PATCH 062/121] Remove weirdly redundant error box. --- client/homebrew/brewRenderer/brewRenderer.jsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index c26bd5e18..7eae3228f 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -244,11 +244,6 @@ const BrewRenderer = (props)=>{ tabIndex={-1} style={{ height: state.height }}> - -
- - -
{baseThemePath && From 8570335d7915aa8801dd046ed8b2c5242289390c Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 5 Jul 2024 16:53:21 -0500 Subject: [PATCH 063/121] Consolidate variable redundancy. --- client/homebrew/brewRenderer/brewRenderer.jsx | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 7eae3228f..9e4b79803 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -188,32 +188,24 @@ const BrewRenderer = (props)=>{ document.dispatchEvent(new MouseEvent('click')); }; - let rendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; - let baseRendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; - const blankRendererPath = props.renderer == 'V3' ? 'V3' : 'Legacy'; + let brewThemeRendererPath = props?.renderer ? props.renderer : 'Legacy'; if(props?.theme && (props?.theme[0] === '#')) { - rendererPath = 'Brew'; + brewThemeRendererPath = 'Brew'; } let themePath = props.theme ?? '5ePHB'; const Themes = { ...staticThemes, ...props.userThemes }; - let baseThemePath = (themePath && themePath[0] !== '#') ? Themes[rendererPath][themePath]?.baseTheme : 'Brew'; + const baseThemePath = (themePath && themePath[0] !== '#') ? Themes[brewThemeRendererPath][themePath]?.baseTheme : 'Brew'; // Override static theme values if a Brew theme. if(themePath && themePath[0] === '#') { themePath = themePath.slice(1); - rendererPath = ''; + brewThemeRendererPath = ''; } else { - rendererPath += '/'; + brewThemeRendererPath += '/'; } - if(rendererPath == '') { - baseRendererPath = ''; - } else { - baseRendererPath += '/'; - } - - const staticOrUserParent = (props.theme && props?.theme[0] == '#') ? `/cssParent/${themePath}` : `/css/${baseRendererPath}${baseThemePath}`; + const staticOrUserParent = (props.theme && props?.theme[0] == '#') ? `/cssParent/${themePath}` : `/css/${brewThemeRendererPath}${baseThemePath}`; return ( <> @@ -244,11 +236,11 @@ const BrewRenderer = (props)=>{ tabIndex={-1} style={{ height: state.height }}> - + {baseThemePath && } - + {/* Apply CSS from Style tab and render pages from Markdown tab */} {state.isMounted From 656edb07ea3746bb4aadebecc572208cf4ac5503 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 8 Jul 2024 18:12:58 -0500 Subject: [PATCH 064/121] Rework detection of user brews to look up themeid in static themes list before assuming is a user brew. Ended up being a fairly straightforward change. A few ternaries got smooshed or inverted. Passes builtin and local tests. Need to compare on the test instance. --- client/homebrew/brewRenderer/brewRenderer.jsx | 25 ++++++++----------- .../editor/metadataEditor/metadataEditor.jsx | 3 +-- .../homebrew/editor/snippetbar/snippetbar.jsx | 2 +- server/homebrew.api.js | 8 +++--- server/homebrew.api.spec.js | 2 +- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index d87e720c1..918fdb5c9 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -188,27 +188,24 @@ const BrewRenderer = (props)=>{ document.dispatchEvent(new MouseEvent('click')); }; - let brewThemeRendererPath = props?.renderer ? props.renderer : 'Legacy'; - // Correct for casing vs theme.json - if(brewThemeRendererPath == 'legacy') { brewThemeRendererPath = 'Legacy'; } - if(props?.theme && (props?.theme[0] === '#')) { - brewThemeRendererPath = 'Brew'; - } + let brewThemeRendererPath = `${props?.renderer ? _.upperFirst(props.renderer) : 'V3'}`; + let themePath = props.theme ?? '5ePHB'; const Themes = { ...staticThemes, ...props.userThemes }; - const baseThemePath = (themePath && themePath[0] !== '#') ? Themes[brewThemeRendererPath][themePath].baseTheme : 'Brew'; + let staticOrUserParent; + let baseThemePath = null; - // Override static theme values if a Brew theme. - - if(themePath && themePath[0] === '#') { - themePath = themePath.slice(1); + if (!Themes[brewThemeRendererPath].hasOwnProperty(themePath)) { brewThemeRendererPath = ''; + staticOrUserParent = `/cssParent/${themePath}`; + baseThemePath = 'Brew'; } else { + baseThemePath = Themes[brewThemeRendererPath][themePath].baseTheme brewThemeRendererPath += '/'; + staticOrUserParent = `/css/${brewThemeRendererPath}${baseThemePath}`; + } - const staticOrUserParent = (props.theme && props?.theme[0] == '#') ? `/cssParent/${themePath}` : `/css/${brewThemeRendererPath}${baseThemePath}`; - return ( <> {/*render dummy page while iFrame is mounting.*/} @@ -238,7 +235,7 @@ const BrewRenderer = (props)=>{ tabIndex={-1} style={{ height: state.height }}> - + {baseThemePath && } diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 14a61800b..8f236b833 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -213,8 +213,7 @@ const MetadataEditor = createClass({ }); }; - const currentThemePath = this.props.metadata?.theme && this.props.metadata.theme[0] === '#' ? 'Brew' : this.props.metadata.renderer; -// const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme]; + const currentThemePath = this.props.metadata?.theme && Themes[_.upperFirst(this.props.metadata.renderer)].hasOwnProperty(this.props.metadata?.theme) ? this.props.metadata.renderer : 'Brew'; const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`].hasOwnProperty(this.props.metadata.theme) ? mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme] : { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme.slice(1)}`}; let dropdown; diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 80f7fc7b2..445ca2748 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -84,7 +84,7 @@ const Snippetbar = createClass({ compileSnippets : function(rendererPath, themePath, snippets) { let compiledSnippets = snippets; - const baseSnippetsPath = themePath && (themePath[0] === '#') ? false : Themes[rendererPath][themePath].baseSnippets; + const baseSnippetsPath = themePath && (Themes[rendererPath].hasOwnProperty(themePath)) ? Themes[rendererPath][themePath].baseSnippets : false; const objB = _.keyBy(compiledSnippets, 'groupName'); diff --git a/server/homebrew.api.js b/server/homebrew.api.js index f7da4f898..1fdd707fb 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -89,13 +89,13 @@ const api = { if(brews) { for await (const brew of brews) { - userThemes.Brew[`#${brew.shareId}`] = { + userThemes.Brew[brew.shareId] = { name : brew.title, renderer : 'V3', baseTheme : '', baseSnippets : false, author : brew.authors[0], - path : `#${brew.shareId}`, + path : brew.shareId, thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' }; } @@ -285,7 +285,7 @@ const api = { const brew = req.brew; splitTextStyleAndMetadata(brew); res.setHeader('Content-Type', 'text/css'); - const themePath = req.brew.theme[0] != '#' ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme.slice(1)}`; + const themePath = themes[_.upperFirst(req.brew.renderer)].hasOwnProperty(req.brew.theme) ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme}`; // Drop Parent theme if it has already been loaded. // This assumes the continued use of the V3/5ePHB and V3/Blank themes for the app. const parentThemeImport = ((req.brew.theme != '5ePHB') && (req.brew.theme != 'Blank')) ? `@import url(\"${themePath}\");\n\n`:''; @@ -296,7 +296,7 @@ const api = { const brew = req.brew; splitTextStyleAndMetadata(brew); res.setHeader('Content-Type', 'text/css'); - const themePath = req.brew.theme[0] != '#' ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme.slice(1)}`; + const themePath = themes[_.upperFirst(req.brew.renderer)].hasOwnProperty(req.brew.theme) ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme}`; const parentThemeImport = `@import url(\"${themePath}\");\n\n`; const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}`); diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 945af7a04..5704d01fa 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -604,7 +604,7 @@ brew`); describe('getBrewThemeWithUserParent', ()=>{ it('should collect parent theme and brew style - returning as css with user-theme parent imported.', async ()=>{ const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); - model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', shareId: 'iAmAUserTheme', theme: '#IamATheme', style: 'I Have a style!' })); + model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', shareId: 'iAmAUserTheme', theme: 'IamATheme', style: 'I Have a style!' })); const fn = api.getBrew('share', true); const req = { brew: {}, get: ()=>{return 'localhost';}, protocol: 'https' }; const next = jest.fn(); From a247e50c9fb272f2a82132b6b1afd1979fb0adb1 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 10 Jul 2024 14:15:03 -0400 Subject: [PATCH 065/121] renaming "get" functions rename `getStaticTheme` to `getStaticThemeCSS` rename `getBrewThemeWithCSS` to `getBrewThemeCSS` rename `getBrewThemeParent` to `getBrewThemeParentCSS` to avoid confusion with other "get" endpoints like `getBrew`, and unify naming for endpoint functions that return CSS. Simplify `isStaticTheme` function (getting the parent theme is handled elsewhere) --- server/app.js | 8 ++++---- server/homebrew.api.js | 40 ++++++++++++++++++------------------- server/homebrew.api.spec.js | 12 +++++------ 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/server/app.js b/server/app.js index 98fd00937..642575ab4 100644 --- a/server/app.js +++ b/server/app.js @@ -9,7 +9,7 @@ const yaml = require('js-yaml'); const app = express(); const config = require('./config.js'); -const { homebrewApi, getBrew, getBrewThemeWithCSS, getStaticTheme, getBrewThemeParent } = require('./homebrew.api.js'); +const { homebrewApi, getBrew, getBrewThemeCSS, getStaticThemeCSS, getBrewThemeParentCSS } = require('./homebrew.api.js'); const GoogleActions = require('./googleActions.js'); const serveCompressedStaticAssets = require('./static-assets.mv.js'); const sanitizeFilename = require('sanitize-filename'); @@ -79,9 +79,9 @@ app.get('/robots.txt', (req, res)=>{ // Theme -app.get('/css/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeWithCSS)); -app.get('/css/:engine/:id/', asyncHandler(getStaticTheme)); -app.get('/cssParent/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeParent)); +app.get('/css/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeCSS)); +app.get('/css/:engine/:id/', asyncHandler(getStaticThemeCSS)); +app.get('/cssParent/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeParentCSS)); //Home page diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 1fdd707fb..b6dd9cec5 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -13,17 +13,10 @@ var url = require('url'); const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); -const themes = require('../themes/themes.json'); +const Themes = require('../themes/themes.json'); -const isStaticTheme = (engine, themeName)=>{ - if(!themes.hasOwnProperty(engine)) { - return undefined; - } - if(themes[engine].hasOwnProperty(themeName)) { - return themes[engine][themeName].baseTheme; - } else { - return undefined; - } +const isStaticTheme = (renderer, themeName)=>{ + return Themes[renderer]?.[themeName] !== undefined; }; // const getTopBrews = (cb) => { @@ -281,35 +274,40 @@ const api = { res.status(200).send(saved); }, - getBrewThemeWithCSS : async (req, res)=>{ + getBrewThemeCSS : async (req, res)=>{ const brew = req.brew; + console.log(`getBrewThemeCSS for ${brew.shareId}`) splitTextStyleAndMetadata(brew); res.setHeader('Content-Type', 'text/css'); - const themePath = themes[_.upperFirst(req.brew.renderer)].hasOwnProperty(req.brew.theme) ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme}`; + const themePath = Themes[_.upperFirst(req.brew.renderer)].hasOwnProperty(req.brew.theme) ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme}`; // Drop Parent theme if it has already been loaded. // This assumes the continued use of the V3/5ePHB and V3/Blank themes for the app. + console.log(`and parentThemeImport for ${brew.theme}`) const parentThemeImport = ((req.brew.theme != '5ePHB') && (req.brew.theme != 'Blank')) ? `@import url(\"${themePath}\");\n\n`:''; const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}${req.brew.style}`); }, - getBrewThemeParent : async (req, res)=>{ + getBrewThemeParentCSS : async (req, res)=>{ const brew = req.brew; + console.log(`getBrewThemeParentCSS for ${brew.shareId}`) splitTextStyleAndMetadata(brew); res.setHeader('Content-Type', 'text/css'); - const themePath = themes[_.upperFirst(req.brew.renderer)].hasOwnProperty(req.brew.theme) ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme}`; + console.log(`getBrewThemeParentCSS parent is ${brew.theme}`) + const themePath = Themes[_.upperFirst(req.brew.renderer)].hasOwnProperty(req.brew.theme) ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme}`; const parentThemeImport = `@import url(\"${themePath}\");\n\n`; const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}`); }, - getStaticTheme : async(req, res)=>{ - const themeParent = isStaticTheme(req.params.engine, req.params.id); - if(themeParent === undefined){ - res.status(404).send(`Invalid Theme - Engine: ${req.params.engine}, Name: ${req.params.id}`); - } else { + getStaticThemeCSS : async(req, res)=>{ + if (!isStaticTheme(req.params.engine, req.params.id)) + res.status(404).send(`Invalid Theme - Renderer: ${req.params.engine}, Name: ${req.params.id}`); + else { + const themeParent = Themes[req.params.engine][req.params.id].baseTheme; + console.log(`getStaticThemeCSS for ${themeParent}`) res.setHeader('Content-Type', 'text/css'); res.setHeader('Cache-Control', 'public, max-age: 43200, must-revalidate'); - const parentTheme = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n/* Static Theme ${themes[req.params.engine][themeParent].name} */\n` : ''; - return res.status(200).send(`${parentTheme}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n/* Static Theme ${themes[req.params.engine][req.params.id].name} */\n`); + const parentTheme = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n/* Static Theme ${Themes[req.params.engine][themeParent].name} */\n` : ''; + return res.status(200).send(`${parentTheme}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.engine][req.params.id].name} */\n`); } }, updateBrew : async (req, res)=>{ diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 5704d01fa..c7ebfc964 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -594,7 +594,7 @@ brew`); const next = jest.fn(); await fn(req, null, next); - api.getBrewThemeWithCSS(req, res); + api.getBrewThemeCSS(req, res); const sent = res.send.mock.calls[0][0]; expect(sent).toBe(`@import url("/css/V3/5eDMG");\n\n/* From Brew: https://localhost/share/iAmAUserTheme */\n\nI Have a style!`); expect(res.status).toHaveBeenCalledWith(200); @@ -610,14 +610,14 @@ brew`); const next = jest.fn(); await fn(req, null, next); - api.getBrewThemeWithCSS(req, res); + api.getBrewThemeCSS(req, res); const sent = res.send.mock.calls[0][0]; expect(sent).toBe(`@import url("/css/IamATheme");\n\n/* From Brew: https://localhost/share/iAmAUserTheme */\n\nI Have a style!`); expect(res.status).toHaveBeenCalledWith(200); }); }); - describe('getStaticTheme', ()=>{ + describe('getStaticThemeCSS', ()=>{ it('should return an import of the theme without including a parent.', async ()=>{ const req = { params : { @@ -625,7 +625,7 @@ brew`); id : '5ePHB' } }; - api.getStaticTheme(req, res); + api.getStaticThemeCSS(req, res); const sent = res.send.mock.calls[0][0]; expect(sent).toBe('@import url("/themes/V3/5ePHB/style.css");\n/* Static Theme 5e PHB */\n'); expect(res.status).toHaveBeenCalledWith(200); @@ -637,7 +637,7 @@ brew`); id : '5eDMG' } }; - api.getStaticTheme(req, res); + api.getStaticThemeCSS(req, res); const sent = res.send.mock.calls[0][0]; expect(sent).toBe('@import url("/css/V3/5ePHB");\n/* Static Theme 5e PHB */\n@import url("/themes/V3/5eDMG/style.css");\n/* Static Theme 5e DMG */\n'); expect(res.status).toHaveBeenCalledWith(200); @@ -649,7 +649,7 @@ brew`); id : '5eDMGGGG' } }; - api.getStaticTheme(req, res); + api.getStaticThemeCSS(req, res); const sent = res.send.mock.calls[0][0]; expect(sent).toBe('Invalid Theme - Engine: V3, Name: 5eDMGGGG'); expect(res.status).toHaveBeenCalledWith(404); From 28446d3ae2c8408c577bcf752b12a8c9707631a2 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 10 Jul 2024 14:21:23 -0400 Subject: [PATCH 066/121] Comments for theme CSS endpoints --- server/homebrew.api.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index b6dd9cec5..07c339d94 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -274,6 +274,7 @@ const api = { res.status(200).send(saved); }, + //Return CSS for a brew theme, with @include endpoint for its parent theme if any (except for Blank and 5ePHB) getBrewThemeCSS : async (req, res)=>{ const brew = req.brew; console.log(`getBrewThemeCSS for ${brew.shareId}`) @@ -287,6 +288,7 @@ const api = { const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}${req.brew.style}`); }, + //Return @include endpoint for a theme's parent theme only getBrewThemeParentCSS : async (req, res)=>{ const brew = req.brew; console.log(`getBrewThemeParentCSS for ${brew.shareId}`) @@ -298,14 +300,15 @@ const api = { const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}`); }, + //Return CSS for a static theme, with @include endpoint for its parent theme if any getStaticThemeCSS : async(req, res)=>{ if (!isStaticTheme(req.params.engine, req.params.id)) res.status(404).send(`Invalid Theme - Renderer: ${req.params.engine}, Name: ${req.params.id}`); else { - const themeParent = Themes[req.params.engine][req.params.id].baseTheme; console.log(`getStaticThemeCSS for ${themeParent}`) res.setHeader('Content-Type', 'text/css'); res.setHeader('Cache-Control', 'public, max-age: 43200, must-revalidate'); + const themeParent = Themes[req.params.engine][req.params.id].baseTheme; const parentTheme = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n/* Static Theme ${Themes[req.params.engine][themeParent].name} */\n` : ''; return res.status(200).send(`${parentTheme}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.engine][req.params.id].name} */\n`); } From 88578a3d167747fc8605da25bc92c53d4ef7be81 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 10 Jul 2024 14:22:42 -0400 Subject: [PATCH 067/121] Fix failing test --- server/homebrew.api.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index c7ebfc964..d33a8f133 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -651,7 +651,7 @@ brew`); }; api.getStaticThemeCSS(req, res); const sent = res.send.mock.calls[0][0]; - expect(sent).toBe('Invalid Theme - Engine: V3, Name: 5eDMGGGG'); + expect(sent).toBe('Invalid Theme - Renderer: V3, Name: 5eDMGGGG'); expect(res.status).toHaveBeenCalledWith(404); }); }); From 27aebf0e3be7e5d6bc98e706f8910b7a586ad825 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 10 Jul 2024 17:15:45 -0400 Subject: [PATCH 068/121] Give 5ePHB and Journal themes a baseTheme of "Blank" --- themes/V3/5ePHB/settings.json | 2 +- themes/V3/Journal/settings.json | 2 +- themes/themes.json | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/themes/V3/5ePHB/settings.json b/themes/V3/5ePHB/settings.json index 499096a05..53329ce4a 100644 --- a/themes/V3/5ePHB/settings.json +++ b/themes/V3/5ePHB/settings.json @@ -1,6 +1,6 @@ { "name" : "5e PHB", "renderer" : "V3", - "baseTheme" : false, + "baseTheme" : "Blank", "baseSnippets" : false } diff --git a/themes/V3/Journal/settings.json b/themes/V3/Journal/settings.json index 069bdb270..74700cc8c 100644 --- a/themes/V3/Journal/settings.json +++ b/themes/V3/Journal/settings.json @@ -1,6 +1,6 @@ { "name" : "Journal", "renderer" : "V3", - "baseTheme" : false, + "baseTheme" : "Blank", "baseSnippets" : "5ePHB" } diff --git a/themes/themes.json b/themes/themes.json index 0d28c7394..16a4b9b13 100644 --- a/themes/themes.json +++ b/themes/themes.json @@ -18,7 +18,7 @@ "5ePHB": { "name": "5e PHB", "renderer": "V3", - "baseTheme": false, + "baseTheme": "Blank", "baseSnippets": false, "path": "5ePHB" }, @@ -32,7 +32,7 @@ "Journal": { "name": "Journal", "renderer": "V3", - "baseTheme": false, + "baseTheme": "Blank", "baseSnippets": "5ePHB", "path": "Journal" } From 7eb96ee6be6ce3129717a8a98669f9f43cec8dff Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 10 Jul 2024 17:46:51 -0400 Subject: [PATCH 069/121] Simplify brewRenderer output to only emit current theme Instead of Blank, Parent, and Theme, just make use of the @include chaining, to handle all parent themes down to and including Blank --- client/homebrew/brewRenderer/brewRenderer.jsx | 26 ++++--------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 918fdb5c9..4c77728fa 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -188,23 +188,11 @@ const BrewRenderer = (props)=>{ document.dispatchEvent(new MouseEvent('click')); }; - let brewThemeRendererPath = `${props?.renderer ? _.upperFirst(props.renderer) : 'V3'}`; + let rendererPath = ''; + let themePath = props.theme; - let themePath = props.theme ?? '5ePHB'; - const Themes = { ...staticThemes, ...props.userThemes }; - let staticOrUserParent; - let baseThemePath = null; - - if (!Themes[brewThemeRendererPath].hasOwnProperty(themePath)) { - brewThemeRendererPath = ''; - staticOrUserParent = `/cssParent/${themePath}`; - baseThemePath = 'Brew'; - } else { - baseThemePath = Themes[brewThemeRendererPath][themePath].baseTheme - brewThemeRendererPath += '/'; - staticOrUserParent = `/css/${brewThemeRendererPath}${baseThemePath}`; - - } + if (staticThemes[_.upperFirst(props.renderer)]?.[props.theme] !== undefined) //Change CSS path if is staticTheme + rendererPath = _.upperFirst(props.renderer) + '/'; return ( <> @@ -235,11 +223,7 @@ const BrewRenderer = (props)=>{ tabIndex={-1} style={{ height: state.height }}> - - {baseThemePath && - - } - + {/* Apply CSS from Style tab and render pages from Markdown tab */} {state.isMounted From 24c86dd1991e83b54f1d2145f8617b980f5e1dfd Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 10 Jul 2024 17:49:57 -0400 Subject: [PATCH 070/121] Remove unused test --- server/homebrew.api.spec.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index d33a8f133..fb46cfa02 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -618,18 +618,6 @@ brew`); }); describe('getStaticThemeCSS', ()=>{ - it('should return an import of the theme without including a parent.', async ()=>{ - const req = { - params : { - engine : 'V3', - id : '5ePHB' - } - }; - api.getStaticThemeCSS(req, res); - const sent = res.send.mock.calls[0][0]; - expect(sent).toBe('@import url("/themes/V3/5ePHB/style.css");\n/* Static Theme 5e PHB */\n'); - expect(res.status).toHaveBeenCalledWith(200); - }); it('should return an import of the theme including a parent.', async ()=>{ const req = { params : { From a6f787ea8f22de7514048cd1dad7954f0aff3dc3 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 10 Jul 2024 17:56:39 -0400 Subject: [PATCH 071/121] Remove `getBrewThemeParentCSS` --- server/app.js | 3 +-- server/homebrew.api.js | 21 ++++----------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/server/app.js b/server/app.js index 642575ab4..b2f76f280 100644 --- a/server/app.js +++ b/server/app.js @@ -9,7 +9,7 @@ const yaml = require('js-yaml'); const app = express(); const config = require('./config.js'); -const { homebrewApi, getBrew, getBrewThemeCSS, getStaticThemeCSS, getBrewThemeParentCSS } = require('./homebrew.api.js'); +const { homebrewApi, getBrew, getBrewThemeCSS, getStaticThemeCSS } = require('./homebrew.api.js'); const GoogleActions = require('./googleActions.js'); const serveCompressedStaticAssets = require('./static-assets.mv.js'); const sanitizeFilename = require('sanitize-filename'); @@ -81,7 +81,6 @@ app.get('/robots.txt', (req, res)=>{ app.get('/css/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeCSS)); app.get('/css/:engine/:id/', asyncHandler(getStaticThemeCSS)); -app.get('/cssParent/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeParentCSS)); //Home page diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 07c339d94..20c1be3ed 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -274,41 +274,28 @@ const api = { res.status(200).send(saved); }, - //Return CSS for a brew theme, with @include endpoint for its parent theme if any (except for Blank and 5ePHB) + //Return CSS for a brew theme, with @include endpoint for its parent theme if any getBrewThemeCSS : async (req, res)=>{ const brew = req.brew; console.log(`getBrewThemeCSS for ${brew.shareId}`) splitTextStyleAndMetadata(brew); res.setHeader('Content-Type', 'text/css'); const themePath = Themes[_.upperFirst(req.brew.renderer)].hasOwnProperty(req.brew.theme) ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme}`; - // Drop Parent theme if it has already been loaded. - // This assumes the continued use of the V3/5ePHB and V3/Blank themes for the app. console.log(`and parentThemeImport for ${brew.theme}`) - const parentThemeImport = ((req.brew.theme != '5ePHB') && (req.brew.theme != 'Blank')) ? `@import url(\"${themePath}\");\n\n`:''; + const parentThemeImport = `@import url(\"${themePath}\");\n\n`; const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}${req.brew.style}`); }, - //Return @include endpoint for a theme's parent theme only - getBrewThemeParentCSS : async (req, res)=>{ - const brew = req.brew; - console.log(`getBrewThemeParentCSS for ${brew.shareId}`) - splitTextStyleAndMetadata(brew); - res.setHeader('Content-Type', 'text/css'); - console.log(`getBrewThemeParentCSS parent is ${brew.theme}`) - const themePath = Themes[_.upperFirst(req.brew.renderer)].hasOwnProperty(req.brew.theme) ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme}`; - const parentThemeImport = `@import url(\"${themePath}\");\n\n`; - const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; - return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}`); - }, //Return CSS for a static theme, with @include endpoint for its parent theme if any getStaticThemeCSS : async(req, res)=>{ if (!isStaticTheme(req.params.engine, req.params.id)) res.status(404).send(`Invalid Theme - Renderer: ${req.params.engine}, Name: ${req.params.id}`); else { - console.log(`getStaticThemeCSS for ${themeParent}`) res.setHeader('Content-Type', 'text/css'); res.setHeader('Cache-Control', 'public, max-age: 43200, must-revalidate'); const themeParent = Themes[req.params.engine][req.params.id].baseTheme; + console.log(`getStaticThemeCSS for ${req.params.id}`) + console.log(`and parentThemeImport for ${themeParent}`) const parentTheme = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n/* Static Theme ${Themes[req.params.engine][themeParent].name} */\n` : ''; return res.status(200).send(`${parentTheme}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.engine][req.params.id].name} */\n`); } From 29c2274a194028828d1e6836080f0e089cf87dbe Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 10 Jul 2024 18:54:45 -0400 Subject: [PATCH 072/121] Unify some variable naming --- server/homebrew.api.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 20c1be3ed..e39026b84 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -277,14 +277,17 @@ const api = { //Return CSS for a brew theme, with @include endpoint for its parent theme if any getBrewThemeCSS : async (req, res)=>{ const brew = req.brew; - console.log(`getBrewThemeCSS for ${brew.shareId}`) splitTextStyleAndMetadata(brew); res.setHeader('Content-Type', 'text/css'); - const themePath = Themes[_.upperFirst(req.brew.renderer)].hasOwnProperty(req.brew.theme) ? `/css/${req.brew.renderer}/${req.brew.theme}` : `/css/${req.brew.theme}`; + let rendererPath = ''; + if(isStaticTheme(req.brew.renderer,req.brew.theme)) //Check if parent is staticBrew + rendererPath = _.upperFirst(req.brew.renderer) + '/'; + + console.log(`getBrewThemeCSS for ${brew.shareId}`) console.log(`and parentThemeImport for ${brew.theme}`) - const parentThemeImport = `@import url(\"${themePath}\");\n\n`; + const parentThemeImport = `@import url(\"/css/${rendererPath}${req.brew.theme}\");\n\n`; const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; - return res.status(200).send(req.brew.renderer == 'legacy' ? '' : `${parentThemeImport}${themeLocationComment}${req.brew.style}`); + return res.status(200).send(`${parentThemeImport}${themeLocationComment}${req.brew.style}`); }, //Return CSS for a static theme, with @include endpoint for its parent theme if any getStaticThemeCSS : async(req, res)=>{ @@ -296,8 +299,8 @@ const api = { const themeParent = Themes[req.params.engine][req.params.id].baseTheme; console.log(`getStaticThemeCSS for ${req.params.id}`) console.log(`and parentThemeImport for ${themeParent}`) - const parentTheme = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n/* Static Theme ${Themes[req.params.engine][themeParent].name} */\n` : ''; - return res.status(200).send(`${parentTheme}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.engine][req.params.id].name} */\n`); + const parentThemeImport = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n/* Static Theme ${Themes[req.params.engine][themeParent].name} */\n` : ''; + return res.status(200).send(`${parentThemeImport}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.engine][req.params.id].name} */\n`); } }, updateBrew : async (req, res)=>{ From 5c0a072115b02cdb0dce095a72c36c90ea963eb6 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 11 Jul 2024 00:25:11 -0400 Subject: [PATCH 073/121] userThemes passed to SnippetBar.jsx is never used --- client/homebrew/editor/editor.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 3417d7c4d..efcc9c861 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -417,7 +417,6 @@ const Editor = createClass({ showEditButtons={this.props.showEditButtons} renderer={this.props.renderer} theme={this.props.brew.theme} - userThemes={this.props.brew.userThemes} undo={this.undo} redo={this.redo} foldCode={this.foldCode} From 2fa3c0f3114e88edba4b62b96a502de77492f0e8 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 11 Jul 2024 00:26:50 -0400 Subject: [PATCH 074/121] themeClass is never used --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 8f236b833..4711cc73c 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -36,7 +36,6 @@ const MetadataEditor = createClass({ authors : [], systems : [], renderer : 'legacy', - themeClass : 'V3', theme : '5ePHB', lang : 'en' }, @@ -109,9 +108,8 @@ const MetadataEditor = createClass({ }); }, - handleTheme : function(theme, themeClass){ + handleTheme : function(theme){ this.props.metadata.renderer = theme.renderer; - this.props.metadata.themeClass = themeClass; this.props.metadata.theme = theme.path; this.props.onChange(this.props.metadata); }, @@ -200,7 +198,7 @@ const MetadataEditor = createClass({ return _.map(_.values(mergedThemes[renderer]), (theme)=>{ const preview = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; const texture = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`; - return
this.handleTheme(theme, renderer)} title={''}> + return
this.handleTheme(theme)} title={''}>

{`${theme?.author ? theme.author : renderer} : ${theme.name}`}

From 23fd70e3c3bd108f8c5e51b629b241ac3bd199b1 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 11 Jul 2024 18:10:26 +1200 Subject: [PATCH 075/121] Add additional style to existing SolberaImitation --- themes/fonts/5e/fonts.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/themes/fonts/5e/fonts.less b/themes/fonts/5e/fonts.less index 8f089b51c..c028b06f9 100644 --- a/themes/fonts/5e/fonts.less +++ b/themes/fonts/5e/fonts.less @@ -74,8 +74,9 @@ @font-face { font-family: SolberaImitationRemake; //Tweaked 5e version src: url('../../../fonts/5e/Solbera Imitation Tweak.woff2'); - font-weight: normal; + font-weight: 100 1000; font-style: normal; + font-style: italic; } /* Cover Page */ From cb9d24d5b4eaa6b24236bc808da51cee709eeab2 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Thu, 11 Jul 2024 20:03:17 +1200 Subject: [PATCH 076/121] Remove text-decoration from Brew Item links --- .../pages/basePages/listPage/brewItem/brewItem.less | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less index 9bee4e5eb..a3c17215e 100644 --- a/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less +++ b/client/homebrew/pages/basePages/listPage/brewItem/brewItem.less @@ -119,11 +119,12 @@ text-align : center; a{ .animate(opacity); - display : block; - margin : 8px 0px; - opacity : 0.6; - font-size : 1.3em; - color : white; + display : block; + margin : 8px 0px; + opacity : 0.6; + font-size : 1.3em; + color : white; + text-decoration : unset; &:hover{ opacity : 1; } From ade819c70c4d0cb0e18266ffceff9208c83ef863 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 13 Jul 2024 12:12:05 -0500 Subject: [PATCH 077/121] A not so light rework. This removes the existing endpoints and replaces them with /theme. /theme/:id - return a theme bundle containing all styling from this USER theme and any parents. /theme/:engine/:id - return a theme bundle containing all styling from this STATIC theme and any parents The theme bundle returns a marshalled JSON object containing: styles - an array of strings representing the collected styles in loading order snippets - an array ( currently empty ) of collected snippets. The various bits of theme rendering code for ` }} />; - return
${cleanStyle} ` }} />; - }; - const renderPage = (pageText, index)=>{ if(props.renderer == 'legacy') { const html = MarkdownLegacy.render(pageText); @@ -170,7 +167,44 @@ const BrewRenderer = (props)=>{ } }; + const loadAllBrewStylesAndSnippets = ()=>{ + /* + Loads the theme bundle and parses it out. + These functionally replaces the previous renderStyles() function but needs to wait until the window is mounted. + */ + const rendererPath = isStaticTheme(props.renderer, props.theme) ? `/${props.renderer}/` : '/'; + // Check for a User or Static Theme to change the endpoint path + fetch(`${window.location.protocol}//${window.location.host}/theme${rendererPath}${props.theme}`).then((response)=>response.json()).then((themeBundle)=>{ + // Load the themeBundle from the endpoint as an object. + const documentFrame = document.getElementById('BrewRenderer'); + const iframeDocument = documentFrame.contentDocument || documentFrame.contentWindow.document; + // Find the brew frame Document root. + + for (let style=0; style < themeBundle.styles.length; style++){ + /* + Walk through the styles array on the Theme Bundle. + Create a new style node and add it to the Brew Frame + */ + const newStyles = document.createElement('style'); + newStyles.appendChild(document.createTextNode(`${themeBundle.styles[style]}\n`)); + iframeDocument.head.appendChild(newStyles); + + } + /* + Add the local brew styling to the Brew Frame + */ + const newStyles = document.createElement('style'); + const cleanStyle = props.style; //DOMPurify.sanitize(props.style, purifyConfig); + + newStyles.appendChild(document.createTextNode(`/* Local Brew Styling */\n\n${cleanStyle}`)); + iframeDocument.head.appendChild(newStyles); + + // TO-DO - Walk the snippets returns and add them to the appropriate menu. + }); + }; + const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount" + loadAllBrewStylesAndSnippets(); // Load the brew's inherited and local styles. setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame updateSize(); window.addEventListener('resize', updateSize); @@ -189,10 +223,10 @@ const BrewRenderer = (props)=>{ }; let rendererPath = ''; - let themePath = props.theme; + const themePath = props.theme; - if (staticThemes[_.upperFirst(props.renderer)]?.[props.theme] !== undefined) //Change CSS path if is staticTheme - rendererPath = _.upperFirst(props.renderer) + '/'; + if(staticThemes[_.upperFirst(props.renderer)]?.[props.theme] !== undefined) //Change CSS path if is staticTheme + rendererPath = `${_.upperFirst(props.renderer)}/`; return ( <> @@ -222,14 +256,10 @@ const BrewRenderer = (props)=>{ onKeyDown={handleControlKeys} tabIndex={-1} style={{ height: state.height }}> - - - {/* Apply CSS from Style tab and render pages from Markdown tab */} {state.isMounted && <> - {renderStyle()}
{renderPages()}
diff --git a/server/app.js b/server/app.js index b2f76f280..9680c64ca 100644 --- a/server/app.js +++ b/server/app.js @@ -9,7 +9,7 @@ const yaml = require('js-yaml'); const app = express(); const config = require('./config.js'); -const { homebrewApi, getBrew, getBrewThemeCSS, getStaticThemeCSS } = require('./homebrew.api.js'); +const { homebrewApi, getBrew, getThemeBundle } = require('./homebrew.api.js'); const GoogleActions = require('./googleActions.js'); const serveCompressedStaticAssets = require('./static-assets.mv.js'); const sanitizeFilename = require('sanitize-filename'); @@ -78,10 +78,10 @@ app.get('/robots.txt', (req, res)=>{ }); // Theme - -app.get('/css/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getBrewThemeCSS)); -app.get('/css/:engine/:id/', asyncHandler(getStaticThemeCSS)); - +// Path for User Themes +app.get('/theme/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getThemeBundle)); +// Path for Static Themes +app.get('/theme/:engine/:id', asyncHandler(getThemeBundle)); //Home page app.get('/', (req, res, next)=>{ diff --git a/server/homebrew.api.js b/server/homebrew.api.js index e39026b84..ac91799dc 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -8,8 +8,8 @@ const Markdown = require('../shared/naturalcrit/markdown.js'); const yaml = require('js-yaml'); const asyncHandler = require('express-async-handler'); const { nanoid } = require('nanoid'); -var url = require('url'); - +const path = require('path'); +const fs = require('fs'); const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); @@ -274,31 +274,111 @@ const api = { res.status(200).send(saved); }, + getThemeBundle : async(req, res)=>{ + /* + getThemeBundle: Collects the theme and all parent themes + returns an object containing an array of css, in render order, and an array + of snippets ( currently empty ) + Important parameter members: + req.params.id: This is the shareId ( User theme ) or name ( static theme ) + loaded first. + req.params.engine: This is the Markdown+ version for the static theme. If a + User theme the value will come from the User Theme metadata. + */ + let parentReq = {}; + const completeStyles = []; + const completeSnippets = []; + if(!req.params.engine) { + // If this is not set, our *first* theme is a User theme. + const finalChildBrew = req.brew; + // Break up the frontmatter + splitTextStyleAndMetadata(finalChildBrew); + // If there is anything in the snippets member, append it to the snippets array. + if(finalChildBrew?.snippets) completeSnippets.push(JSON.parse(finalChildBrew.snippets)); + // If there is anything in the styles member, append it to the styles array with labelling. + if(finalChildBrew?.style) completeStyles.push(`/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.params.id} */\n\n${finalChildBrew.style}`); + + // Set up the simulated request we are using for the parent-walking. + // This is our loop control. + parentReq = { + params : { + id : finalChildBrew.theme, + // This is the only value needed for the User themes. This is the shareId of the theme. + }, + renderer : finalChildBrew.renderer + // We set this for use later when checking for Static theme inheritance. + }; + while ((parentReq.params.id) && (!isStaticTheme(finalChildBrew.renderer, parentReq.params.id))) { + await api.getBrew('share')(parentReq, res, ()=>{}); + // Load the referenced Brew + splitTextStyleAndMetadata(parentReq); + // break up the meta data + if(parentReq?.snippets) completeSnippets.push(JSON.parse(parentReq.snippets)); + // If there is anything in the snippets member, append it to the snippets array. + if(parentReq?.style) { + completeStyles.push(`/* From Brew: ${req.protocol}://${req.get('host')}/share/${parentReq.params.id} */\n\n${parentReq.style}`); + // If there is anything in the styles member, append it to the styles array with labelling. + } + // Update the loop object to point to this theme's parent + parentReq.params.id = parentReq?.theme; + } + } else { + // If the first theme wasn't a User theme, set up the loop control object + // This is done the same as above for consistant logic. + parentReq = { + params : { + id : req.params.id, + // This is the name of the theme + }, + renderer : req.params.engine + // The renderer is needed for the static pathing. + }; + } + + while ((parentReq.params.id) && (isStaticTheme(parentReq.renderer, parentReq.params.id))) { + // If we have a static path + const localStyle = fs.readFileSync(path.join(__dirname, '../build/themes/', parentReq.renderer, parentReq.params.id, 'style.css')).toString(); + // Read the Theme's style.css from the filesystem + completeStyles.push(`/* From Theme ${parentReq.params.id} */\n\n${localStyle}`); + // Label and append the themes style to the styles array. + parentReq.params.id = Themes[parentReq.renderer][parentReq.params.id].baseTheme; + // NOTE: This currently makes NO attempt to do anything with Static theme Snippets. Loading of static snippets remains unchanged. + } + + const returnObj = { + styles : completeStyles.reverse(), + // Reverse the order of the styles array so they are rendered oldest aprent to youngest child. + snippets : completeSnippets + }; + + res.setHeader('Content-Type', 'text/json'); + return res.status(200).send(JSON.stringify(returnObj)); + }, //Return CSS for a brew theme, with @include endpoint for its parent theme if any getBrewThemeCSS : async (req, res)=>{ const brew = req.brew; splitTextStyleAndMetadata(brew); res.setHeader('Content-Type', 'text/css'); let rendererPath = ''; - if(isStaticTheme(req.brew.renderer,req.brew.theme)) //Check if parent is staticBrew - rendererPath = _.upperFirst(req.brew.renderer) + '/'; + if(isStaticTheme(req.brew.renderer, req.brew.theme)) //Check if parent is staticBrew + rendererPath = `${_.upperFirst(req.brew.renderer)}/`; - console.log(`getBrewThemeCSS for ${brew.shareId}`) - console.log(`and parentThemeImport for ${brew.theme}`) + console.log(`getBrewThemeCSS for ${brew.shareId}`); + console.log(`and parentThemeImport for ${brew.theme}`); const parentThemeImport = `@import url(\"/css/${rendererPath}${req.brew.theme}\");\n\n`; const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; return res.status(200).send(`${parentThemeImport}${themeLocationComment}${req.brew.style}`); }, //Return CSS for a static theme, with @include endpoint for its parent theme if any getStaticThemeCSS : async(req, res)=>{ - if (!isStaticTheme(req.params.engine, req.params.id)) + if(!isStaticTheme(req.params.engine, req.params.id)) res.status(404).send(`Invalid Theme - Renderer: ${req.params.engine}, Name: ${req.params.id}`); else { res.setHeader('Content-Type', 'text/css'); res.setHeader('Cache-Control', 'public, max-age: 43200, must-revalidate'); const themeParent = Themes[req.params.engine][req.params.id].baseTheme; - console.log(`getStaticThemeCSS for ${req.params.id}`) - console.log(`and parentThemeImport for ${themeParent}`) + console.log(`getStaticThemeCSS for ${req.params.id}`); + console.log(`and parentThemeImport for ${themeParent}`); const parentThemeImport = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n/* Static Theme ${Themes[req.params.engine][themeParent].name} */\n` : ''; return res.status(200).send(`${parentThemeImport}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.engine][req.params.id].name} */\n`); } diff --git a/shared/helpers.js b/shared/helpers.js index 8ca185046..321791f84 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -15,6 +15,11 @@ const splitTextStyleAndMetadata = (brew)=>{ brew.style = brew.text.slice(7, index - 1); brew.text = brew.text.slice(index + 5); } + if(brew.text.startsWith('```snippets')) { + const index = brew.text.indexOf('```\n\n'); + brew.snippets = brew.text.slice(11, index - 1); + brew.text = brew.text.slice(index + 5); + } }; const printCurrentBrew = ()=>{ From 5f8d46f1b66c077308ff908d0b3ccddfc7b1cf9b Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 17:09:45 -0400 Subject: [PATCH 078/121] Reuse `splitTextStyleAndMetadata` from `helpers.js` --- server/homebrew.api.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index ac91799dc..09eed01bd 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -10,6 +10,7 @@ const asyncHandler = require('express-async-handler'); const { nanoid } = require('nanoid'); const path = require('path'); const fs = require('fs'); +const { splitTextStyleAndMetadata } = require('../shared/helpers.js'); const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); @@ -27,22 +28,6 @@ const isStaticTheme = (renderer, themeName)=>{ const MAX_TITLE_LENGTH = 100; -const splitTextStyleAndMetadata = (brew)=>{ - brew.text = brew.text.replaceAll('\r\n', '\n'); - if(brew.text.startsWith('```metadata')) { - const index = brew.text.indexOf('```\n\n'); - const metadataSection = brew.text.slice(12, index - 1); - const metadata = yaml.load(metadataSection); - Object.assign(brew, _.pick(metadata, ['title', 'description', 'tags', 'systems', 'renderer', 'theme', 'lang'])); - brew.text = brew.text.slice(index + 5); - } - if(brew.text.startsWith('```css')) { - const index = brew.text.indexOf('```\n\n'); - brew.style = brew.text.slice(7, index - 1); - brew.text = brew.text.slice(index + 5); - } -}; - const api = { homebrewApi : router, getId : (req)=>{ From ee381c91fe55133a8a4dc9a5cd041221d5feb19e Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 17:26:38 -0400 Subject: [PATCH 079/121] Simplify getUserBrewThemes function a bit --- server/homebrew.api.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 09eed01bd..888c1d137 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -46,6 +46,7 @@ const api = { } return { id, googleId }; }, + //Get array of any of this user's brews tagged with `meta:theme` getUsersBrewThemes : async (username, id)=>{ const fields = [ 'title', @@ -57,24 +58,20 @@ const api = { 'authors' ]; - const userThemes = { - Brew : { - - } - }; + const userThemes = {}; const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] }, shareId: { $ne: id }, renderer: { $ne: 'Legacy' } }); if(brews) { - for await (const brew of brews) { + for (const brew of brews) { userThemes.Brew[brew.shareId] = { name : brew.title, - renderer : 'V3', + renderer : brew.renderer, baseTheme : '', baseSnippets : false, author : brew.authors[0], path : brew.shareId, - thumbnail : brew.thumbnail.length > 0 ? brew.thumbnail : '/assets/naturalCritLogoWhite.svg' + thumbnail : brew.thumbnail || '/assets/naturalCritLogoWhite.svg' }; } } From f29a5e346e591e5d32b441381585a075fbb9d19e Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 17:35:19 -0400 Subject: [PATCH 080/121] Remove `id` parameter from getUsersBrewThemes Filtering out the current brew can be done later as needed; certain situations may call for retrieving the whole list. --- server/homebrew.api.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 888c1d137..6da3d99af 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -47,7 +47,7 @@ const api = { return { id, googleId }; }, //Get array of any of this user's brews tagged with `meta:theme` - getUsersBrewThemes : async (username, id)=>{ + getUsersBrewThemes : async (username)=>{ const fields = [ 'title', 'tags', @@ -60,7 +60,7 @@ const api = { const userThemes = {}; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] }, shareId: { $ne: id }, renderer: { $ne: 'Legacy' } }); + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] }, renderer: { $ne: 'Legacy' } }); if(brews) { for (const brew of brews) { @@ -139,7 +139,6 @@ const api = { const userID = req?.account?.username && (accessType === 'edit') ? req.account.username : mainAuthor; // Clean up brew: fill in missing fields with defaults / fix old invalid values - const userThemes = accessType != 'themes' ? await api.getUsersBrewThemes(userID, id, req, res, next) : {}; if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings @@ -384,7 +383,7 @@ const api = { brew.description = brew.description.trim() || ''; brew.text = api.mergeBrewText(brew); const userID = req?.account?.username ? req.account.username : brew.authors.split(',')[0]; - brew.userThemes = await api.getUsersBrewThemes(userID, brew.editId, req, res, null); + brew.userThemes = await api.getUsersBrewThemes(userID, req, res, null); if(brew.googleId && removeFromGoogle) { From 47f912750b2664b97f3d9496741d8071a2b6f27b Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 17:44:23 -0400 Subject: [PATCH 081/121] Extract getting userThemes from `getBrew()` `getBrew()` should do one thing only; retrieve a brew. UI elements like the list of themes available to the user are not part of a brew. Moved into the handers for the `/edit/` and `/new/` endpoints --- server/app.js | 7 +++++-- server/homebrew.api.js | 7 ------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/server/app.js b/server/app.js index 9680c64ca..6c791d634 100644 --- a/server/app.js +++ b/server/app.js @@ -9,7 +9,7 @@ const yaml = require('js-yaml'); const app = express(); const config = require('./config.js'); -const { homebrewApi, getBrew, getThemeBundle } = require('./homebrew.api.js'); +const { homebrewApi, getBrew, getThemeBundle, getUsersBrewThemes } = require('./homebrew.api.js'); const GoogleActions = require('./googleActions.js'); const serveCompressedStaticAssets = require('./static-assets.mv.js'); const sanitizeFilename = require('sanitize-filename'); @@ -274,6 +274,8 @@ app.get('/user/:username', async (req, res, next)=>{ app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; + req.userThemes = await(getUsersBrewThemes(req.account?.username)); + req.ogMeta = { ...defaultMetaTags, title : req.brew.title || 'Untitled Brew', description : req.brew.description || 'No description.', @@ -299,10 +301,11 @@ app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{ renderer : req.brew.renderer, theme : req.brew.theme, tags : req.brew.tags, - userThemes : req.brew.userThemes }; req.brew = _.defaults(brew, DEFAULT_BREW); + req.userThemes = await(getUsersBrewThemes(req.account?.username)); + req.ogMeta = { ...defaultMetaTags, title : 'New', description : 'Start crafting your homebrew on the Homebrewery!' diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 6da3d99af..ee361ea92 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -135,15 +135,11 @@ const api = { throw { name: 'BrewLoad Error', message: 'Brew not found', status: 404, HBErrorCode: '05', accessType: accessType, brewId: id }; } - const mainAuthor = stub.authors ? stub.authors[0] : ''; - const userID = req?.account?.username && (accessType === 'edit') ? req.account.username : mainAuthor; - // Clean up brew: fill in missing fields with defaults / fix old invalid values if(stub) { stub.tags = stub.tags || undefined; // Clear empty strings stub.renderer = stub.renderer || undefined; // Clear empty strings stub = _.defaults(stub, DEFAULT_BREW_LOAD); // Fill in blank fields - stub.userThemes = userThemes; } req.brew = stub ?? {}; @@ -382,9 +378,6 @@ const api = { brew.title = brew.title.trim(); brew.description = brew.description.trim() || ''; brew.text = api.mergeBrewText(brew); - const userID = req?.account?.username ? req.account.username : brew.authors.split(',')[0]; - brew.userThemes = await api.getUsersBrewThemes(userID, req, res, null); - if(brew.googleId && removeFromGoogle) { // If the google id exists and we're removing it from google, set afterSave to delete the google brew and mark the brew's google id as undefined From c9b885f868e20bf02912b2e1641b2a8ecb267f18 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 18:01:50 -0400 Subject: [PATCH 082/121] include `theme` as baseTheme when getting user brew themes `baseTheme` for a user brew theme is just the `theme` value of that brew. --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index ee361ea92..abc0d9583 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -67,7 +67,7 @@ const api = { userThemes.Brew[brew.shareId] = { name : brew.title, renderer : brew.renderer, - baseTheme : '', + baseTheme : brew.theme, baseSnippets : false, author : brew.authors[0], path : brew.shareId, From e222811d03a7093433f46f0cf1dcb7fa8df1a1c4 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 18:06:46 -0400 Subject: [PATCH 083/121] Rename `engine` to `renderer` to unify naming This value is named `renderer` everywhere else. Relabeling to a consistent name. --- server/app.js | 2 +- server/homebrew.api.spec.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/app.js b/server/app.js index 6c791d634..7be31a01c 100644 --- a/server/app.js +++ b/server/app.js @@ -81,7 +81,7 @@ app.get('/robots.txt', (req, res)=>{ // Path for User Themes app.get('/theme/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getThemeBundle)); // Path for Static Themes -app.get('/theme/:engine/:id', asyncHandler(getThemeBundle)); +app.get('/theme/:renderer/:id', asyncHandler(getThemeBundle)); //Home page app.get('/', (req, res, next)=>{ diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index fb46cfa02..5eb8a407c 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -621,8 +621,8 @@ brew`); it('should return an import of the theme including a parent.', async ()=>{ const req = { params : { - engine : 'V3', - id : '5eDMG' + renderer : 'V3', + id : '5eDMG' } }; api.getStaticThemeCSS(req, res); @@ -633,8 +633,8 @@ brew`); it('should fail for an invalid static theme.', async()=>{ const req = { params : { - engine : 'V3', - id : '5eDMGGGG' + renderer : 'V3', + id : '5eDMGGGG' } }; api.getStaticThemeCSS(req, res); From 591cae0e8ff5105804053cb08b4793e81fddf1fd Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 18:08:00 -0400 Subject: [PATCH 084/121] more renaming `engine` to `renderer` --- server/homebrew.api.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index abc0d9583..c28c81500 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -259,13 +259,13 @@ const api = { Important parameter members: req.params.id: This is the shareId ( User theme ) or name ( static theme ) loaded first. - req.params.engine: This is the Markdown+ version for the static theme. If a + req.params.renderer: This is the Markdown+ version for the static theme. If a User theme the value will come from the User Theme metadata. */ let parentReq = {}; const completeStyles = []; const completeSnippets = []; - if(!req.params.engine) { + if(!req.params.renderer) { // If this is not set, our *first* theme is a User theme. const finalChildBrew = req.brew; // Break up the frontmatter @@ -307,7 +307,7 @@ const api = { id : req.params.id, // This is the name of the theme }, - renderer : req.params.engine + renderer : req.params.renderer // The renderer is needed for the static pathing. }; } @@ -348,16 +348,16 @@ const api = { }, //Return CSS for a static theme, with @include endpoint for its parent theme if any getStaticThemeCSS : async(req, res)=>{ - if(!isStaticTheme(req.params.engine, req.params.id)) - res.status(404).send(`Invalid Theme - Renderer: ${req.params.engine}, Name: ${req.params.id}`); + if(!isStaticTheme(req.params.renderer, req.params.id)) + res.status(404).send(`Invalid Theme - Renderer: ${req.params.renderer}, Name: ${req.params.id}`); else { res.setHeader('Content-Type', 'text/css'); res.setHeader('Cache-Control', 'public, max-age: 43200, must-revalidate'); - const themeParent = Themes[req.params.engine][req.params.id].baseTheme; + const themeParent = Themes[req.params.renderer][req.params.id].baseTheme; console.log(`getStaticThemeCSS for ${req.params.id}`); console.log(`and parentThemeImport for ${themeParent}`); - const parentThemeImport = themeParent ? `@import url(\"/css/${req.params.engine}/${themeParent}\");\n/* Static Theme ${Themes[req.params.engine][themeParent].name} */\n` : ''; - return res.status(200).send(`${parentThemeImport}@import url(\"/themes/${req.params.engine}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.engine][req.params.id].name} */\n`); + const parentThemeImport = themeParent ? `@import url(\"/css/${req.params.renderer}/${themeParent}\");\n/* Static Theme ${Themes[req.params.renderer][themeParent].name} */\n` : ''; + return res.status(200).send(`${parentThemeImport}@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.renderer][req.params.id].name} */\n`); } }, updateBrew : async (req, res)=>{ From f392216ff4adc437fb411a58e107171d0e03e7e1 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 18:08:29 -0400 Subject: [PATCH 085/121] Spacing --- server/app.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server/app.js b/server/app.js index 7be31a01c..99ad650d7 100644 --- a/server/app.js +++ b/server/app.js @@ -294,13 +294,13 @@ app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{ sanitizeBrew(req.brew, 'share'); splitTextStyleAndMetadata(req.brew); const brew = { - shareId : req.brew.shareId, - title : `CLONE - ${req.brew.title}`, - text : req.brew.text, - style : req.brew.style, - renderer : req.brew.renderer, - theme : req.brew.theme, - tags : req.brew.tags, + shareId : req.brew.shareId, + title : `CLONE - ${req.brew.title}`, + text : req.brew.text, + style : req.brew.style, + renderer : req.brew.renderer, + theme : req.brew.theme, + tags : req.brew.tags, }; req.brew = _.defaults(brew, DEFAULT_BREW); From 44c96aad04d3c1312d07f8c3b290d268b78d92c4 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 18:11:04 -0400 Subject: [PATCH 086/121] spacing --- server/homebrew.api.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index c28c81500..2ccd58e53 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -81,12 +81,11 @@ const api = { getBrew : (accessType, stubOnly = false)=>{ // Create middleware with the accessType passed in as part of the scope return async (req, res, next)=>{ - // Get relevant IDs for the brew const { id, googleId } = api.getId(req); // Try to find the document in the Homebrewery database -- if it doesn't exist, that's fine. - let stub = await HomebrewModel.get((accessType === 'edit') ? { editId: id } : { shareId: id }) + let stub = await HomebrewModel.get(accessType === 'edit' ? { editId: id } : { shareId: id }) .catch((err)=>{ if(googleId) { console.warn(`Unable to find document stub for ${accessType}Id ${id}`); From 62c619de245dbd3a668825b860a4e7224b4a0d3c Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 19:38:51 -0400 Subject: [PATCH 087/121] userThemes need not be nested inside a Brew object --- server/homebrew.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 2ccd58e53..1af951a74 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -64,7 +64,7 @@ const api = { if(brews) { for (const brew of brews) { - userThemes.Brew[brew.shareId] = { + userThemes[brew.shareId] = { name : brew.title, renderer : brew.renderer, baseTheme : brew.theme, From 4951b9bf1ab32845f45bc1490bd4fb2abd595d4a Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 13 Jul 2024 19:46:12 -0400 Subject: [PATCH 088/121] Add async error handler to /edit and /new Since /edit and /new endpoints now have an `await` inside that could return an error (`getUsersBrewThemes()`), asyncHandler must be added to pass errors along instead of just crashing --- server/app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/app.js b/server/app.js index 99ad650d7..d0160e3d0 100644 --- a/server/app.js +++ b/server/app.js @@ -271,7 +271,7 @@ app.get('/user/:username', async (req, res, next)=>{ }); //Edit Page -app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ +app.get('/edit/:id', asyncHandler(getBrew('edit')), asyncHandler(async(req, res, next)=>{ req.brew = req.brew.toObject ? req.brew.toObject() : req.brew; req.userThemes = await(getUsersBrewThemes(req.account?.username)); @@ -287,10 +287,10 @@ app.get('/edit/:id', asyncHandler(getBrew('edit')), async(req, res, next)=>{ splitTextStyleAndMetadata(req.brew); res.header('Cache-Control', 'no-cache, no-store'); //reload the latest saved brew when pressing back button, not the cached version before save. return next(); -}); +})); //New Page -app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{ +app.get('/new/:id', asyncHandler(getBrew('share')), asyncHandler(async(req, res, next)=>{ sanitizeBrew(req.brew, 'share'); splitTextStyleAndMetadata(req.brew); const brew = { @@ -312,7 +312,7 @@ app.get('/new/:id', asyncHandler(getBrew('share')), (req, res, next)=>{ }; return next(); -}); +})); //Share Page app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, res, next)=>{ From 484b0a6dff5a13832f33b3979624645563254611 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 15 Jul 2024 16:38:19 -0400 Subject: [PATCH 089/121] simplify `getThemeBundle()` by using just one loop Also, removes need for special handling of the "first" theme. --- server/app.js | 2 +- server/homebrew.api.js | 83 ++++++++++++++---------------------------- 2 files changed, 28 insertions(+), 57 deletions(-) diff --git a/server/app.js b/server/app.js index d0160e3d0..2d0e1b16d 100644 --- a/server/app.js +++ b/server/app.js @@ -79,7 +79,7 @@ app.get('/robots.txt', (req, res)=>{ // Theme // Path for User Themes -app.get('/theme/:id', asyncHandler(getBrew('theme', false)), asyncHandler(getThemeBundle)); +app.get('/theme/:id', asyncHandler(getThemeBundle)); // Path for Static Themes app.get('/theme/:renderer/:id', asyncHandler(getThemeBundle)); diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 1af951a74..98bc4c865 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -262,69 +262,40 @@ const api = { User theme the value will come from the User Theme metadata. */ let parentReq = {}; - const completeStyles = []; + let currentTheme; + const completeStyles = []; const completeSnippets = []; - if(!req.params.renderer) { - // If this is not set, our *first* theme is a User theme. - const finalChildBrew = req.brew; - // Break up the frontmatter - splitTextStyleAndMetadata(finalChildBrew); - // If there is anything in the snippets member, append it to the snippets array. - if(finalChildBrew?.snippets) completeSnippets.push(JSON.parse(finalChildBrew.snippets)); - // If there is anything in the styles member, append it to the styles array with labelling. - if(finalChildBrew?.style) completeStyles.push(`/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.params.id} */\n\n${finalChildBrew.style}`); - // Set up the simulated request we are using for the parent-walking. - // This is our loop control. - parentReq = { - params : { - id : finalChildBrew.theme, - // This is the only value needed for the User themes. This is the shareId of the theme. - }, - renderer : finalChildBrew.renderer - // We set this for use later when checking for Static theme inheritance. - }; - while ((parentReq.params.id) && (!isStaticTheme(finalChildBrew.renderer, parentReq.params.id))) { - await api.getBrew('share')(parentReq, res, ()=>{}); - // Load the referenced Brew - splitTextStyleAndMetadata(parentReq); - // break up the meta data - if(parentReq?.snippets) completeSnippets.push(JSON.parse(parentReq.snippets)); - // If there is anything in the snippets member, append it to the snippets array. - if(parentReq?.style) { - completeStyles.push(`/* From Brew: ${req.protocol}://${req.get('host')}/share/${parentReq.params.id} */\n\n${parentReq.style}`); - // If there is anything in the styles member, append it to the styles array with labelling. - } - // Update the loop object to point to this theme's parent - parentReq.params.id = parentReq?.theme; + while (req.params.id) { + console.log(`loading theme ID ${req.params.id}`) + //=== User Themes ===// + if(!isStaticTheme(req.params.renderer, req.params.id)) { + await api.getBrew('share')(req, res, ()=>{}); + currentTheme = req.brew; + splitTextStyleAndMetadata(currentTheme); + + // If there is anything in the snippets or style members, append them to the appropriate array + if(currentTheme?.snippets) completeSnippets.push(JSON.parse(currentTheme.snippets)); + if(currentTheme?.style) completeStyles.push(`/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.params.id} */\n\n${currentTheme.style}`); + + req.params.id = currentTheme.theme; + req.params.renderer = currentTheme.renderer; + } + //=== Static Themes ===// + else { + + // NOTE: This currently makes NO attempt to do anything with Static theme Snippets. Loading of static snippets remains unchanged. + const localStyle = `@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");`; + completeStyles.push(`/* From Theme ${req.params.id} */\n\n${localStyle}`); + + req.params.id = Themes[req.params.renderer][req.params.id].baseTheme; } - } else { - // If the first theme wasn't a User theme, set up the loop control object - // This is done the same as above for consistant logic. - parentReq = { - params : { - id : req.params.id, - // This is the name of the theme - }, - renderer : req.params.renderer - // The renderer is needed for the static pathing. - }; - } - - while ((parentReq.params.id) && (isStaticTheme(parentReq.renderer, parentReq.params.id))) { - // If we have a static path - const localStyle = fs.readFileSync(path.join(__dirname, '../build/themes/', parentReq.renderer, parentReq.params.id, 'style.css')).toString(); - // Read the Theme's style.css from the filesystem - completeStyles.push(`/* From Theme ${parentReq.params.id} */\n\n${localStyle}`); - // Label and append the themes style to the styles array. - parentReq.params.id = Themes[parentReq.renderer][parentReq.params.id].baseTheme; - // NOTE: This currently makes NO attempt to do anything with Static theme Snippets. Loading of static snippets remains unchanged. } const returnObj = { + // Reverse the order of the arrays so they are listed oldest parent to youngest child. styles : completeStyles.reverse(), - // Reverse the order of the styles array so they are rendered oldest aprent to youngest child. - snippets : completeSnippets + snippets : completeSnippets.reverse() }; res.setHeader('Content-Type', 'text/json'); From af5434c9b7e4c0a2b4fe982cd9ca6b28dc83f37c Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 15 Jul 2024 16:45:55 -0400 Subject: [PATCH 090/121] cleanup --- server/homebrew.api.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 98bc4c865..1709f4f46 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -261,7 +261,7 @@ const api = { req.params.renderer: This is the Markdown+ version for the static theme. If a User theme the value will come from the User Theme metadata. */ - let parentReq = {}; + let currentTheme; const completeStyles = []; const completeSnippets = []; @@ -283,7 +283,6 @@ const api = { } //=== Static Themes ===// else { - // NOTE: This currently makes NO attempt to do anything with Static theme Snippets. Loading of static snippets remains unchanged. const localStyle = `@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");`; completeStyles.push(`/* From Theme ${req.params.id} */\n\n${localStyle}`); From dfbd85a8ce6792b33af894d3a35d4b633197c5be Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 15 Jul 2024 23:29:16 -0400 Subject: [PATCH 091/121] pass `userThemes` as a new prop, rather than inside of the brew --- client/homebrew/homebrew.jsx | 4 ++-- client/homebrew/pages/editPage/editPage.jsx | 3 +-- client/homebrew/pages/newPage/newPage.jsx | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/homebrew/homebrew.jsx b/client/homebrew/homebrew.jsx index 2489bc1ca..cd6de102d 100644 --- a/client/homebrew/homebrew.jsx +++ b/client/homebrew/homebrew.jsx @@ -66,9 +66,9 @@ const Homebrew = createClass({
- } /> + } /> } /> - } /> + } /> } /> } /> } /> diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index e3d8c1b2c..d30e42177 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -55,7 +55,6 @@ const EditPage = createClass({ autoSaveWarning : false, unsavedTime : new Date(), currentEditorPage : 0, - userThemes : this.props.brew.userThemes, displayLockMessage : this.props.brew.lock || false }; }, @@ -415,7 +414,7 @@ const EditPage = createClass({ theme={this.state.brew.theme} errors={this.state.htmlErrors} lang={this.state.brew.lang} - userThemes={this.state.brew.userThemes} + userThemes={this.props.userThemes} currentEditorPage={this.state.currentEditorPage} allowPrint={true} /> diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 84776a1b7..276ebd7af 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -218,6 +218,7 @@ const NewPage = createClass({ theme={this.state.brew.theme} errors={this.state.htmlErrors} lang={this.state.brew.lang} + userThemes={this.props.userThemes} currentEditorPage={this.state.currentEditorPage} allowPrint={true} /> From 1444581c868242bb7570e7c78c309bf36d605189 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 15 Jul 2024 23:44:07 -0400 Subject: [PATCH 092/121] pass userThemes prop to Editor -> MetadataEditor --- client/homebrew/editor/editor.jsx | 3 ++- client/homebrew/pages/editPage/editPage.jsx | 1 + client/homebrew/pages/newPage/newPage.jsx | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index efcc9c861..a766572a2 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -381,7 +381,8 @@ const Editor = createClass({ + reportError={this.props.reportError} + userThemes={this.props.userThemes}/> ; } }, diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index d30e42177..a67129ca3 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -406,6 +406,7 @@ const EditPage = createClass({ onMetaChange={this.handleMetaChange} reportError={this.errorReported} renderer={this.state.brew.renderer} + userThemes={this.props.userThemes} /> Date: Mon, 15 Jul 2024 23:47:19 -0400 Subject: [PATCH 093/121] fix crash in metadataeditor --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 4711cc73c..a71b6cbc2 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -192,7 +192,7 @@ const MetadataEditor = createClass({ renderThemeDropdown : function(){ if(!global.enable_themes) return; - const mergedThemes = { ...Themes, ...this.props.metadata.userThemes }; + const mergedThemes = { ...Themes, ...this.props.userThemes }; const listThemes = (renderer)=>{ return _.map(_.values(mergedThemes[renderer]), (theme)=>{ @@ -211,8 +211,8 @@ const MetadataEditor = createClass({ }); }; - const currentThemePath = this.props.metadata?.theme && Themes[_.upperFirst(this.props.metadata.renderer)].hasOwnProperty(this.props.metadata?.theme) ? this.props.metadata.renderer : 'Brew'; - const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`].hasOwnProperty(this.props.metadata.theme) ? mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme] : { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme.slice(1)}`}; + const currentThemePath = this.props.metadata?.theme && Themes[_.upperFirst(this.props.metadata.renderer)]?.hasOwnProperty(this.props.metadata?.theme) ? this.props.metadata.renderer : 'Brew'; + const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`]?.hasOwnProperty(this.props.metadata.theme) ? mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme] : { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme.slice(1)}`}; let dropdown; if(this.props.metadata.renderer == 'legacy') { From d741878f78dd10761e8754b1bb15e4a2d9280bbd Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 19 Jul 2024 00:00:06 -0400 Subject: [PATCH 094/121] Also remove userthemes from Brew object in `sharePage` --- client/homebrew/pages/sharePage/sharePage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 8e589b2e7..ac2455696 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -99,7 +99,7 @@ const SharePage = createClass({ style={this.props.brew.style} renderer={this.props.brew.renderer} theme={this.props.brew.theme} - userThemes={this.props.brew.userThemes} + userThemes={this.props.userThemes} allowPrint={true} />
From 0448f15322a91b143e1c7eb9d2fe87e6b31b4f58 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 19 Jul 2024 00:05:45 -0400 Subject: [PATCH 095/121] Classify user brews as V3 if they use V3 Each theme in the theme chain, including user brews, must use the same renderer. When moving to V4 or future versions, it will be important to distinguish which themes are compatible with each other --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 3 +-- server/homebrew.api.js | 8 +++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index a71b6cbc2..0eee308ff 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -192,7 +192,7 @@ const MetadataEditor = createClass({ renderThemeDropdown : function(){ if(!global.enable_themes) return; - const mergedThemes = { ...Themes, ...this.props.userThemes }; + const mergedThemes = _.merge(Themes, this.props.userThemes); const listThemes = (renderer)=>{ return _.map(_.values(mergedThemes[renderer]), (theme)=>{ @@ -230,7 +230,6 @@ const MetadataEditor = createClass({
{/*listThemes('Legacy')*/} {listThemes('V3')} - {listThemes('Brew')} ; } diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 1709f4f46..747a83b55 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -55,16 +55,18 @@ const api = { 'thumbnail', 'textBin', 'text', - 'authors' + 'authors', + 'renderer' ]; const userThemes = {}; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] }, renderer: { $ne: 'Legacy' } }); + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] }}); if(brews) { for (const brew of brews) { - userThemes[brew.shareId] = { + userThemes[brew.renderer] ??= {}; + userThemes[brew.renderer][brew.shareId] = { name : brew.title, renderer : brew.renderer, baseTheme : brew.theme, From 460358ce1fde3f140aaa0f4f556db9c8485c8bed Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 19 Jul 2024 00:09:21 -0400 Subject: [PATCH 096/121] Simplify some logic --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 0eee308ff..5d6972e49 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -196,8 +196,8 @@ const MetadataEditor = createClass({ const listThemes = (renderer)=>{ return _.map(_.values(mergedThemes[renderer]), (theme)=>{ - const preview = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; - const texture = theme?.thumbnail ? theme.thumbnail : `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`; + const preview = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; + const texture = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`; return
this.handleTheme(theme)} title={''}>

{`${theme?.author ? theme.author : renderer} : ${theme.name}`}

From f364f054f8b73864964e6ef0392401012ae9648e Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Fri, 19 Jul 2024 01:33:56 -0400 Subject: [PATCH 097/121] restore `renderStyle` `renderStyle` is still necessary; it allows us to update the style live in the component render step as the user types into the style tab. Otherwise the style is only rendered once and never updates. React also discourages directly editing the DOM ourselves, because it makes changes to the DOM that react cannot track; we should aim to provide all DOM writes inside of the component render function instead of using `document.createElement`, etc. Too that end, this commit reduces the `loadAllStylesAndSnippets` function to just fetch and parse the data; actual rendering is moved back to `renderStyle()` --- client/homebrew/brewRenderer/brewRenderer.jsx | 45 +++++++------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index fa17dfee2..fce84b5f7 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -69,6 +69,7 @@ const BrewRenderer = (props)=>{ height : PAGE_HEIGHT, isMounted : false, visibility : 'hidden', + themeBundle : {} }); const mainRef = useRef(null); @@ -128,6 +129,11 @@ const BrewRenderer = (props)=>{
; }; + const renderStyle = ()=>{ + const cleanStyle = props.style; //DOMPurify.sanitize(props.style, purifyConfig); + return
${cleanStyle} ` }} />; + }; + const renderPage = (pageText, index)=>{ if(props.renderer == 'legacy') { const html = MarkdownLegacy.render(pageText); @@ -167,39 +173,17 @@ const BrewRenderer = (props)=>{ } }; + // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected const loadAllBrewStylesAndSnippets = ()=>{ - /* - Loads the theme bundle and parses it out. - These functionally replaces the previous renderStyles() function but needs to wait until the window is mounted. - */ const rendererPath = isStaticTheme(props.renderer, props.theme) ? `/${props.renderer}/` : '/'; - // Check for a User or Static Theme to change the endpoint path + + // Load the themeBundle from the endpoint as an object fetch(`${window.location.protocol}//${window.location.host}/theme${rendererPath}${props.theme}`).then((response)=>response.json()).then((themeBundle)=>{ - // Load the themeBundle from the endpoint as an object. - const documentFrame = document.getElementById('BrewRenderer'); - const iframeDocument = documentFrame.contentDocument || documentFrame.contentWindow.document; - // Find the brew frame Document root. - - for (let style=0; style < themeBundle.styles.length; style++){ - /* - Walk through the styles array on the Theme Bundle. - Create a new style node and add it to the Brew Frame - */ - const newStyles = document.createElement('style'); - newStyles.appendChild(document.createTextNode(`${themeBundle.styles[style]}\n`)); - iframeDocument.head.appendChild(newStyles); - - } - /* - Add the local brew styling to the Brew Frame - */ - const newStyles = document.createElement('style'); - const cleanStyle = props.style; //DOMPurify.sanitize(props.style, purifyConfig); - - newStyles.appendChild(document.createTextNode(`/* Local Brew Styling */\n\n${cleanStyle}`)); - iframeDocument.head.appendChild(newStyles); - - // TO-DO - Walk the snippets returns and add them to the appropriate menu. + themeBundle.joinedStyles = themeBundle.styles.map(style => ``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); + setState((prevState)=>({ + ...prevState, + themeBundle : themeBundle + })); }); }; @@ -260,6 +244,7 @@ const BrewRenderer = (props)=>{ {state.isMounted && <> + {renderStyle()}
{renderPages()}
From 0a5ff213de4c90ecf3462dfe970d9f7c3bad64e5 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 20 Jul 2024 11:39:23 -0400 Subject: [PATCH 098/121] use same theme endpoint for user and static themes `getThemeBundle()` rework no longer needs two separate endpoints --- client/homebrew/brewRenderer/brewRenderer.jsx | 5 +---- server/app.js | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index fce84b5f7..baea64d3d 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -175,10 +175,7 @@ const BrewRenderer = (props)=>{ // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected const loadAllBrewStylesAndSnippets = ()=>{ - const rendererPath = isStaticTheme(props.renderer, props.theme) ? `/${props.renderer}/` : '/'; - - // Load the themeBundle from the endpoint as an object - fetch(`${window.location.protocol}//${window.location.host}/theme${rendererPath}${props.theme}`).then((response)=>response.json()).then((themeBundle)=>{ + fetch(`${window.location.protocol}//${window.location.host}/theme/${props.renderer}/${props.theme}`).then((response)=>response.json()).then((themeBundle)=>{ themeBundle.joinedStyles = themeBundle.styles.map(style => ``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); setState((prevState)=>({ ...prevState, diff --git a/server/app.js b/server/app.js index 2d0e1b16d..62976ade6 100644 --- a/server/app.js +++ b/server/app.js @@ -78,9 +78,6 @@ app.get('/robots.txt', (req, res)=>{ }); // Theme -// Path for User Themes -app.get('/theme/:id', asyncHandler(getThemeBundle)); -// Path for Static Themes app.get('/theme/:renderer/:id', asyncHandler(getThemeBundle)); //Home page From 45f7080afd1744624d34efb78e9d925ad52a0bec Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 21 Jul 2024 16:25:24 -0400 Subject: [PATCH 099/121] Move `loadAllBrewStylesAndSnippets` to the parent page component Themes contain both CSS and Snippets. The brewRenderer only cares about the CSS, but other components need the Snippets. Better to have the parent "editPage", etc. load the theme bundles and pass them down to each child that needs it, rather than trying to pass from the child up. This also fixes the `metadataEditor.jsx` not being able to change themes live; A new theme bundle is now loaded when a new theme is selected, instead of only the first time the BrewRenderer mounts. Also renamed to "fetchThemeBundle" --- client/homebrew/brewRenderer/brewRenderer.jsx | 16 ++----------- .../editor/metadataEditor/metadataEditor.jsx | 2 +- client/homebrew/pages/editPage/editPage.jsx | 24 ++++++++++++++++--- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index baea64d3d..c01182d7b 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -61,6 +61,7 @@ const BrewRenderer = (props)=>{ lang : '', errors : [], currentEditorPage : 0, + themeBundle : {}, ...props }; @@ -69,7 +70,6 @@ const BrewRenderer = (props)=>{ height : PAGE_HEIGHT, isMounted : false, visibility : 'hidden', - themeBundle : {} }); const mainRef = useRef(null); @@ -131,7 +131,7 @@ const BrewRenderer = (props)=>{ const renderStyle = ()=>{ const cleanStyle = props.style; //DOMPurify.sanitize(props.style, purifyConfig); - return
${cleanStyle} ` }} />; + return
${cleanStyle} ` }} />; }; const renderPage = (pageText, index)=>{ @@ -173,19 +173,7 @@ const BrewRenderer = (props)=>{ } }; - // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected - const loadAllBrewStylesAndSnippets = ()=>{ - fetch(`${window.location.protocol}//${window.location.host}/theme/${props.renderer}/${props.theme}`).then((response)=>response.json()).then((themeBundle)=>{ - themeBundle.joinedStyles = themeBundle.styles.map(style => ``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); - setState((prevState)=>({ - ...prevState, - themeBundle : themeBundle - })); - }); - }; - const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount" - loadAllBrewStylesAndSnippets(); // Load the brew's inherited and local styles. setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame updateSize(); window.addEventListener('resize', updateSize); diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 5d6972e49..2ccf5c440 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -111,7 +111,7 @@ const MetadataEditor = createClass({ handleTheme : function(theme){ this.props.metadata.renderer = theme.renderer; this.props.metadata.theme = theme.path; - this.props.onChange(this.props.metadata); + this.props.onChange(this.props.metadata, "theme"); }, handleLanguage : function(languageCode){ diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index a67129ca3..1c6fe1620 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -55,7 +55,8 @@ const EditPage = createClass({ autoSaveWarning : false, unsavedTime : new Date(), currentEditorPage : 0, - displayLockMessage : this.props.brew.lock || false + displayLockMessage : this.props.brew.lock || false, + themeBundle : {} }; }, @@ -87,6 +88,8 @@ const EditPage = createClass({ htmlErrors : Markdown.validate(prevState.brew.text) })); + this.fetchThemeBundle(this.props.brew.renderer, this.props.brew.theme); + document.addEventListener('keydown', this.handleControlKeys); }, componentWillUnmount : function() { @@ -130,7 +133,10 @@ const EditPage = createClass({ }), ()=>{if(this.state.autoSave) this.trySave();}); }, - handleMetaChange : function(metadata){ + handleMetaChange : function(metadata, field=undefined){ + if(field == "theme") // Fetch theme bundle only if theme was changed + this.fetchThemeBundle(metadata.renderer, metadata.theme); + this.setState((prevState)=>({ brew : { ...prevState.brew, @@ -138,13 +144,24 @@ const EditPage = createClass({ }, isPending : true, }), ()=>{if(this.state.autoSave) this.trySave();}); - }, hasChanges : function(){ return !_.isEqual(this.state.brew, this.savedBrew); }, + // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected + fetchThemeBundle : function(renderer, theme) { + fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ + themeBundle.joinedStyles = themeBundle.styles.map(style => ``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); + this.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT + ...prevState, + themeBundle : themeBundle + })); + }); + + }, + trySave : function(immediate=false){ if(!this.debounceSave) this.debounceSave = _.debounce(this.save, SAVE_TIMEOUT); if(this.hasChanges()){ @@ -413,6 +430,7 @@ const EditPage = createClass({ style={this.state.brew.style} renderer={this.state.brew.renderer} theme={this.state.brew.theme} + themeBundle={this.state.themeBundle} errors={this.state.htmlErrors} lang={this.state.brew.lang} userThemes={this.props.userThemes} From c0123b96eb018975ceb2b37740628fa1b20556a4 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 22 Jul 2024 02:44:41 -0400 Subject: [PATCH 100/121] Support snippet compilation Original handling of snippets only worked if the current selected theme was a staticTheme. This now fully merges all snippets through the theme chain no matter what the top-level theme is. So user themes built on 5ePHB can benefit from 5ePHB snippets too. User input of user snippets will be a later PR, but merging them into static snippets is now supported. --- client/homebrew/editor/editor.jsx | 1 + .../homebrew/editor/snippetbar/snippetbar.jsx | 44 ++++++++----------- client/homebrew/pages/editPage/editPage.jsx | 1 + server/homebrew.api.js | 5 ++- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index a766572a2..cb5d122f1 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -425,6 +425,7 @@ const Editor = createClass({ historySize={this.historySize()} currentEditorTheme={this.state.editorTheme} updateEditorTheme={this.updateEditorTheme} + snippetBundle={this.props.snippetBundle} cursorPos={this.codeEditor.current?.getCursorPosition() || {}} /> {this.renderEditor()} diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 445ca2748..34687f020 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -6,9 +6,6 @@ const _ = require('lodash'); const cx = require('classnames'); //Import all themes - -const Themes = require('themes/themes.json'); - const ThemeSnippets = {}; ThemeSnippets['Legacy_5ePHB'] = require('themes/Legacy/5ePHB/snippets.js'); ThemeSnippets['V3_5ePHB'] = require('themes/V3/5ePHB/snippets.js'); @@ -40,7 +37,8 @@ const Snippetbar = createClass({ foldCode : ()=>{}, unfoldCode : ()=>{}, updateEditorTheme : ()=>{}, - cursorPos : {} + cursorPos : {}, + snippetBundle : [] }; }, @@ -53,21 +51,15 @@ const Snippetbar = createClass({ }, componentDidMount : async function() { - const rendererPath = this.props.renderer == 'V3' ? 'V3' : 'Legacy'; - const themePath = this.props.theme ?? '5ePHB'; - let snippets = _.cloneDeep(ThemeSnippets[`${rendererPath}_${themePath}`]); - snippets = this.compileSnippets(rendererPath, themePath, snippets); + let snippets = this.compileSnippets(); this.setState({ snippets : snippets }); }, componentDidUpdate : async function(prevProps) { - if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme) { - const rendererPath = this.props.renderer == 'V3' ? 'V3' : 'Legacy'; - const themePath = this.props.theme ?? '5ePHB'; - let snippets = _.cloneDeep(ThemeSnippets[`${rendererPath}_${themePath}`]); - snippets = this.compileSnippets(rendererPath, themePath, snippets); + if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme || prevProps.snippetBundle != this.props.snippetBundle) { + let snippets = this.compileSnippets(); this.setState({ snippets : snippets }); @@ -75,26 +67,26 @@ const Snippetbar = createClass({ }, - mergeCustomizer : function(valueA, valueB, key) { + mergeCustomizer : function(oldValue, newValue, key) { if(key == 'snippets') { - const result = _.reverse(_.unionBy(_.reverse(valueB), _.reverse(valueA), 'name')); // Join snippets together, with preference for the current theme over the base theme + const result = _.reverse(_.unionBy(_.reverse(newValue), _.reverse(oldValue), 'name')); // Join snippets together, with preference for the child theme over the parent theme return _.filter(result, 'gen'); //Only keep snippets with a 'gen' property. } }, - compileSnippets : function(rendererPath, themePath, snippets) { - let compiledSnippets = snippets; - const baseSnippetsPath = themePath && (Themes[rendererPath].hasOwnProperty(themePath)) ? Themes[rendererPath][themePath].baseSnippets : false; + compileSnippets : function() { + let compiledSnippets = []; - const objB = _.keyBy(compiledSnippets, 'groupName'); + let oldSnippets = _.keyBy(compiledSnippets, 'groupName'); + + for (let snippets of this.props.snippetBundle) { + if (typeof(snippets) == "string") // load staticThemes as needed; they were sent as just a file name + snippets = ThemeSnippets[snippets]; - if(baseSnippetsPath) { - const objA = _.keyBy(_.cloneDeep(ThemeSnippets[`${rendererPath}_${baseSnippetsPath}`]), 'groupName'); - compiledSnippets = _.values(_.mergeWith(objA, objB, this.mergeCustomizer)); - compiledSnippets = this.compileSnippets(rendererPath, baseSnippetsPath, _.cloneDeep(compiledSnippets)); - } else { - const objA = _.keyBy(_.cloneDeep(ThemeSnippets[`${rendererPath}_Blank`]), 'groupName'); - compiledSnippets = _.values(_.mergeWith(objA, objB, this.mergeCustomizer)); + let newSnippets = _.keyBy(_.cloneDeep(snippets), 'groupName'); + compiledSnippets = _.values(_.mergeWith(oldSnippets, newSnippets, this.mergeCustomizer)); + + oldSnippets = _.keyBy(compiledSnippets, 'groupName'); } return compiledSnippets; }, diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 1c6fe1620..a36d272db 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -424,6 +424,7 @@ const EditPage = createClass({ reportError={this.errorReported} renderer={this.state.brew.renderer} userThemes={this.props.userThemes} + snippetBundle={this.state.themeBundle.snippets} /> Date: Mon, 22 Jul 2024 02:46:26 -0400 Subject: [PATCH 101/121] Lint --- .../editor/metadataEditor/metadataEditor.jsx | 4 ++-- client/homebrew/editor/snippetbar/snippetbar.jsx | 10 +++++----- client/homebrew/pages/editPage/editPage.jsx | 8 ++++---- server/homebrew.api.js | 5 ++--- server/homebrew.api.spec.js | 14 +++++++------- 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 2ccf5c440..0c5b56304 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -111,7 +111,7 @@ const MetadataEditor = createClass({ handleTheme : function(theme){ this.props.metadata.renderer = theme.renderer; this.props.metadata.theme = theme.path; - this.props.onChange(this.props.metadata, "theme"); + this.props.onChange(this.props.metadata, 'theme'); }, handleLanguage : function(languageCode){ @@ -212,7 +212,7 @@ const MetadataEditor = createClass({ }; const currentThemePath = this.props.metadata?.theme && Themes[_.upperFirst(this.props.metadata.renderer)]?.hasOwnProperty(this.props.metadata?.theme) ? this.props.metadata.renderer : 'Brew'; - const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`]?.hasOwnProperty(this.props.metadata.theme) ? mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme] : { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme.slice(1)}`}; + const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`]?.hasOwnProperty(this.props.metadata.theme) ? mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme] : { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme.slice(1)}` }; let dropdown; if(this.props.metadata.renderer == 'legacy') { diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx index 34687f020..af493c961 100644 --- a/client/homebrew/editor/snippetbar/snippetbar.jsx +++ b/client/homebrew/editor/snippetbar/snippetbar.jsx @@ -51,7 +51,7 @@ const Snippetbar = createClass({ }, componentDidMount : async function() { - let snippets = this.compileSnippets(); + const snippets = this.compileSnippets(); this.setState({ snippets : snippets }); @@ -59,7 +59,7 @@ const Snippetbar = createClass({ componentDidUpdate : async function(prevProps) { if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme || prevProps.snippetBundle != this.props.snippetBundle) { - let snippets = this.compileSnippets(); + const snippets = this.compileSnippets(); this.setState({ snippets : snippets }); @@ -78,12 +78,12 @@ const Snippetbar = createClass({ let compiledSnippets = []; let oldSnippets = _.keyBy(compiledSnippets, 'groupName'); - + for (let snippets of this.props.snippetBundle) { - if (typeof(snippets) == "string") // load staticThemes as needed; they were sent as just a file name + if(typeof(snippets) == 'string') // load staticThemes as needed; they were sent as just a file name snippets = ThemeSnippets[snippets]; - let newSnippets = _.keyBy(_.cloneDeep(snippets), 'groupName'); + const newSnippets = _.keyBy(_.cloneDeep(snippets), 'groupName'); compiledSnippets = _.values(_.mergeWith(oldSnippets, newSnippets, this.mergeCustomizer)); oldSnippets = _.keyBy(compiledSnippets, 'groupName'); diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index a36d272db..f8040d5c3 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -134,9 +134,9 @@ const EditPage = createClass({ }, handleMetaChange : function(metadata, field=undefined){ - if(field == "theme") // Fetch theme bundle only if theme was changed + if(field == 'theme') // Fetch theme bundle only if theme was changed this.fetchThemeBundle(metadata.renderer, metadata.theme); - + this.setState((prevState)=>({ brew : { ...prevState.brew, @@ -153,13 +153,13 @@ const EditPage = createClass({ // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected fetchThemeBundle : function(renderer, theme) { fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ - themeBundle.joinedStyles = themeBundle.styles.map(style => ``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); + themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); this.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT ...prevState, themeBundle : themeBundle })); }); - + }, trySave : function(immediate=false){ diff --git a/server/homebrew.api.js b/server/homebrew.api.js index b8807a439..aa3eded0a 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -61,7 +61,7 @@ const api = { const userThemes = {}; - const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] }}); + const brews = await HomebrewModel.getByUser(username, true, fields, { tags: { $in: ['meta:theme', 'meta:Theme'] } }); if(brews) { for (const brew of brews) { @@ -269,7 +269,6 @@ const api = { const completeSnippets = []; while (req.params.id) { - console.log(`loading theme ID ${req.params.id}`) //=== User Themes ===// if(!isStaticTheme(req.params.renderer, req.params.id)) { await api.getBrew('share')(req, res, ()=>{}); @@ -282,7 +281,7 @@ const api = { req.params.id = currentTheme.theme; req.params.renderer = currentTheme.renderer; - } + } //=== Static Themes ===// else { const localSnippets = `${req.params.renderer}_${req.params.id}`; // Just log the name for loading on client diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 5eb8a407c..67f4abe5f 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -288,14 +288,14 @@ describe('Tests for api', ()=>{ textBin : undefined, version : undefined, userThemes : { - Brew: {} + Brew : {} }, - createdAt : undefined, - gDrive : false, - style : undefined, - trashed : false, - updatedAt : undefined, - views : 0 + createdAt : undefined, + gDrive : false, + style : undefined, + trashed : false, + updatedAt : undefined, + views : 0 }); expect(next).toHaveBeenCalled(); expect(api.getId).toHaveBeenCalledWith(req); From 0b01f27d11a379c7a786d12f9231f472bbc3514b Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 23 Jul 2024 16:26:33 -0400 Subject: [PATCH 102/121] Load theme bundles on `/share` page --- client/homebrew/pages/sharePage/sharePage.jsx | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index ac2455696..90dc1959a 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -18,18 +18,38 @@ const SharePage = createClass({ displayName : 'SharePage', getDefaultProps : function() { return { - brew : DEFAULT_BREW_LOAD + brew : DEFAULT_BREW_LOAD, + themeBundle : {} + }; + }, + + getInitialState : function() { + return { + themeBundle : this.props.themeBundle }; }, componentDidMount : function() { document.addEventListener('keydown', this.handleControlKeys); + + this.fetchThemeBundle(this.props.brew.renderer, this.props.brew.theme); }, componentWillUnmount : function() { document.removeEventListener('keydown', this.handleControlKeys); }, + // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected + fetchThemeBundle : function(renderer, theme) { + fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ + themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); + this.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT + ...prevState, + themeBundle : themeBundle + })); + }); + }, + handleControlKeys : function(e){ if(!(e.ctrlKey || e.metaKey)) return; const P_KEY = 80; @@ -99,7 +119,7 @@ const SharePage = createClass({ style={this.props.brew.style} renderer={this.props.brew.renderer} theme={this.props.brew.theme} - userThemes={this.props.userThemes} + themeBundle={this.state.themeBundle} allowPrint={true} />
From 22b6aa14f0e4882ac3c9a12ea97822c276e13e12 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 23 Jul 2024 16:43:23 -0400 Subject: [PATCH 103/121] Add to /new page --- client/homebrew/homebrew.jsx | 2 +- client/homebrew/pages/editPage/editPage.jsx | 2 -- client/homebrew/pages/newPage/newPage.jsx | 25 ++++++++++++++++--- client/homebrew/pages/sharePage/sharePage.jsx | 3 +-- server/app.js | 14 ++++++++++- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/client/homebrew/homebrew.jsx b/client/homebrew/homebrew.jsx index cd6de102d..1df417872 100644 --- a/client/homebrew/homebrew.jsx +++ b/client/homebrew/homebrew.jsx @@ -69,7 +69,7 @@ const Homebrew = createClass({ } /> } /> } /> - } /> + } /> } /> } /> } /> diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index f8040d5c3..e3e7990df 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -159,7 +159,6 @@ const EditPage = createClass({ themeBundle : themeBundle })); }); - }, trySave : function(immediate=false){ @@ -434,7 +433,6 @@ const EditPage = createClass({ themeBundle={this.state.themeBundle} errors={this.state.htmlErrors} lang={this.state.brew.lang} - userThemes={this.props.userThemes} currentEditorPage={this.state.currentEditorPage} allowPrint={true} /> diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 878896a06..4b223faa7 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -44,7 +44,8 @@ const NewPage = createClass({ saveGoogle : (global.account && global.account.googleId ? true : false), error : null, htmlErrors : Markdown.validate(brew.text), - currentEditorPage : 0 + currentEditorPage : 0, + themeBundle : {} }; }, @@ -77,6 +78,8 @@ const NewPage = createClass({ saveGoogle : (saveStorage == 'GOOGLE-DRIVE' && this.state.saveGoogle) }); + this.fetchThemeBundle(this.props.brew.renderer, this.props.brew.theme); + localStorage.setItem(BREWKEY, brew.text); if(brew.style) localStorage.setItem(STYLEKEY, brew.style); @@ -86,6 +89,17 @@ const NewPage = createClass({ document.removeEventListener('keydown', this.handleControlKeys); }, + // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected + fetchThemeBundle : function(renderer, theme) { + fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ + themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); + this.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT + ...prevState, + themeBundle : themeBundle + })); + }); + }, + handleControlKeys : function(e){ if(!(e.ctrlKey || e.metaKey)) return; const S_KEY = 83; @@ -122,7 +136,10 @@ const NewPage = createClass({ localStorage.setItem(STYLEKEY, style); }, - handleMetaChange : function(metadata){ + handleMetaChange : function(metadata, field=undefined){ + if(field == 'theme') // Fetch theme bundle only if theme was changed + this.fetchThemeBundle(metadata.renderer, metadata.theme); + this.setState((prevState)=>({ brew : { ...prevState.brew, ...metadata }, }), ()=>{ @@ -157,7 +174,7 @@ const NewPage = createClass({ .catch((err)=>{ this.setState({ isSaving: false, error: err }); }); - if(!res) return; + if(!res) return; brew = res.body; localStorage.removeItem(BREWKEY); @@ -217,9 +234,9 @@ const NewPage = createClass({ style={this.state.brew.style} renderer={this.state.brew.renderer} theme={this.state.brew.theme} + themeBundle={this.state.themeBundle} errors={this.state.htmlErrors} lang={this.state.brew.lang} - userThemes={this.props.userThemes} currentEditorPage={this.state.currentEditorPage} allowPrint={true} /> diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 90dc1959a..c1f044d2d 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -19,13 +19,12 @@ const SharePage = createClass({ getDefaultProps : function() { return { brew : DEFAULT_BREW_LOAD, - themeBundle : {} }; }, getInitialState : function() { return { - themeBundle : this.props.themeBundle + themeBundle : {} }; }, diff --git a/server/app.js b/server/app.js index 62976ade6..5d3e74925 100644 --- a/server/app.js +++ b/server/app.js @@ -286,7 +286,7 @@ app.get('/edit/:id', asyncHandler(getBrew('edit')), asyncHandler(async(req, res, return next(); })); -//New Page +//New Page from ID app.get('/new/:id', asyncHandler(getBrew('share')), asyncHandler(async(req, res, next)=>{ sanitizeBrew(req.brew, 'share'); splitTextStyleAndMetadata(req.brew); @@ -311,6 +311,18 @@ app.get('/new/:id', asyncHandler(getBrew('share')), asyncHandler(async(req, res, return next(); })); +//New Page +app.get('/new', asyncHandler(async(req, res, next)=>{ + req.userThemes = await(getUsersBrewThemes(req.account?.username)); + + req.ogMeta = { ...defaultMetaTags, + title : 'New', + description : 'Start crafting your homebrew on the Homebrewery!' + }; + + return next(); +})); + //Share Page app.get('/share/:id', asyncHandler(getBrew('share')), asyncHandler(async (req, res, next)=>{ const { brew } = req; From ac82e3ecb2545088590d63846c3160be1edd680b Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 23 Jul 2024 16:50:29 -0400 Subject: [PATCH 104/121] Add to home page --- client/homebrew/pages/homePage/homePage.jsx | 19 ++++++++++++++++++- server/app.js | 3 ++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 1aa816df2..0609d5b8b 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -34,12 +34,28 @@ const HomePage = createClass({ brew : this.props.brew, welcomeText : this.props.brew.text, error : undefined, - currentEditorPage : 0 + currentEditorPage : 0, + themeBundle : {} }; }, editor : React.createRef(null), + componentDidMount : function() { + this.fetchThemeBundle(this.props.brew.renderer, this.props.brew.theme); + }, + + // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected + fetchThemeBundle : function(renderer, theme) { + fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ + themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); + this.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT + ...prevState, + themeBundle : themeBundle + })); + }); + }, + handleSave : function(){ request.post('/api') .send(this.state.brew) @@ -95,6 +111,7 @@ const HomePage = createClass({ style={this.state.brew.style} renderer={this.state.brew.renderer} currentEditorPage={this.state.currentEditorPage} + themeBundle={this.state.themeBundle} />
diff --git a/server/app.js b/server/app.js index 5d3e74925..0de404c1e 100644 --- a/server/app.js +++ b/server/app.js @@ -84,7 +84,8 @@ app.get('/theme/:renderer/:id', asyncHandler(getThemeBundle)); app.get('/', (req, res, next)=>{ req.brew = { text : welcomeText, - renderer : 'V3' + renderer : 'V3', + theme : '5ePHB' }, req.ogMeta = { ...defaultMetaTags, From 27c52fc244671931f9d4ebd27f0b049ea8c05c3e Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 23 Jul 2024 17:11:48 -0400 Subject: [PATCH 105/121] Fix loading CSS for Legacy --- client/homebrew/editor/metadataEditor/metadataEditor.jsx | 2 +- client/homebrew/pages/editPage/editPage.jsx | 2 +- client/homebrew/pages/newPage/newPage.jsx | 2 +- server/app.js | 3 ++- server/homebrew.api.js | 4 +--- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 0c5b56304..473b2ab69 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -99,7 +99,7 @@ const MetadataEditor = createClass({ if(renderer == 'legacy') this.props.metadata.theme = '5ePHB'; } - this.props.onChange(this.props.metadata); + this.props.onChange(this.props.metadata, 'renderer'); }, handlePublish : function(val){ this.props.onChange({ diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index e3e7990df..05bd79d4d 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -134,7 +134,7 @@ const EditPage = createClass({ }, handleMetaChange : function(metadata, field=undefined){ - if(field == 'theme') // Fetch theme bundle only if theme was changed + if(field == 'theme' || field == 'renderer') // Fetch theme bundle only if theme or renderer was changed this.fetchThemeBundle(metadata.renderer, metadata.theme); this.setState((prevState)=>({ diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 4b223faa7..e8c2636b0 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -137,7 +137,7 @@ const NewPage = createClass({ }, handleMetaChange : function(metadata, field=undefined){ - if(field == 'theme') // Fetch theme bundle only if theme was changed + if(field == 'theme' || field == 'renderer') // Fetch theme bundle only if theme or renderer was changed this.fetchThemeBundle(metadata.renderer, metadata.theme); this.setState((prevState)=>({ diff --git a/server/app.js b/server/app.js index 0de404c1e..8ad35ca35 100644 --- a/server/app.js +++ b/server/app.js @@ -101,7 +101,8 @@ app.get('/', (req, res, next)=>{ app.get('/legacy', (req, res, next)=>{ req.brew = { text : welcomeTextLegacy, - renderer : 'legacy' + renderer : 'legacy', + theme : '5ePHB' }, req.ogMeta = { ...defaultMetaTags, diff --git a/server/homebrew.api.js b/server/homebrew.api.js index aa3eded0a..0b6218597 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -8,8 +8,6 @@ const Markdown = require('../shared/naturalcrit/markdown.js'); const yaml = require('js-yaml'); const asyncHandler = require('express-async-handler'); const { nanoid } = require('nanoid'); -const path = require('path'); -const fs = require('fs'); const { splitTextStyleAndMetadata } = require('../shared/helpers.js'); const { DEFAULT_BREW, DEFAULT_BREW_LOAD } = require('./brewDefaults.js'); @@ -263,7 +261,7 @@ const api = { req.params.renderer: This is the Markdown+ version for the static theme. If a User theme the value will come from the User Theme metadata. */ - + req.params.renderer = _.upperFirst(req.params.renderer); let currentTheme; const completeStyles = []; const completeSnippets = []; From 82f73fb21d42581baf3b3b65074f8f9ad3108dac Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 23 Jul 2024 17:24:50 -0400 Subject: [PATCH 106/121] cleanup --- client/homebrew/brewRenderer/brewRenderer.jsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index c01182d7b..cdbbfc157 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -18,12 +18,6 @@ const { printCurrentBrew } = require('../../../shared/helpers.js'); const DOMPurify = require('dompurify'); const purifyConfig = { FORCE_BODY: true, SANITIZE_DOM: false }; -const staticThemes = require('themes/themes.json'); - -const isStaticTheme = (renderer, themeName)=>{ - return staticThemes[renderer]?.[themeName] !== undefined; -}; - const PAGE_HEIGHT = 1056; const INITIAL_CONTENT = dedent` @@ -191,12 +185,6 @@ const BrewRenderer = (props)=>{ document.dispatchEvent(new MouseEvent('click')); }; - let rendererPath = ''; - const themePath = props.theme; - - if(staticThemes[_.upperFirst(props.renderer)]?.[props.theme] !== undefined) //Change CSS path if is staticTheme - rendererPath = `${_.upperFirst(props.renderer)}/`; - return ( <> {/*render dummy page while iFrame is mounting.*/} From ddc569377825d1582172fcbf71dd55a82cc47b8a Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 23 Jul 2024 17:31:07 -0400 Subject: [PATCH 107/121] revert package-lock --- package-lock.json | 2219 +++++++++++++++++++++++++++++---------------- 1 file changed, 1452 insertions(+), 767 deletions(-) diff --git a/package-lock.json b/package-lock.json index 556854e7a..cce4d5577 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,13 +67,22 @@ "npm": "^10.2.x" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" @@ -128,6 +137,11 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, "node_modules/@babel/generator": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", @@ -142,6 +156,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", @@ -219,9 +246,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", - "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -770,12 +797,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", - "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1797,9 +1824,9 @@ "dev": true }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.3.tgz", - "integrity": "sha512-xI/tL2zxzEbESvnSxwFgwvy5HS00oCXxL4MLs6HUiDcYfwowsoQaABKxUElp1ARITrINzBnsECOc1q0eg2GOrA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.1.tgz", + "integrity": "sha512-xrvsmVUtefWMWQsGgFffqWSK03pZ1vfDki4IVIIUxxDKnGBzqNgv0A7SB1oXtVNEkcVO8xi1ZrTL29HhSu5kGA==", "dev": true, "funding": [ { @@ -1815,13 +1842,13 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.3.1" + "@csstools/css-tokenizer": "^2.2.0" } }, "node_modules/@csstools/css-tokenizer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.3.1.tgz", - "integrity": "sha512-iMNHTyxLbBlWIfGtabT157LH9DUx9X8+Y3oymFEuMj8HNc+rpE3dPFGFgHjpKfjeFDjLjYIAIhXPGvS2lKxL9g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.0.tgz", + "integrity": "sha512-wErmsWCbsmig8sQKkM6pFhr/oPha1bHfvxsUY5CYSQxwyhA9Ulrs8EqCgClhg4Tgg2XapVstGqSVcz0xOYizZA==", "dev": true, "funding": [ { @@ -1838,9 +1865,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.11.tgz", - "integrity": "sha512-uox5MVhvNHqitPP+SynrB1o8oPxPMt2JLgp5ghJOWf54WGQ5OKu47efne49r1SWqs3wRP8xSWjnO9MBKxhB1dA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.4.tgz", + "integrity": "sha512-V/OUXYX91tAC1CDsiY+HotIcJR+vPtzrX8pCplCpT++i8ThZZsq5F5dzZh/bDM3WUOjrvC1ljed1oSJxMfjqhw==", "dev": true, "funding": [ { @@ -1856,14 +1883,14 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.6.3", - "@csstools/css-tokenizer": "^2.3.1" + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0" } }, "node_modules/@csstools/selector-specificity": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz", - "integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz", + "integrity": "sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==", "dev": true, "funding": [ { @@ -1898,9 +1925,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -1930,9 +1957,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2004,9 +2031,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -2637,6 +2664,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "node_modules/@jest/transform/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2746,22 +2779,21 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "engines": { "node": ">=6.0.0" } @@ -2775,9 +2807,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -2846,9 +2878,9 @@ "dev": true }, "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "dependencies": { "type-detect": "4.0.8" @@ -2864,9 +2896,9 @@ } }, "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -2877,18 +2909,18 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -2896,72 +2928,81 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" } }, "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "node_modules/@types/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } + "version": "18.15.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz", + "integrity": "sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==", + "dev": true }, "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, "node_modules/@types/webidl-conversions": { @@ -2978,31 +3019,31 @@ } }, "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.10.0.tgz", - "integrity": "sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -3010,12 +3051,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.10.0.tgz", - "integrity": "sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -3023,22 +3064,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.10.0.tgz", - "integrity": "sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -3059,10 +3100,22 @@ "balanced-match": "^1.0.0" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -3075,10 +3128,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" }, @@ -3086,39 +3142,81 @@ "node": ">=10" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@typescript-eslint/utils": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.10.0.tgz", - "integrity": "sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.10.0", - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/typescript-estree": "7.10.0" + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.10.0.tgz", - "integrity": "sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==", + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.10.0", - "eslint-visitor-keys": "^3.4.3" + "yallist": "^4.0.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -3131,6 +3229,11 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -3144,9 +3247,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -3194,9 +3297,9 @@ } }, "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "dependencies": { "debug": "^4.3.4" }, @@ -3373,24 +3476,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array.prototype.flatmap": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", @@ -3459,28 +3544,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" } }, "node_modules/asn1.js/node_modules/bn.js": { @@ -3489,12 +3566,25 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "node_modules/assert": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", - "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "dependencies": { - "object.assign": "^4.1.4", - "util": "^0.10.4" + "object-assign": "^4.1.1", + "util": "0.10.3" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==" + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==", + "dependencies": { + "inherits": "2.0.1" } }, "node_modules/assign-symbols": { @@ -3515,9 +3605,9 @@ } }, "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, "node_modules/async-each": { "version": "1.0.6", @@ -3708,12 +3798,12 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", - "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.2", + "@babel/helper-define-polyfill-provider": "^0.6.1", "semver": "^6.3.1" }, "peerDependencies": { @@ -3733,11 +3823,11 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", - "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.1.tgz", + "integrity": "sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2" + "@babel/helper-define-polyfill-provider": "^0.6.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -3815,16 +3905,47 @@ "node": ">=0.10.0" } }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^6.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/base64-js": { @@ -3855,14 +3976,11 @@ } }, "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bindings": { @@ -3956,6 +4074,33 @@ "browser-pack": "bin/cmd.js" } }, + "node_modules/browser-pack/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browser-pack/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/browser-pack/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/browser-pack/node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -4078,23 +4223,22 @@ } }, "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", "dependencies": { "bn.js": "^5.2.1", "browserify-rsa": "^4.1.0", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", + "elliptic": "^6.5.4", "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", - "readable-stream": "^2.3.8", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 0.12" + "node": ">= 4" } }, "node_modules/browserify-zlib": { @@ -4110,6 +4254,33 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" }, + "node_modules/browserify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browserify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/browserify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/browserify/node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -4307,9 +4478,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001620", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz", - "integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==", + "version": "1.0.30001599", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz", + "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==", "funding": [ { "type": "opencollective", @@ -4348,9 +4519,15 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4363,9 +4540,6 @@ "engines": { "node": ">= 8.10.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -4382,9 +4556,9 @@ } }, "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", "dev": true, "funding": [ { @@ -4406,9 +4580,9 @@ } }, "node_modules/cjs-module-lexer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", - "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, "node_modules/class-utils": { @@ -4455,9 +4629,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.16", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", - "integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==" + "version": "5.65.12", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.12.tgz", + "integrity": "sha512-z2jlHBocElRnPYysN2HAuhXbO3DNB0bcSKmNz3hcWR2Js2Dkhc1bEOxG93Z3DeUrnm+qx56XOY5wQmbP5KY0sw==" }, "node_modules/collect-v8-coverage": { "version": "1.0.2", @@ -4532,12 +4706,9 @@ } }, "node_modules/component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "node_modules/concat-map": { "version": "0.0.1", @@ -4558,6 +4729,33 @@ "typedarray": "^0.0.6" } }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", @@ -4588,9 +4786,10 @@ } }, "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "node_modules/cookie": { "version": "0.4.1", @@ -4642,9 +4841,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", + "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", "dependencies": { "browserslist": "^4.23.0" }, @@ -4659,14 +4858,14 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", "dev": true, "dependencies": { - "import-fresh": "^3.3.0", + "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", + "parse-json": "^5.0.0", "path-type": "^4.0.0" }, "engines": { @@ -4674,14 +4873,6 @@ }, "funding": { "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, "node_modules/create-ecdh": { @@ -4859,9 +5050,9 @@ } }, "node_modules/css-functions-list": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz", - "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.1.tgz", + "integrity": "sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==", "dev": true, "engines": { "node": ">=12 || >=16" @@ -5019,9 +5210,9 @@ } }, "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -5035,8 +5226,7 @@ "node_modules/dedent-tabs": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/dedent-tabs/-/dedent-tabs-0.10.3.tgz", - "integrity": "sha512-RYq1ewj+FDOEKxjhU9a2xwSJX+ODruTeIcMwt3KVAuUpOGFLDzmQWU3ByXRLVFHYAg584gcYSv1k+KheoLExsw==", - "deprecated": "The dedent package is maintained again, so this one isn't necessary anymore. Please use dedent again. All features from this package should now be included." + "integrity": "sha512-RYq1ewj+FDOEKxjhU9a2xwSJX+ODruTeIcMwt3KVAuUpOGFLDzmQWU3ByXRLVFHYAg584gcYSv1k+KheoLExsw==" }, "node_modules/deep-is": { "version": "0.1.4", @@ -5073,6 +5263,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -5134,6 +5325,33 @@ "deps-sort": "bin/cmd.js" } }, + "node_modules/deps-sort/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/deps-sort/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/deps-sort/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/deps-sort/node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -5144,9 +5362,9 @@ } }, "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -5265,6 +5483,33 @@ "readable-stream": "^2.0.2" } }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -5279,14 +5524,14 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.775", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.775.tgz", - "integrity": "sha512-JpOfl1aNAiZ88wFzjPczTLwYIoPIsij8S9/XQH9lqMpiJOf23kxea68B8wje4f68t4rOIq4Bh+vP4I65njiJBw==" + "version": "1.4.711", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.711.tgz", + "integrity": "sha512-hRg81qzvUEibX2lDxnFlVCHACa+LtrCPIsWAxo161LDYIB3jauf57RGsMZV9mvGwE98yGH06icj3zBEoOkxd/w==" }, "node_modules/elliptic": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.5.tgz", - "integrity": "sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -5505,9 +5750,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "engines": { "node": ">=6" } @@ -5756,9 +6001,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -6102,16 +6347,47 @@ "node": ">=0.10.0" } }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^6.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/fast-deep-equal": { @@ -6121,9 +6397,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -6175,9 +6451,9 @@ } }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -6268,9 +6544,9 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", "dev": true, "dependencies": { "flatted": "^3.2.9", @@ -6278,13 +6554,13 @@ "rimraf": "^3.0.2" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=12.0.0" } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "node_modules/for-each": { @@ -6376,9 +6652,9 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "hasInstallScript": true, "optional": true, "os": [ @@ -6424,24 +6700,23 @@ } }, "node_modules/gaxios": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.6.0.tgz", - "integrity": "sha512-bpOZVQV5gthH/jVCSuYuokRo2bTKOcuBiVWpjmTn6C5Agl5zclGfTljuGsQZxwwDBkli+YhZhP4TdlqTnhOezQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.1.1.tgz", + "integrity": "sha512-bw8smrX+XlAoo9o1JAksBwX+hi/RG15J+NTSxmNPIclKC3ZVK6C2afwY8OSdRvOK0+ZLecUJYtj2MmjOt3Dm0w==", "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", - "node-fetch": "^2.6.9", - "uuid": "^9.0.1" + "node-fetch": "^2.6.9" }, "engines": { "node": ">=14" } }, "node_modules/gcp-metadata": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", - "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.0.0.tgz", + "integrity": "sha512-Ozxyi23/1Ar51wjUT2RDklK+3HxqDr8TLBNK8rBBFQ7T85iIGnXnVusauj06QyqCXRFZig8LZC+TUddWbndlpQ==", "dependencies": { "gaxios": "^6.0.0", "json-bigint": "^1.0.0" @@ -6603,6 +6878,15 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, + "node_modules/global-prefix/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/global-prefix/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -6624,13 +6908,12 @@ } }, "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "dev": true, "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" + "define-properties": "^1.1.3" }, "engines": { "node": ">= 0.4" @@ -6666,29 +6949,46 @@ "dev": true }, "node_modules/google-auth-library": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.10.0.tgz", - "integrity": "sha512-ol+oSa5NbcGdDqA+gZ3G3mev59OHBZksBTxY/tYwjtcp1H/scAFwJfSQU9/1RALoyZ7FslNbke8j4i3ipwlyuQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.0.0.tgz", + "integrity": "sha512-IQGjgQoVUAfOk6khqTVMLvWx26R+yPw9uLyb1MNyMQpdKiKt0Fd9sp4NWoINjyGHR8S3iw12hMTYK7O8J07c6Q==", "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^6.1.1", - "gcp-metadata": "^6.1.0", + "gaxios": "^6.0.0", + "gcp-metadata": "^6.0.0", "gtoken": "^7.0.0", - "jws": "^4.0.0" + "jws": "^4.0.0", + "lru-cache": "^6.0.0" }, "engines": { "node": ">=14" } }, + "node_modules/google-auth-library/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-auth-library/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/googleapis-common": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.2.0.tgz", - "integrity": "sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.0.0.tgz", + "integrity": "sha512-58iSybJPQZ8XZNMpjrklICefuOuyJ0lMxfKmBqmaC0/xGT4SiOs4BE60LAOOGtBURy1n8fHa2X2YUNFEWWbXyQ==", "dependencies": { "extend": "^3.0.2", "gaxios": "^6.0.3", - "google-auth-library": "^9.7.0", + "google-auth-library": "^9.0.0", "qs": "^6.7.0", "url-template": "^2.0.8", "uuid": "^9.0.0" @@ -6720,9 +7020,9 @@ "dev": true }, "node_modules/gtoken": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", - "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.0.1.tgz", + "integrity": "sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==", "dependencies": { "gaxios": "^6.0.0", "jws": "^4.0.0" @@ -6741,9 +7041,12 @@ } }, "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, "engines": { "node": ">= 0.4.0" } @@ -6860,24 +7163,14 @@ "node": ">=0.10.0" } }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" }, "engines": { "node": ">=4" @@ -6998,9 +7291,9 @@ "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" }, "node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -7049,9 +7342,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -7162,9 +7455,9 @@ } }, "node_modules/inline-source-map": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.3.tgz", - "integrity": "sha512-1aVsPEsJWMJq/pdMU61CDlm1URcW702MTB4w9/zUjMus6H/Py8o7g68Pr9D4I6QluWGt/KdmswuRhaA05xVR1w==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha512-0mVWSSbNDvedDWIN4wxLsdPM4a7cIPcpyMxj3QZ406QRwQ6ePGB1YIHxVPjqpcUGbWQ5C+nHTwGNWAGvt7ggVA==", "dependencies": { "source-map": "~0.5.3" } @@ -7197,6 +7490,33 @@ "insert-module-globals": "bin/cmd.js" } }, + "node_modules/insert-module-globals/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/insert-module-globals/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/insert-module-globals/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/insert-module-globals/node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -7229,14 +7549,25 @@ } }, "node_modules/is-accessor-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", - "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "dependencies": { - "hasown": "^2.0.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">= 0.10" + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/is-array-buffer": { @@ -7344,14 +7675,25 @@ } }, "node_modules/is-data-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", - "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "dependencies": { - "hasown": "^2.0.0" + "kind-of": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/is-data-view": { @@ -7385,15 +7727,24 @@ } }, "node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/is-extendable": { @@ -7533,10 +7884,12 @@ } }, "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, "engines": { "node": ">=0.10.0" } @@ -7694,10 +8047,9 @@ } }, "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, "node_modules/isexe": { "version": "2.0.0", @@ -7714,23 +8066,23 @@ } }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", - "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", + "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", "dev": true, "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" }, @@ -7738,11 +8090,26 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "node_modules/istanbul-lib-instrument/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" }, @@ -7750,6 +8117,12 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-instrument/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", @@ -7800,9 +8173,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -9049,11 +9422,26 @@ "node": ">=8" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" }, @@ -9073,6 +9461,12 @@ "node": ">=8" } }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", @@ -9508,15 +9902,13 @@ } }, "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" }, "engines": { "node": ">=4.0" @@ -9567,9 +9959,12 @@ } }, "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dependencies": { + "is-buffer": "^1.1.5" + }, "engines": { "node": ">=0.10.0" } @@ -9770,11 +10165,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "node_modules/make-dir/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" }, @@ -9782,6 +10192,12 @@ "node": ">=10" } }, + "node_modules/make-dir/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -9957,6 +10373,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/meow/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -10106,6 +10531,24 @@ "node": ">= 6" } }, + "node_modules/minimist-options/node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimist-options/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -10129,17 +10572,6 @@ "node": ">=0.10.0" } }, - "node_modules/mixin-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -10173,6 +10605,33 @@ "node": ">= 0.8.0" } }, + "node_modules/module-deps/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/module-deps/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/module-deps/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/module-deps/node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -10199,37 +10658,6 @@ "whatwg-url": "^13.0.0" } }, - "node_modules/mongodb-connection-string-url/node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "engines": { - "node": ">=12" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", - "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/mongoose": { "version": "8.4.5", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.4.5.tgz", @@ -10383,9 +10811,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nan": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", - "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "optional": true }, "node_modules/nanoid": { @@ -10444,16 +10872,39 @@ "node": ">=0.10.0" } }, - "node_modules/nanomatch/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/nanomatch/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^6.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/nanomatch/node_modules/is-extendable": { @@ -10467,13 +10918,10 @@ "node": ">=0.10.0" } }, - "node_modules/nanomatch/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, + "node_modules/nanomatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "engines": { "node": ">=0.10.0" } @@ -10531,6 +10979,14 @@ "node": ">=10" } }, + "node_modules/nconf/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -10558,6 +11014,25 @@ } } }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -10570,9 +11045,9 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/nodemon": { - "version": "2.0.22", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", - "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.21.tgz", + "integrity": "sha512-djN/n2549DUtY33S7o1djRCd7dEm0kBnj9c7S9XVXqRUbuggN1MZH/Nqa+5RFQr63Fbefq37nFXAE9VU86yL1A==", "dependencies": { "chokidar": "^3.5.2", "debug": "^3.2.7", @@ -10612,6 +11087,20 @@ "semver": "bin/semver" } }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", @@ -10627,11 +11116,26 @@ "node": ">=10" } }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" }, @@ -10639,6 +11143,12 @@ "node": ">=10" } }, + "node_modules/normalize-package-data/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -10703,6 +11213,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "engines": { "node": ">= 0.4" } @@ -10722,6 +11233,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, "dependencies": { "call-bind": "^1.0.5", "define-properties": "^1.2.1", @@ -10847,17 +11359,17 @@ } }, "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -10946,19 +11458,15 @@ } }, "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" } }, "node_modules/parse-json": { @@ -11074,9 +11582,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -11189,9 +11697,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { @@ -11208,9 +11716,9 @@ } ], "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -11257,9 +11765,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -11285,9 +11793,9 @@ "dev": true }, "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true, "funding": [ { @@ -11420,17 +11928,17 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "engines": { "node": ">=6" } }, "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.3.tgz", + "integrity": "sha512-KddyFewCsO0j3+np81IQ+SweXLDnDQTs5s67BOnrYmYe/yNmUhttQyGsYzy8yUnoljGAQ9sl38YB4vH8ur7Y+w==", "dev": true, "funding": [ { @@ -11457,6 +11965,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", @@ -11570,9 +12087,9 @@ } }, "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "node_modules/react-router": { @@ -11613,6 +12130,33 @@ "readable-stream": "^2.0.2" } }, + "node_modules/read-only-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/read-only-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/read-only-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/read-pkg": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", @@ -11673,35 +12217,16 @@ } }, "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/readdirp": { @@ -11758,9 +12283,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "dependencies": { "regenerate": "^1.4.2" }, @@ -11816,17 +12341,6 @@ "node": ">=0.10.0" } }, - "node_modules/regex-not/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -11919,11 +12433,11 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -12062,6 +12576,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -12196,16 +12716,16 @@ } }, "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", "dependencies": { - "define-data-property": "^1.1.4", + "define-data-property": "^1.1.2", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", + "get-intrinsic": "^1.2.3", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" + "has-property-descriptors": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -12240,17 +12760,6 @@ "node": ">=0.10.0" } }, - "node_modules/set-value/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -12307,9 +12816,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", + "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12487,16 +12996,47 @@ "node": ">=0.10.0" } }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^6.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/snapdragon-util": { @@ -12551,9 +13091,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12607,9 +13147,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -12623,9 +13163,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", - "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", "dev": true }, "node_modules/split-string": { @@ -12662,17 +13202,6 @@ "node": ">=0.10.0" } }, - "node_modules/split-string/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -12729,6 +13258,33 @@ "readable-stream": "^2.0.2" } }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stream-browserify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/stream-browserify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/stream-combiner2": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", @@ -12738,6 +13294,33 @@ "readable-stream": "^2.0.2" } }, + "node_modules/stream-combiner2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stream-combiner2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/stream-combiner2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/stream-http": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", @@ -12749,19 +13332,6 @@ "xtend": "^4.0.2" } }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/stream-splicer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", @@ -12771,6 +13341,33 @@ "readable-stream": "^2.0.2" } }, + "node_modules/stream-splicer/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stream-splicer/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/stream-splicer/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -13025,23 +13622,22 @@ } }, "node_modules/stylelint-order": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-6.0.4.tgz", - "integrity": "sha512-0UuKo4+s1hgQ/uAxlYU4h0o0HS4NiQDud0NAUNI0aa8FJdmYHA5ZZTFHiV5FpmE3071e9pZx5j0QpVJW5zOCUA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-6.0.3.tgz", + "integrity": "sha512-1j1lOb4EU/6w49qZeT2SQVJXm0Ht+Qnq9GMfUa3pMwoyojIWfuA+JUDmoR97Bht1RLn4ei0xtLGy87M7d29B1w==", "dev": true, "dependencies": { - "postcss": "^8.4.32", + "postcss": "^8.4.21", "postcss-sorting": "^8.0.2" }, "peerDependencies": { - "stylelint": "^14.0.0 || ^15.0.0 || ^16.0.1" + "stylelint": "^14.0.0 || ^15.0.0" } }, "node_modules/stylelint-stylistic": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/stylelint-stylistic/-/stylelint-stylistic-0.4.5.tgz", - "integrity": "sha512-E3Mz68yqmZe5Zk5UraR5MA2DjxgfE2TCZerDPk+fcd9dwLjwRupAt0j+Q1fBJRE3vhh3PvToKDhvhfMHf1tfNg==", - "deprecated": "This package has been deprecated in favor of @stylistic/stylelint-plugin", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/stylelint-stylistic/-/stylelint-stylistic-0.4.3.tgz", + "integrity": "sha512-WphmneK3MRrm5ixvRPWy7+c9+EQUh0FPvNMXW/N9VD85vyqtpxUejpD+mxubVVht0fRgidcqBxtW3s3tU2Ujhw==", "dev": true, "dependencies": { "is-plain-object": "^5.0.0", @@ -13054,6 +13650,15 @@ "stylelint": "^15.0.0" } }, + "node_modules/stylelint-stylistic/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", @@ -13061,17 +13666,26 @@ "dev": true }, "node_modules/stylelint/node_modules/file-entry-cache": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-7.0.2.tgz", - "integrity": "sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-7.0.1.tgz", + "integrity": "sha512-uLfFktPmRetVCbHe5UPuekWrQ6hENufnA46qEGbfACkK5drjTTdQYUragRgMjHldcbYG+nslUerqMPjbBSHXjQ==", "dev": true, "dependencies": { - "flat-cache": "^3.2.0" + "flat-cache": "^3.1.1" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/stylelint/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/stylelint/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -13082,9 +13696,9 @@ } }, "node_modules/stylelint/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", + "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", "dev": true, "engines": { "node": ">=14" @@ -13228,9 +13842,9 @@ } }, "node_modules/table": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", - "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "dependencies": { "ajv": "^8.0.1", @@ -13244,15 +13858,15 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", - "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.3", + "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "uri-js": "^4.2.2" }, "funding": { "type": "github", @@ -13395,16 +14009,39 @@ "node": ">=0.10.0" } }, - "node_modules/to-regex/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/to-regex/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^6.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/to-regex/node_modules/is-extendable": { @@ -13418,13 +14055,10 @@ "node": ">=0.10.0" } }, - "node_modules/to-regex/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, + "node_modules/to-regex/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "engines": { "node": ">=0.10.0" } @@ -13438,17 +14072,26 @@ } }, "node_modules/touch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", - "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dependencies": { + "nopt": "~1.0.10" + }, "bin": { "nodetouch": "bin/nodetouch.js" } }, "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } }, "node_modules/trim-newlines": { "version": "4.1.1", @@ -13616,9 +14259,9 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", + "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", "dev": true, "peer": true, "bin": { @@ -13672,12 +14315,6 @@ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -13729,9 +14366,9 @@ } }, "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "engines": { "node": ">= 10.0.0" } @@ -13788,11 +14425,6 @@ "node": ">=0.10.0" } }, - "node_modules/unset-value/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -13803,9 +14435,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -13821,8 +14453,8 @@ } ], "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.1.1", + "picocolors": "^1.0.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -13847,12 +14479,12 @@ "deprecated": "Please see https://github.com/lydell/urix#deprecated" }, "node_modules/url": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", - "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.11.2" + "punycode": "1.3.2", + "querystring": "0.2.0" } }, "node_modules/url-template": { @@ -13861,23 +14493,9 @@ "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" }, "node_modules/url/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" - }, - "node_modules/url/node_modules/qs": { - "version": "6.12.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz", - "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" }, "node_modules/use": { "version": "3.1.1", @@ -13888,9 +14506,9 @@ } }, "node_modules/utf8-byte-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", - "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==" }, "node_modules/util": { "version": "0.10.4", @@ -13931,14 +14549,14 @@ } }, "node_modules/v8-to-istanbul": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", - "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" + "convert-source-map": "^1.6.0" }, "engines": { "node": ">=10.12.0" @@ -13965,6 +14583,7 @@ "node_modules/vitreum": { "version": "6.0.4", "resolved": "git+https://git@github.com/calculuschild/vitreum.git#9d55fd6fb7e85e7070de798c4f9d5b983c1b7dba", + "integrity": "sha512-6b5A4XEXnpyl6JDRWWOhe5lHxtzMVqNA+0Xrl7mPXqh7cYwTUm0yhkYEUkV+mz7rrHTpH7bYEWYsWEE/qTZMpg==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -14138,7 +14757,7 @@ "version": "1.2.13", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", "hasInstallScript": true, "optional": true, "os": [ @@ -14172,6 +14791,25 @@ "node": ">=0.10.0" } }, + "node_modules/watchify/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchify/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/watchify/node_modules/is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", @@ -14183,16 +14821,44 @@ "node": ">=0.10.0" } }, - "node_modules/watchify/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/watchify/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "kind-of": "^6.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" + } + }, + "node_modules/watchify/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchify/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchify/node_modules/is-descriptor/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/watchify/node_modules/is-extendable": { @@ -14217,7 +14883,7 @@ "node": ">=0.10.0" } }, - "node_modules/watchify/node_modules/is-number/node_modules/kind-of": { + "node_modules/watchify/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", @@ -14228,17 +14894,6 @@ "node": ">=0.10.0" } }, - "node_modules/watchify/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/watchify/node_modules/micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -14274,6 +14929,28 @@ "node": ">=0.10.0" } }, + "node_modules/watchify/node_modules/micromatch/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/watchify/node_modules/readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", @@ -14287,6 +14964,19 @@ "node": ">=0.10" } }, + "node_modules/watchify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/watchify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/watchify/node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -14309,17 +14999,23 @@ } }, "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } }, "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" } }, "node_modules/which": { @@ -14379,6 +15075,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", @@ -14416,15 +15118,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -14490,9 +15183,9 @@ } }, "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "engines": { "node": ">=8.3.0" }, @@ -14549,14 +15242,6 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", From 8e7baca47d256ae301cf37f3598d840cd6397243 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Tue, 23 Jul 2024 17:40:32 -0400 Subject: [PATCH 108/121] Fix tests --- server/homebrew.api.js | 4 ---- server/homebrew.api.spec.js | 19 ++++++++----------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 0b6218597..8faebd51b 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -309,8 +309,6 @@ const api = { if(isStaticTheme(req.brew.renderer, req.brew.theme)) //Check if parent is staticBrew rendererPath = `${_.upperFirst(req.brew.renderer)}/`; - console.log(`getBrewThemeCSS for ${brew.shareId}`); - console.log(`and parentThemeImport for ${brew.theme}`); const parentThemeImport = `@import url(\"/css/${rendererPath}${req.brew.theme}\");\n\n`; const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; return res.status(200).send(`${parentThemeImport}${themeLocationComment}${req.brew.style}`); @@ -323,8 +321,6 @@ const api = { res.setHeader('Content-Type', 'text/css'); res.setHeader('Cache-Control', 'public, max-age: 43200, must-revalidate'); const themeParent = Themes[req.params.renderer][req.params.id].baseTheme; - console.log(`getStaticThemeCSS for ${req.params.id}`); - console.log(`and parentThemeImport for ${themeParent}`); const parentThemeImport = themeParent ? `@import url(\"/css/${req.params.renderer}/${themeParent}\");\n/* Static Theme ${Themes[req.params.renderer][themeParent].name} */\n` : ''; return res.status(200).send(`${parentThemeImport}@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.renderer][req.params.id].name} */\n`); } diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 67f4abe5f..847c71946 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -287,15 +287,12 @@ describe('Tests for api', ()=>{ thumbnail : '', textBin : undefined, version : undefined, - userThemes : { - Brew : {} - }, - createdAt : undefined, - gDrive : false, - style : undefined, - trashed : false, - updatedAt : undefined, - views : 0 + createdAt : undefined, + gDrive : false, + style : undefined, + trashed : false, + updatedAt : undefined, + views : 0 }); expect(next).toHaveBeenCalled(); expect(api.getId).toHaveBeenCalledWith(req); @@ -600,7 +597,7 @@ brew`); expect(res.status).toHaveBeenCalledWith(200); }); }); - +////////////////////////////// describe('getBrewThemeWithUserParent', ()=>{ it('should collect parent theme and brew style - returning as css with user-theme parent imported.', async ()=>{ const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); @@ -643,7 +640,7 @@ brew`); expect(res.status).toHaveBeenCalledWith(404); }); }); - +//////////////////////////////// describe('deleteBrew', ()=>{ it('should handle case where fetching the brew returns an error', async ()=>{ From d2afa7adeae5327eba70535c396cd83066e521d5 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 23 Jul 2024 22:17:52 -0500 Subject: [PATCH 109/121] Move fetchThemeBundle into /shared/helpers This might not be the best rework - I was unsure if the *this* that would be available when called would see the appropriate object so I assumed not and pass it as a parameter. Works, but may be bad form. --- client/homebrew/pages/editPage/editPage.jsx | 17 +++-------------- client/homebrew/pages/homePage/homePage.jsx | 14 ++------------ client/homebrew/pages/newPage/newPage.jsx | 17 +++-------------- client/homebrew/pages/sharePage/sharePage.jsx | 15 ++------------- shared/helpers.js | 13 ++++++++++++- 5 files changed, 22 insertions(+), 54 deletions(-) diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 05bd79d4d..39a6d1931 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -25,7 +25,7 @@ const LockNotification = require('./lockNotification/lockNotification.jsx'); const Markdown = require('naturalcrit/markdown.js'); const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js'); -const { printCurrentBrew } = require('../../../../shared/helpers.js'); +const { printCurrentBrew, fetchThemeBundle } = require('../../../../shared/helpers.js'); const googleDriveIcon = require('../../googleDrive.svg'); @@ -88,7 +88,7 @@ const EditPage = createClass({ htmlErrors : Markdown.validate(prevState.brew.text) })); - this.fetchThemeBundle(this.props.brew.renderer, this.props.brew.theme); + fetchThemeBundle(this, this.props.brew.renderer, this.props.brew.theme); document.addEventListener('keydown', this.handleControlKeys); }, @@ -135,7 +135,7 @@ const EditPage = createClass({ handleMetaChange : function(metadata, field=undefined){ if(field == 'theme' || field == 'renderer') // Fetch theme bundle only if theme or renderer was changed - this.fetchThemeBundle(metadata.renderer, metadata.theme); + fetchThemeBundle(this, metadata.renderer, metadata.theme); this.setState((prevState)=>({ brew : { @@ -150,17 +150,6 @@ const EditPage = createClass({ return !_.isEqual(this.state.brew, this.savedBrew); }, - // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected - fetchThemeBundle : function(renderer, theme) { - fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ - themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); - this.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT - ...prevState, - themeBundle : themeBundle - })); - }); - }, - trySave : function(immediate=false){ if(!this.debounceSave) this.debounceSave = _.debounce(this.save, SAVE_TIMEOUT); if(this.hasChanges()){ diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index 0609d5b8b..bcfd237b4 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -13,6 +13,7 @@ const HelpNavItem = require('../../navbar/help.navitem.jsx'); const RecentNavItem = require('../../navbar/recent.navitem.jsx').both; const AccountNavItem = require('../../navbar/account.navitem.jsx'); const ErrorNavItem = require('../../navbar/error-navitem.jsx'); +const { fetchThemeBundle } = require('../../../../shared/helpers.js'); const SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); @@ -42,18 +43,7 @@ const HomePage = createClass({ editor : React.createRef(null), componentDidMount : function() { - this.fetchThemeBundle(this.props.brew.renderer, this.props.brew.theme); - }, - - // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected - fetchThemeBundle : function(renderer, theme) { - fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ - themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); - this.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT - ...prevState, - themeBundle : themeBundle - })); - }); + fetchThemeBundle(this, this.props.brew.renderer, this.props.brew.theme); }, handleSave : function(){ diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index e8c2636b0..c9160062f 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -19,7 +19,7 @@ const Editor = require('../../editor/editor.jsx'); const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); const { DEFAULT_BREW } = require('../../../../server/brewDefaults.js'); -const { printCurrentBrew } = require('../../../../shared/helpers.js'); +const { printCurrentBrew, fetchThemeBundle } = require('../../../../shared/helpers.js'); const BREWKEY = 'homebrewery-new'; const STYLEKEY = 'homebrewery-new-style'; @@ -78,7 +78,7 @@ const NewPage = createClass({ saveGoogle : (saveStorage == 'GOOGLE-DRIVE' && this.state.saveGoogle) }); - this.fetchThemeBundle(this.props.brew.renderer, this.props.brew.theme); + fetchThemeBundle(this, this.props.brew.renderer, this.props.brew.theme); localStorage.setItem(BREWKEY, brew.text); if(brew.style) @@ -89,17 +89,6 @@ const NewPage = createClass({ document.removeEventListener('keydown', this.handleControlKeys); }, - // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected - fetchThemeBundle : function(renderer, theme) { - fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ - themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); - this.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT - ...prevState, - themeBundle : themeBundle - })); - }); - }, - handleControlKeys : function(e){ if(!(e.ctrlKey || e.metaKey)) return; const S_KEY = 83; @@ -138,7 +127,7 @@ const NewPage = createClass({ handleMetaChange : function(metadata, field=undefined){ if(field == 'theme' || field == 'renderer') // Fetch theme bundle only if theme or renderer was changed - this.fetchThemeBundle(metadata.renderer, metadata.theme); + fetchThemeBundle(this, metadata.renderer, metadata.theme); this.setState((prevState)=>({ brew : { ...prevState.brew, ...metadata }, diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index c1f044d2d..390e577d0 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -12,7 +12,7 @@ const Account = require('../../navbar/account.navitem.jsx'); const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); const { DEFAULT_BREW_LOAD } = require('../../../../server/brewDefaults.js'); -const { printCurrentBrew } = require('../../../../shared/helpers.js'); +const { printCurrentBrew, fetchThemeBundle } = require('../../../../shared/helpers.js'); const SharePage = createClass({ displayName : 'SharePage', @@ -31,24 +31,13 @@ const SharePage = createClass({ componentDidMount : function() { document.addEventListener('keydown', this.handleControlKeys); - this.fetchThemeBundle(this.props.brew.renderer, this.props.brew.theme); + fetchThemeBundle(this, this.props.brew.renderer, this.props.brew.theme); }, componentWillUnmount : function() { document.removeEventListener('keydown', this.handleControlKeys); }, - // Loads the theme bundle and parses it out. Called when the iFrame is first mounted, and when a new theme is selected - fetchThemeBundle : function(renderer, theme) { - fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ - themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); - this.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT - ...prevState, - themeBundle : themeBundle - })); - }); - }, - handleControlKeys : function(e){ if(!(e.ctrlKey || e.metaKey)) return; const P_KEY = 80; diff --git a/shared/helpers.js b/shared/helpers.js index 321791f84..8f9e23928 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -33,7 +33,18 @@ const printCurrentBrew = ()=>{ } }; +const fetchThemeBundle = (obj, renderer, theme)=>{ + fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ + themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); + obj.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT + ...prevState, + themeBundle : themeBundle + })); + }); +}; + module.exports = { splitTextStyleAndMetadata, - printCurrentBrew + printCurrentBrew, + fetchThemeBundle, }; From 113f9b3fe391e179ebe264f6b8257527dc62d6da Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 27 Jul 2024 02:00:38 -0400 Subject: [PATCH 110/121] No need to stringify Theme Bundle object --- server/homebrew.api.js | 4 ++-- shared/helpers.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 8faebd51b..a766aaa6a 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -297,8 +297,8 @@ const api = { snippets : completeSnippets.reverse() }; - res.setHeader('Content-Type', 'text/json'); - return res.status(200).send(JSON.stringify(returnObj)); + res.setHeader('Content-Type', 'application/json'); + return res.status(200).send(returnObj); }, //Return CSS for a brew theme, with @include endpoint for its parent theme if any getBrewThemeCSS : async (req, res)=>{ diff --git a/shared/helpers.js b/shared/helpers.js index 8f9e23928..65dfc2752 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -36,7 +36,7 @@ const printCurrentBrew = ()=>{ const fetchThemeBundle = (obj, renderer, theme)=>{ fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); - obj.setState((prevState)=>({ // MOVE TO MOUNT STEP OF SHARE / NEW / EDIT + obj.setState((prevState)=>({ ...prevState, themeBundle : themeBundle })); From b64a0c520006f1d96c680c831769afea8f87e8ea Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 27 Jul 2024 03:30:51 -0400 Subject: [PATCH 111/121] Start adding tests for /theme/ endpoint --- package.json | 2 +- server/homebrew.api.spec.js | 47 ++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 321f9afbe..0f5d8548f 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "circleci": "npm test && eslint **/*.{js,jsx} --max-warnings=0", "verify": "npm run lint && npm test", "test": "jest --runInBand", - "test:api-unit": "jest server/*.spec.js --verbose", + "test:api-unit": "jest \"server/.*.spec.js\" -t --verbose", "test:coverage": "jest --coverage --silent --runInBand", "test:dev": "jest --verbose --watch", "test:basic": "jest tests/markdown/basic.test.js --verbose", diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 847c71946..4aa9e5663 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -582,6 +582,51 @@ brew`); }); }); + describe('theme bundle', () => { + it('should return Theme Bundle for a User Theme', async () => { + const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); + model.get = jest.fn(() => toBrewPromise({ title: 'User Theme A', renderer: 'V3', theme: null, shareId: 'userThemeAID', style: 'User Theme A Style' })); + const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; + + await api.getThemeBundle(req, res); + + expect(res.status).toHaveBeenCalledWith(200); + expect(res.send).toHaveBeenCalledWith({ + styles: ["/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style"], + snippets: [] + }); + }); + + it('should return Theme Bundle for nested User Themes', async () => { + console.log(api.getId) + const brews = { + userThemeAID: { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style' }, + userThemeBID: { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style' }, + userThemeCID: { title: 'User Theme C', renderer: 'V3', theme: null, shareId: 'userThemeCID', style: 'User Theme C Style' } + }; + + const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); + model.get = jest.fn((shareId) => { + toBrewPromise(brews[shareId]); + }); + const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; + + await api.getThemeBundle(req, res); + + expect(res.send).toHaveBeenCalledWith({ + styles: [ + "/* From Brew: https://localhost/share/userThemeCID */\n\nUser Theme C Style", + "/* From Brew: https://localhost/share/userThemeBID */\n\nUser Theme B Style", + "/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style" + ], + snippets: [] + }); + expect(res.status).toHaveBeenCalledWith(200); + }); + + }); + +////////////////////////////// describe('getBrewThemeWithStaticParent', ()=>{ it('should collect parent theme and brew style - returning as css with static parent imported.', async ()=>{ const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); @@ -597,7 +642,7 @@ brew`); expect(res.status).toHaveBeenCalledWith(200); }); }); -////////////////////////////// + describe('getBrewThemeWithUserParent', ()=>{ it('should collect parent theme and brew style - returning as css with user-theme parent imported.', async ()=>{ const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); From f2d933410e7d182a09d76ddd1bcd85234f0779eb Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 27 Jul 2024 19:17:05 -0400 Subject: [PATCH 112/121] Add error handling for missing themes --- server/homebrew.api.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index a766aaa6a..3a5a444fb 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -269,7 +269,18 @@ const api = { while (req.params.id) { //=== User Themes ===// if(!isStaticTheme(req.params.renderer, req.params.id)) { - await api.getBrew('share')(req, res, ()=>{}); + await api.getBrew('share')(req, res, ()=>{}) + .catch((err)=>{ + console.error(err); + if(err.HBErrorCode == '05') + res.status(err.status).send(`Theme Not Found - Renderer: ${req.params.renderer}, Name: ${req.params.id}`); + else + res.status(err.status || err.response.status).send(err.message || err); + req.brew = undefined; + }); + if (!req.brew) + return; + currentTheme = req.brew; splitTextStyleAndMetadata(currentTheme); From edec9369ec48d924f945f88e7137a5a74eedc212 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 27 Jul 2024 19:17:19 -0400 Subject: [PATCH 113/121] Finish adding test cases --- package.json | 3 +- server/homebrew.api.spec.js | 87 ++++++++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 0f5d8548f..11d31291f 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "circleci": "npm test && eslint **/*.{js,jsx} --max-warnings=0", "verify": "npm run lint && npm test", "test": "jest --runInBand", - "test:api-unit": "jest \"server/.*.spec.js\" -t --verbose", + "test:api-unit": "jest \"server/.*.spec.js\" --verbose", + "test:api-unit:themes": "jest \"server/.*.spec.js\" -t \"theme bundle\" --verbose", "test:coverage": "jest --coverage --silent --runInBand", "test:dev": "jest --verbose --watch", "test:basic": "jest tests/markdown/basic.test.js --verbose", diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 4aa9e5663..13975bcb1 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -14,6 +14,9 @@ describe('Tests for api', ()=>{ let saved; beforeEach(()=>{ + jest.resetModules(); + jest.restoreAllMocks(); + saved = undefined; saveFunc = jest.fn(async function() { saved = { ...this, _id: '1' }; @@ -82,10 +85,6 @@ describe('Tests for api', ()=>{ }; }); - afterEach(()=>{ - jest.restoreAllMocks(); - }); - describe('getId', ()=>{ it('should return only id if google id is not present', ()=>{ const { id, googleId } = api.getId({ @@ -582,10 +581,14 @@ brew`); }); }); - describe('theme bundle', () => { + describe('Theme bundle', () => { it('should return Theme Bundle for a User Theme', async () => { + const brews = { + userThemeAID: { title: 'User Theme A', renderer: 'V3', theme: null, shareId: 'userThemeAID', style: 'User Theme A Style' } + }; + const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); - model.get = jest.fn(() => toBrewPromise({ title: 'User Theme A', renderer: 'V3', theme: null, shareId: 'userThemeAID', style: 'User Theme A Style' })); + model.get = jest.fn((getParams) => toBrewPromise(brews[getParams.shareId])); const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; await api.getThemeBundle(req, res); @@ -598,7 +601,6 @@ brew`); }); it('should return Theme Bundle for nested User Themes', async () => { - console.log(api.getId) const brews = { userThemeAID: { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style' }, userThemeBID: { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style' }, @@ -606,13 +608,12 @@ brew`); }; const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); - model.get = jest.fn((shareId) => { - toBrewPromise(brews[shareId]); - }); + model.get = jest.fn((getParams) => toBrewPromise(brews[getParams.shareId])); const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; await api.getThemeBundle(req, res); + expect(res.status).toHaveBeenCalledWith(200); expect(res.send).toHaveBeenCalledWith({ styles: [ "/* From Brew: https://localhost/share/userThemeCID */\n\nUser Theme C Style", @@ -621,9 +622,71 @@ brew`); ], snippets: [] }); - expect(res.status).toHaveBeenCalledWith(200); }); - + + it('should return Theme Bundle for a Static Theme', async () => { + const req = { params: { renderer: "V3", id: "5ePHB" }, get: () => { return 'localhost'; }, protocol: 'https' }; + + await api.getThemeBundle(req, res); + + expect(res.status).toHaveBeenCalledWith(200); + expect(res.send).toHaveBeenCalledWith({ + styles: [ + `/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`, + `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");` + ], + snippets: [ + "V3_Blank", + "V3_5ePHB" + ] + }); + }); + + it('should return Theme Bundle for nested User and Static Themes together', async () => { + const brews = { + userThemeAID: { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style' }, + userThemeBID: { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style' }, + userThemeCID: { title: 'User Theme C', renderer: 'V3', theme: '5eDMG', shareId: 'userThemeCID', style: 'User Theme C Style' } + }; + + const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); + model.get = jest.fn((getParams) => toBrewPromise(brews[getParams.shareId])); + const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; + + await api.getThemeBundle(req, res); + + expect(res.status).toHaveBeenCalledWith(200); + expect(res.send).toHaveBeenCalledWith({ + styles: [ + `/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`, + `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");`, + `/* From Theme 5eDMG */\n\n@import url("/themes/V3/5eDMG/style.css");`, + "/* From Brew: https://localhost/share/userThemeCID */\n\nUser Theme C Style", + "/* From Brew: https://localhost/share/userThemeBID */\n\nUser Theme B Style", + "/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style" + ], + snippets: [ + "V3_Blank", + "V3_5ePHB", + "V3_5eDMG" + ] + }); + }); + + it('should fail for an invalid Theme in the chain', async()=>{ + const brews = { + userThemeAID: { title: 'User Theme A', renderer: 'V3', theme: 'missingTheme', shareId: 'userThemeAID', style: 'User Theme A Style' }, + }; + + const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); + model.get = jest.fn((getParams) => toBrewPromise(brews[getParams.shareId])); + const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; + + await api.getThemeBundle(req, res); + + expect(res.status).toHaveBeenCalledWith(404); + expect(res.send).toHaveBeenCalledWith('Theme Not Found - Renderer: V3, Name: missingTheme'); + }); }); ////////////////////////////// From 8aa88a2e4590ddccc0992470a8f32fe07568001b Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 28 Jul 2024 16:45:01 -0400 Subject: [PATCH 114/121] Add proper error popup when theme fails to load --- client/homebrew/navbar/error-navitem.jsx | 12 +++++++++++ client/homebrew/navbar/error-navitem.less | 3 +++ .../pages/errorPage/errors/errorIndex.js | 13 ++++++++++++ server/app.js | 5 +---- server/homebrew.api.js | 10 +++------ server/homebrew.api.spec.js | 15 ++++++++----- shared/helpers.js | 21 ++++++++++++------- 7 files changed, 56 insertions(+), 23 deletions(-) diff --git a/client/homebrew/navbar/error-navitem.jsx b/client/homebrew/navbar/error-navitem.jsx index 59e05a253..652959459 100644 --- a/client/homebrew/navbar/error-navitem.jsx +++ b/client/homebrew/navbar/error-navitem.jsx @@ -104,6 +104,18 @@ const ErrorNavItem = createClass({ ; } + if(HBErrorCode === '09') { + return + Oops! +
+ Looks like there was a problem retreiving + the theme, or a theme that it inherits, + for this brew. Verify that brew + {response.body.brewId} still exists! +
+
; + } + return Oops!
diff --git a/client/homebrew/navbar/error-navitem.less b/client/homebrew/navbar/error-navitem.less index 7e7dab772..be138dca4 100644 --- a/client/homebrew/navbar/error-navitem.less +++ b/client/homebrew/navbar/error-navitem.less @@ -21,6 +21,9 @@ font-size : 10px; font-weight : 800; text-transform : uppercase; + .lowercase { + text-transform : none; + } a{ color : @teal; } diff --git a/client/homebrew/pages/errorPage/errors/errorIndex.js b/client/homebrew/pages/errorPage/errors/errorIndex.js index 58725fe3f..7bf2caae1 100644 --- a/client/homebrew/pages/errorPage/errors/errorIndex.js +++ b/client/homebrew/pages/errorPage/errors/errorIndex.js @@ -136,6 +136,19 @@ const errorIndex = (props)=>{ **Brew ID:** ${props.brew.brewId}`, + // Theme load error + '09' : dedent` + ## No Homebrewery theme document could be found. + + The server could not locate the Homebrewery document. It was likely deleted by + its owner. + + : + + **Requested access:** ${props.brew.accessType} + + **Brew ID:** ${props.brew.brewId}`, + // Brew locked by Administrators error '100' : dedent` ## This brew has been locked. diff --git a/server/app.js b/server/app.js index 8ad35ca35..6863bc7cb 100644 --- a/server/app.js +++ b/server/app.js @@ -9,7 +9,7 @@ const yaml = require('js-yaml'); const app = express(); const config = require('./config.js'); -const { homebrewApi, getBrew, getThemeBundle, getUsersBrewThemes } = require('./homebrew.api.js'); +const { homebrewApi, getBrew, getUsersBrewThemes } = require('./homebrew.api.js'); const GoogleActions = require('./googleActions.js'); const serveCompressedStaticAssets = require('./static-assets.mv.js'); const sanitizeFilename = require('sanitize-filename'); @@ -77,9 +77,6 @@ app.get('/robots.txt', (req, res)=>{ return res.sendFile(`robots.txt`, { root: process.cwd() }); }); -// Theme -app.get('/theme/:renderer/:id', asyncHandler(getThemeBundle)); - //Home page app.get('/', (req, res, next)=>{ req.brew = { diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 3a5a444fb..f20e97d4c 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -271,15 +271,10 @@ const api = { if(!isStaticTheme(req.params.renderer, req.params.id)) { await api.getBrew('share')(req, res, ()=>{}) .catch((err)=>{ - console.error(err); if(err.HBErrorCode == '05') - res.status(err.status).send(`Theme Not Found - Renderer: ${req.params.renderer}, Name: ${req.params.id}`); - else - res.status(err.status || err.response.status).send(err.message || err); - req.brew = undefined; + err = {...err, name: 'ThemeLoad Error', message: 'Theme Not Found', HBErrorCode: '09'}; + throw err; }); - if (!req.brew) - return; currentTheme = req.brew; splitTextStyleAndMetadata(currentTheme); @@ -496,5 +491,6 @@ router.put('/api/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api router.put('/api/update/:id', asyncHandler(api.getBrew('edit', true)), asyncHandler(api.updateBrew)); router.delete('/api/:id', asyncHandler(api.deleteBrew)); router.get('/api/remove/:id', asyncHandler(api.deleteBrew)); +router.get('/api/theme/:renderer/:id', asyncHandler(api.getThemeBundle)); module.exports = api; diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 13975bcb1..90ee4dfa3 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -682,14 +682,20 @@ brew`); model.get = jest.fn((getParams) => toBrewPromise(brews[getParams.shareId])); const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; - await api.getThemeBundle(req, res); + let err + await api.getThemeBundle(req, res) + .catch(e => err = e); - expect(res.status).toHaveBeenCalledWith(404); - expect(res.send).toHaveBeenCalledWith('Theme Not Found - Renderer: V3, Name: missingTheme'); + expect(err).toEqual({ + HBErrorCode : "09", + accessType : "share", + brewId : "missingTheme", + message : "Theme Not Found", + name : "ThemeLoad Error", + status : 404}); }); }); -////////////////////////////// describe('getBrewThemeWithStaticParent', ()=>{ it('should collect parent theme and brew style - returning as css with static parent imported.', async ()=>{ const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); @@ -748,7 +754,6 @@ brew`); expect(res.status).toHaveBeenCalledWith(404); }); }); -//////////////////////////////// describe('deleteBrew', ()=>{ it('should handle case where fetching the brew returns an error', async ()=>{ diff --git a/shared/helpers.js b/shared/helpers.js index 65dfc2752..e711de41b 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -1,5 +1,6 @@ const _ = require('lodash'); const yaml = require('js-yaml'); +const request = require('../client/homebrew/utils/request-middleware.js'); const splitTextStyleAndMetadata = (brew)=>{ brew.text = brew.text.replaceAll('\r\n', '\n'); @@ -33,14 +34,20 @@ const printCurrentBrew = ()=>{ } }; -const fetchThemeBundle = (obj, renderer, theme)=>{ - fetch(`${window.location.protocol}//${window.location.host}/theme/${renderer}/${theme}`).then((response)=>response.json()).then((themeBundle)=>{ - themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); //DOMPurify.sanitize(joinedStyles, purifyConfig); - obj.setState((prevState)=>({ +const fetchThemeBundle = async (obj, renderer, theme) => { + const res = await request + .get(`${window.location.protocol}//${window.location.host}/api/theme/${renderer}/${theme}`) + .catch((err) => { + obj.setState({ error: err }); + }); + if (!res) return; + + const themeBundle = res.body; + themeBundle.joinedStyles = themeBundle.styles.map((style) => ``).join('\n\n'); + obj.setState((prevState) => ({ ...prevState, - themeBundle : themeBundle - })); - }); + themeBundle: themeBundle + })); }; module.exports = { From e0425ec6c0599eeb0a2fbd961956b269068aea46 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 28 Jul 2024 16:47:16 -0400 Subject: [PATCH 115/121] Simplify API call url --- shared/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/helpers.js b/shared/helpers.js index e711de41b..90d0004b4 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -36,7 +36,7 @@ const printCurrentBrew = ()=>{ const fetchThemeBundle = async (obj, renderer, theme) => { const res = await request - .get(`${window.location.protocol}//${window.location.host}/api/theme/${renderer}/${theme}`) + .get(`/api/theme/${renderer}/${theme}`) .catch((err) => { obj.setState({ error: err }); }); From 2870caaae6716b427e21d2c4d9915afe3b046e01 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 28 Jul 2024 17:18:30 -0400 Subject: [PATCH 116/121] Clean up metadataEditor theme dropdown --- .../editor/metadataEditor/metadataEditor.jsx | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 473b2ab69..944c4d88a 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -199,37 +199,34 @@ const MetadataEditor = createClass({ const preview = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownPreview.png`; const texture = theme.thumbnail || `/themes/${theme.renderer}/${theme.path}/dropdownTexture.png`; return
this.handleTheme(theme)} title={''}> -

{`${theme?.author ? theme.author : renderer} : ${theme.name}`}

+ {theme.author ?? renderer} : {theme.name}
- +
-
{`${theme.name}`} preview
- +
{theme.name} preview
+
; }); }; - const currentThemePath = this.props.metadata?.theme && Themes[_.upperFirst(this.props.metadata.renderer)]?.hasOwnProperty(this.props.metadata?.theme) ? this.props.metadata.renderer : 'Brew'; - const currentTheme = mergedThemes[`${_.upperFirst(currentThemePath)}`]?.hasOwnProperty(this.props.metadata.theme) ? mergedThemes[`${_.upperFirst(currentThemePath)}`][this.props.metadata.theme] : { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme.slice(1)}` }; + const currentRenderer = this.props.metadata.renderer; + const currentTheme = mergedThemes[`${_.upperFirst(this.props.metadata.renderer)}`][this.props.metadata.theme] + ?? { name: `!!! THEME MISSING !!! ID=${this.props.metadata.theme}` }; let dropdown; - if(this.props.metadata.renderer == 'legacy') { + if(currentRenderer == 'legacy') { dropdown = -
- {`Themes are not supported in the Legacy Renderer`} -
+
{`Themes are not supported in the Legacy Renderer`}
; } else { dropdown = -
- {`${currentTheme?.author ? currentTheme.author : _.upperFirst(currentThemePath)} : ${currentTheme.name}`} -
- {/*listThemes('Legacy')*/} - {listThemes('V3')} +
{currentTheme.author ?? _.upperFirst(currentRenderer)} : {currentTheme.name}
+ + {listThemes(currentRenderer)}
; } From ee9f2c8c83ba6283f2325ce23a7ff8878b3a9696 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 28 Jul 2024 17:53:25 -0400 Subject: [PATCH 117/121] Remove unused CSS endpoints in favor of #3075 Now that we have a dedicated /theme/ route for the recursive theming, the CSS endpoint can be simpler for only getting the `style` of a single brew. #3075 already has this simpler version, but no testing, so I have copied this into a comment there for implementation when it is ready. --- server/homebrew.api.js | 25 ---------------- server/homebrew.api.spec.js | 59 ------------------------------------- 2 files changed, 84 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index f20e97d4c..c8e4996cb 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -306,31 +306,6 @@ const api = { res.setHeader('Content-Type', 'application/json'); return res.status(200).send(returnObj); }, - //Return CSS for a brew theme, with @include endpoint for its parent theme if any - getBrewThemeCSS : async (req, res)=>{ - const brew = req.brew; - splitTextStyleAndMetadata(brew); - res.setHeader('Content-Type', 'text/css'); - let rendererPath = ''; - if(isStaticTheme(req.brew.renderer, req.brew.theme)) //Check if parent is staticBrew - rendererPath = `${_.upperFirst(req.brew.renderer)}/`; - - const parentThemeImport = `@import url(\"/css/${rendererPath}${req.brew.theme}\");\n\n`; - const themeLocationComment = `/* From Brew: ${req.protocol}://${req.get('host')}/share/${req.brew.shareId} */\n\n`; - return res.status(200).send(`${parentThemeImport}${themeLocationComment}${req.brew.style}`); - }, - //Return CSS for a static theme, with @include endpoint for its parent theme if any - getStaticThemeCSS : async(req, res)=>{ - if(!isStaticTheme(req.params.renderer, req.params.id)) - res.status(404).send(`Invalid Theme - Renderer: ${req.params.renderer}, Name: ${req.params.id}`); - else { - res.setHeader('Content-Type', 'text/css'); - res.setHeader('Cache-Control', 'public, max-age: 43200, must-revalidate'); - const themeParent = Themes[req.params.renderer][req.params.id].baseTheme; - const parentThemeImport = themeParent ? `@import url(\"/css/${req.params.renderer}/${themeParent}\");\n/* Static Theme ${Themes[req.params.renderer][themeParent].name} */\n` : ''; - return res.status(200).send(`${parentThemeImport}@import url(\"/themes/${req.params.renderer}/${req.params.id}/style.css\");\n/* Static Theme ${Themes[req.params.renderer][req.params.id].name} */\n`); - } - }, updateBrew : async (req, res)=>{ // Initialize brew from request and body, destructure query params, and set the initial value for the after-save method const brewFromClient = api.excludePropsFromUpdate(req.body); diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 90ee4dfa3..273900ee2 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -696,65 +696,6 @@ brew`); }); }); - describe('getBrewThemeWithStaticParent', ()=>{ - it('should collect parent theme and brew style - returning as css with static parent imported.', async ()=>{ - const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); - model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', theme: '5eDMG', shareId: 'iAmAUserTheme', style: 'I Have a style!' })); - const fn = api.getBrew('share', true); - const req = { brew: {}, get: ()=>{return 'localhost';}, protocol: 'https' }; - const next = jest.fn(); - await fn(req, null, next); - - api.getBrewThemeCSS(req, res); - const sent = res.send.mock.calls[0][0]; - expect(sent).toBe(`@import url("/css/V3/5eDMG");\n\n/* From Brew: https://localhost/share/iAmAUserTheme */\n\nI Have a style!`); - expect(res.status).toHaveBeenCalledWith(200); - }); - }); - - describe('getBrewThemeWithUserParent', ()=>{ - it('should collect parent theme and brew style - returning as css with user-theme parent imported.', async ()=>{ - const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); - model.get = jest.fn(()=>toBrewPromise({ title: 'test brew', renderer: 'V3', shareId: 'iAmAUserTheme', theme: 'IamATheme', style: 'I Have a style!' })); - const fn = api.getBrew('share', true); - const req = { brew: {}, get: ()=>{return 'localhost';}, protocol: 'https' }; - const next = jest.fn(); - await fn(req, null, next); - - api.getBrewThemeCSS(req, res); - const sent = res.send.mock.calls[0][0]; - expect(sent).toBe(`@import url("/css/IamATheme");\n\n/* From Brew: https://localhost/share/iAmAUserTheme */\n\nI Have a style!`); - expect(res.status).toHaveBeenCalledWith(200); - }); - }); - - describe('getStaticThemeCSS', ()=>{ - it('should return an import of the theme including a parent.', async ()=>{ - const req = { - params : { - renderer : 'V3', - id : '5eDMG' - } - }; - api.getStaticThemeCSS(req, res); - const sent = res.send.mock.calls[0][0]; - expect(sent).toBe('@import url("/css/V3/5ePHB");\n/* Static Theme 5e PHB */\n@import url("/themes/V3/5eDMG/style.css");\n/* Static Theme 5e DMG */\n'); - expect(res.status).toHaveBeenCalledWith(200); - }); - it('should fail for an invalid static theme.', async()=>{ - const req = { - params : { - renderer : 'V3', - id : '5eDMGGGG' - } - }; - api.getStaticThemeCSS(req, res); - const sent = res.send.mock.calls[0][0]; - expect(sent).toBe('Invalid Theme - Renderer: V3, Name: 5eDMGGGG'); - expect(res.status).toHaveBeenCalledWith(404); - }); - }); - describe('deleteBrew', ()=>{ it('should handle case where fetching the brew returns an error', async ()=>{ api.getBrew = jest.fn(()=>async ()=>{ throw { message: 'err', HBErrorCode: '02' }; }); From 88eaebfd4984469ca277ce83ba472a3121778ed9 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 28 Jul 2024 18:00:33 -0400 Subject: [PATCH 118/121] Raise test coverage threshold This PR adds tests which means we are now covering a larger % of the codebase. Raise the coverage thresholds to match. --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 11d31291f..c5563cca0 100644 --- a/package.json +++ b/package.json @@ -57,15 +57,15 @@ ], "coverageThreshold": { "global": { - "statements": 25, - "branches": 10, - "functions": 22, - "lines": 25 + "statements": 50, + "branches": 40, + "functions": 40, + "lines": 50 }, "server/homebrew.api.js": { - "statements": 65, + "statements": 70, "branches": 50, - "functions": 60, + "functions": 65, "lines": 70 } }, From 8221579b6a8a2c6567cc12748760f88ac3369d0e Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sun, 28 Jul 2024 18:03:25 -0400 Subject: [PATCH 119/121] Linting --- .../editor/metadataEditor/metadataEditor.jsx | 2 +- client/homebrew/navbar/error-navitem.jsx | 2 +- server/homebrew.api.js | 2 +- server/homebrew.api.spec.js | 126 +++++++++--------- shared/helpers.js | 16 +-- 5 files changed, 74 insertions(+), 74 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index 944c4d88a..4b48c2617 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -225,7 +225,7 @@ const MetadataEditor = createClass({ dropdown =
{currentTheme.author ?? _.upperFirst(currentRenderer)} : {currentTheme.name}
- + {listThemes(currentRenderer)}
; } diff --git a/client/homebrew/navbar/error-navitem.jsx b/client/homebrew/navbar/error-navitem.jsx index 652959459..5dd5c1eb9 100644 --- a/client/homebrew/navbar/error-navitem.jsx +++ b/client/homebrew/navbar/error-navitem.jsx @@ -111,7 +111,7 @@ const ErrorNavItem = createClass({ Looks like there was a problem retreiving the theme, or a theme that it inherits, for this brew. Verify that brew - {response.body.brewId} still exists! + {response.body.brewId} still exists!
; } diff --git a/server/homebrew.api.js b/server/homebrew.api.js index c8e4996cb..c7484da92 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -272,7 +272,7 @@ const api = { await api.getBrew('share')(req, res, ()=>{}) .catch((err)=>{ if(err.HBErrorCode == '05') - err = {...err, name: 'ThemeLoad Error', message: 'Theme Not Found', HBErrorCode: '09'}; + err = { ...err, name: 'ThemeLoad Error', message: 'Theme Not Found', HBErrorCode: '09' }; throw err; }); diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 273900ee2..679301294 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -581,118 +581,118 @@ brew`); }); }); - describe('Theme bundle', () => { - it('should return Theme Bundle for a User Theme', async () => { + describe('Theme bundle', ()=>{ + it('should return Theme Bundle for a User Theme', async ()=>{ const brews = { - userThemeAID: { title: 'User Theme A', renderer: 'V3', theme: null, shareId: 'userThemeAID', style: 'User Theme A Style' } + userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: null, shareId: 'userThemeAID', style: 'User Theme A Style' } }; - const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); - model.get = jest.fn((getParams) => toBrewPromise(brews[getParams.shareId])); - const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; + const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); + model.get = jest.fn((getParams)=>toBrewPromise(brews[getParams.shareId])); + const req = { params: { renderer: 'V3', id: 'userThemeAID' }, get: ()=>{ return 'localhost'; }, protocol: 'https' }; await api.getThemeBundle(req, res); expect(res.status).toHaveBeenCalledWith(200); expect(res.send).toHaveBeenCalledWith({ - styles: ["/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style"], - snippets: [] + styles : ['/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style'], + snippets : [] }); }); - it('should return Theme Bundle for nested User Themes', async () => { + it('should return Theme Bundle for nested User Themes', async ()=>{ const brews = { - userThemeAID: { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style' }, - userThemeBID: { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style' }, - userThemeCID: { title: 'User Theme C', renderer: 'V3', theme: null, shareId: 'userThemeCID', style: 'User Theme C Style' } + userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style' }, + userThemeBID : { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style' }, + userThemeCID : { title: 'User Theme C', renderer: 'V3', theme: null, shareId: 'userThemeCID', style: 'User Theme C Style' } }; - const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); - model.get = jest.fn((getParams) => toBrewPromise(brews[getParams.shareId])); - const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; + const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); + model.get = jest.fn((getParams)=>toBrewPromise(brews[getParams.shareId])); + const req = { params: { renderer: 'V3', id: 'userThemeAID' }, get: ()=>{ return 'localhost'; }, protocol: 'https' }; await api.getThemeBundle(req, res); expect(res.status).toHaveBeenCalledWith(200); expect(res.send).toHaveBeenCalledWith({ - styles: [ - "/* From Brew: https://localhost/share/userThemeCID */\n\nUser Theme C Style", - "/* From Brew: https://localhost/share/userThemeBID */\n\nUser Theme B Style", - "/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style" - ], - snippets: [] + styles : [ + '/* From Brew: https://localhost/share/userThemeCID */\n\nUser Theme C Style', + '/* From Brew: https://localhost/share/userThemeBID */\n\nUser Theme B Style', + '/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style' + ], + snippets : [] }); }); - it('should return Theme Bundle for a Static Theme', async () => { - const req = { params: { renderer: "V3", id: "5ePHB" }, get: () => { return 'localhost'; }, protocol: 'https' }; + it('should return Theme Bundle for a Static Theme', async ()=>{ + const req = { params: { renderer: 'V3', id: '5ePHB' }, get: ()=>{ return 'localhost'; }, protocol: 'https' }; await api.getThemeBundle(req, res); expect(res.status).toHaveBeenCalledWith(200); expect(res.send).toHaveBeenCalledWith({ - styles: [ - `/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`, - `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");` - ], - snippets: [ - "V3_Blank", - "V3_5ePHB" - ] + styles : [ + `/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`, + `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");` + ], + snippets : [ + 'V3_Blank', + 'V3_5ePHB' + ] }); }); - it('should return Theme Bundle for nested User and Static Themes together', async () => { + it('should return Theme Bundle for nested User and Static Themes together', async ()=>{ const brews = { - userThemeAID: { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style' }, - userThemeBID: { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style' }, - userThemeCID: { title: 'User Theme C', renderer: 'V3', theme: '5eDMG', shareId: 'userThemeCID', style: 'User Theme C Style' } + userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: 'userThemeBID', shareId: 'userThemeAID', style: 'User Theme A Style' }, + userThemeBID : { title: 'User Theme B', renderer: 'V3', theme: 'userThemeCID', shareId: 'userThemeBID', style: 'User Theme B Style' }, + userThemeCID : { title: 'User Theme C', renderer: 'V3', theme: '5eDMG', shareId: 'userThemeCID', style: 'User Theme C Style' } }; - const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); - model.get = jest.fn((getParams) => toBrewPromise(brews[getParams.shareId])); - const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; + const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); + model.get = jest.fn((getParams)=>toBrewPromise(brews[getParams.shareId])); + const req = { params: { renderer: 'V3', id: 'userThemeAID' }, get: ()=>{ return 'localhost'; }, protocol: 'https' }; await api.getThemeBundle(req, res); expect(res.status).toHaveBeenCalledWith(200); expect(res.send).toHaveBeenCalledWith({ - styles: [ - `/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`, - `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");`, - `/* From Theme 5eDMG */\n\n@import url("/themes/V3/5eDMG/style.css");`, - "/* From Brew: https://localhost/share/userThemeCID */\n\nUser Theme C Style", - "/* From Brew: https://localhost/share/userThemeBID */\n\nUser Theme B Style", - "/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style" - ], - snippets: [ - "V3_Blank", - "V3_5ePHB", - "V3_5eDMG" - ] + styles : [ + `/* From Theme Blank */\n\n@import url("/themes/V3/Blank/style.css");`, + `/* From Theme 5ePHB */\n\n@import url("/themes/V3/5ePHB/style.css");`, + `/* From Theme 5eDMG */\n\n@import url("/themes/V3/5eDMG/style.css");`, + '/* From Brew: https://localhost/share/userThemeCID */\n\nUser Theme C Style', + '/* From Brew: https://localhost/share/userThemeBID */\n\nUser Theme B Style', + '/* From Brew: https://localhost/share/userThemeAID */\n\nUser Theme A Style' + ], + snippets : [ + 'V3_Blank', + 'V3_5ePHB', + 'V3_5eDMG' + ] }); }); it('should fail for an invalid Theme in the chain', async()=>{ const brews = { - userThemeAID: { title: 'User Theme A', renderer: 'V3', theme: 'missingTheme', shareId: 'userThemeAID', style: 'User Theme A Style' }, + userThemeAID : { title: 'User Theme A', renderer: 'V3', theme: 'missingTheme', shareId: 'userThemeAID', style: 'User Theme A Style' }, }; - const toBrewPromise = (brew) => new Promise((res) => res({ toObject: () => brew })); - model.get = jest.fn((getParams) => toBrewPromise(brews[getParams.shareId])); - const req = { params: { renderer: "V3", id: "userThemeAID" }, get: () => { return 'localhost'; }, protocol: 'https' }; + const toBrewPromise = (brew)=>new Promise((res)=>res({ toObject: ()=>brew })); + model.get = jest.fn((getParams)=>toBrewPromise(brews[getParams.shareId])); + const req = { params: { renderer: 'V3', id: 'userThemeAID' }, get: ()=>{ return 'localhost'; }, protocol: 'https' }; - let err + let err; await api.getThemeBundle(req, res) - .catch(e => err = e); + .catch((e)=>err = e); expect(err).toEqual({ - HBErrorCode : "09", - accessType : "share", - brewId : "missingTheme", - message : "Theme Not Found", - name : "ThemeLoad Error", - status : 404}); + HBErrorCode : '09', + accessType : 'share', + brewId : 'missingTheme', + message : 'Theme Not Found', + name : 'ThemeLoad Error', + status : 404 }); }); }); diff --git a/shared/helpers.js b/shared/helpers.js index 90d0004b4..e5c1b7769 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -34,19 +34,19 @@ const printCurrentBrew = ()=>{ } }; -const fetchThemeBundle = async (obj, renderer, theme) => { +const fetchThemeBundle = async (obj, renderer, theme)=>{ const res = await request .get(`/api/theme/${renderer}/${theme}`) - .catch((err) => { - obj.setState({ error: err }); + .catch((err)=>{ + obj.setState({ error: err }); }); - if (!res) return; + if(!res) return; const themeBundle = res.body; - themeBundle.joinedStyles = themeBundle.styles.map((style) => ``).join('\n\n'); - obj.setState((prevState) => ({ - ...prevState, - themeBundle: themeBundle + themeBundle.joinedStyles = themeBundle.styles.map((style)=>``).join('\n\n'); + obj.setState((prevState)=>({ + ...prevState, + themeBundle : themeBundle })); }; From 32fa50d608fc0d473949467f11fd6a9dd82857b2 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 29 Jul 2024 12:30:13 -0400 Subject: [PATCH 120/121] Fallback to showing "Blank" theme if themes fail to load. --- client/homebrew/brewRenderer/brewRenderer.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index cdbbfc157..4b82c6bc0 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -125,7 +125,8 @@ const BrewRenderer = (props)=>{ const renderStyle = ()=>{ const cleanStyle = props.style; //DOMPurify.sanitize(props.style, purifyConfig); - return
${cleanStyle} ` }} />; + const themeStyles = props.themeBundle?.joinedStyles ?? ''; + return
${cleanStyle} ` }} />; }; const renderPage = (pageText, index)=>{ From 9cc81d2ff928f2f6082e5b30504227ac0335226a Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Mon, 29 Jul 2024 21:52:09 -0400 Subject: [PATCH 121/121] Up to v3.14.0 --- changelog.md | 30 ++++++++++++++++++++++++++++-- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index b331fc4f0..0cdb89c29 100644 --- a/changelog.md +++ b/changelog.md @@ -84,6 +84,34 @@ pre { ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). +### Monday 7/29/2024 - v3.14.0 +{{taskList + +##### abquintic, calculuschild + +* [x] Alternative Brew Themes, including importing other brews as a base theme. + +- In the :fas_circle_info: **Properties** menu, find the new {{openSans **THEME**}} dropdown. It lists Brew Themes, including a new **Blank** theme as a simpler basis for custom styling. +- Brews tagged with `meta:theme` will appear in the Brew Themes list. Selecting one loads its :fas_paintbrush: **Style** tab contents as the CSS basis for the current brew, allowing one brew to style multiple documents. +- Brews with `meta:theme` can also select their own Theme, i.e. layering Themes on top of each other. +- The next goal is to make **Published** Themes shareable between users. + + +Fixes issues [#1899](https://github.com/naturalcrit/homebrewery/issues/1899), [#3085](https://github.com/naturalcrit/homebrewery/issues/3085) + +##### G-Ambatte + +* [x] Fix Drop-cap font becoming corrupted when Bold + +Fixes issues [#3551](https://github.com/naturalcrit/homebrewery/issues/3551) + +* [x] Fixes to UI styling + +Fixes issues [#3568](https://github.com/naturalcrit/homebrewery/issues/3568) + +}} + + ### Saturday 6/7/2024 - v3.13.1 {{taskList @@ -131,8 +159,6 @@ Fixes issue [#3298](https://github.com/naturalcrit/homebrewery/issues/3298) Fixes issue [#3397](https://github.com/naturalcrit/homebrewery/issues/3397) }} -\column - ### Monday 18/3/2024 - v3.12.0 {{taskList diff --git a/package-lock.json b/package-lock.json index cce4d5577..64ce3c77c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "homebrewery", - "version": "3.13.1", + "version": "3.14.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "homebrewery", - "version": "3.13.1", + "version": "3.14.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 321f9afbe..2aa695228 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebrewery", "description": "Create authentic looking D&D homebrews using only markdown", - "version": "3.13.1", + "version": "3.14.0", "engines": { "npm": "^10.2.x", "node": "^20.8.x"