From c5461f2ea2b6a703d4fb9717211ea3b7802bbbf8 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 13 Oct 2026 12:16:26 -0500 Subject: [PATCH 1/9] Rebuild BR Issue_5048 Moves calls to compress/decompress the text/textBin document members to the hombrewery model code. Compression is done in a save().pre setup. Decompression was already handled in the static for loading a brew but the textBin member was not emptied on decompression. --- package-lock.json | 147 +++++++++++++++++------------------- server/homebrew.api.js | 15 +--- server/homebrew.api.spec.js | 15 +++- server/homebrew.model.js | 8 ++ 4 files changed, 88 insertions(+), 97 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e4277d3a..d17c0ace2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2360,6 +2360,7 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2371,6 +2372,7 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2381,6 +2383,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -3646,6 +3649,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.4.tgz", "integrity": "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -3782,6 +3786,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3802,6 +3807,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3822,6 +3828,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3842,6 +3849,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3862,9 +3870,7 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3885,9 +3891,7 @@ "cpu": [ "arm" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3908,9 +3912,7 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3931,9 +3933,7 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3954,9 +3954,7 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3977,9 +3975,7 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4000,6 +3996,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4020,6 +4017,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4037,6 +4035,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "license": "MIT", "optional": true, "engines": { @@ -4165,9 +4164,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4184,9 +4180,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4203,9 +4196,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4222,9 +4212,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4241,9 +4228,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4260,9 +4244,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4404,6 +4385,7 @@ "version": "0.10.4", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -4913,6 +4895,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4926,6 +4909,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4939,6 +4923,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4952,6 +4937,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4965,6 +4951,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4978,6 +4965,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4991,6 +4979,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5004,9 +4993,7 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5020,9 +5007,7 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5036,9 +5021,7 @@ "cpu": [ "loong64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5052,9 +5035,7 @@ "cpu": [ "loong64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5068,9 +5049,7 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5084,9 +5063,7 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5100,9 +5077,7 @@ "cpu": [ "riscv64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5116,9 +5091,7 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5132,9 +5105,7 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5148,9 +5119,7 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5164,6 +5133,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5177,6 +5147,7 @@ "cpu": [ "wasm32" ], + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -5195,6 +5166,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5208,6 +5180,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5221,6 +5194,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11278,9 +11252,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -11301,9 +11272,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -11324,9 +11292,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -11347,9 +11312,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -11907,6 +11869,33 @@ "url": "https://opencollective.com/mongoose" } }, + "node_modules/mongoose/node_modules/gcp-metadata": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", + "integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/mongoose/node_modules/google-logging-utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.2.0.tgz", + "integrity": "sha512-WE9av4wKDZgRjBwgVUabocx8T6/7o3Ca1Fat46FXDhXVAFibzNadedcOXrdgd1Kzmk8tsk/9ZH89Wyf/SqeZ3A==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/mongoose/node_modules/mongodb": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.7.0.tgz", @@ -14725,7 +14714,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "devOptional": true, + "dev": true, "license": "0BSD" }, "node_modules/type-check": { diff --git a/server/homebrew.api.js b/server/homebrew.api.js index aa1f1f84a..efea261b3 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -2,7 +2,6 @@ import _ from 'lodash'; import { model as HomebrewModel } from './homebrew.model.js'; import express from 'express'; -import zlib from 'zlib'; import GoogleActions from './googleActions.js'; import { hbfm } from 'marked-hbfm'; import * as yaml from 'js-yaml'; @@ -303,13 +302,8 @@ const api = { if(!googleId) return; api.excludeStubProps(newHomebrew); newHomebrew.googleId = googleId; - } else { - // Compress brew text to binary before saving - newHomebrew.textBin = zlib.deflateRawSync(newHomebrew.text); - // Delete the non-binary text field since it's not needed anymore - newHomebrew.text = undefined; } - + saved = await newHomebrew.save() .catch((err)=>{ console.error(err, err.toString(), err.stack); @@ -464,11 +458,6 @@ const api = { if(brew.googleId) { // If the google id exists after all those actions, exclude the props that are stored in google and aren't needed for rendering the brew items api.excludeStubProps(brew); - } else { - // Compress brew text to binary before saving - brew.textBin = zlib.deflateRawSync(brew.text); - // Delete the non-binary text field since it's not needed anymore - brew.text = undefined; } brew.updatedAt = new Date(); brew.version = (brew.version || 1) + 1; @@ -549,8 +538,6 @@ const api = { if(shouldDeleteGoogleBrew) { // When there are still authors remaining, we delete the google brew but store the full brew in the Homebrewery database brew.googleId = undefined; - brew.textBin = zlib.deflateRawSync(brew.text); - brew.text = undefined; } brew.markModified('authors'); //Mongo will not properly update arrays without markModified() await brew.save() diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 8bda5407b..68aeec616 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -700,8 +700,16 @@ brew`); shareId : expect.any(String), style : undefined, tags : [], - text : undefined, - textBin : expect.objectContaining({}), + text : '```metadata\n' + + 'title: asdf\n' + + 'bleedSize: {}\n' + + 'safetySpace: {}\n' + + 'trimSize: {}\n' + + '\n' + + '```\n' + + '\n' + + 'asdf', + textBin : undefined, theme : '5ePHB', thumbnail : '', title : 'asdf', @@ -1233,8 +1241,7 @@ brew`); expect(saveFunc).toHaveBeenCalled(); expect(saved.authors).toEqual(['test2']); expect(saved.googleId).toEqual(undefined); - expect(saved.text).toEqual(undefined); - expect(saved.textBin).not.toEqual(undefined); + expect(saved.text).not.toEqual(undefined); }); it('should retain google brew and update stub when multiple authors and extra author requests deletion', async ()=>{ diff --git a/server/homebrew.model.js b/server/homebrew.model.js index e923ac928..b78ece631 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -32,6 +32,13 @@ const HomebrewSchema = mongoose.Schema({ lock : { type: Object, index: true } }, { versionKey: false }); +HomebrewSchema.pre('save', ()=>{ + if(!this.googleId) { + this.textBin = zlib.deflateRawSync(this.text); + this.text = undefined; + } +}); + HomebrewSchema.statics.increaseView = async function(query) { const brew = await Homebrew.findOne(query).exec(); brew.lastViewed = new Date(); @@ -51,6 +58,7 @@ HomebrewSchema.statics.get = async function(query, fields=null){ if(!_.isNil(brew.textBin)) { // Uncompress zipped text field const unzipped = zlib.inflateRawSync(brew.textBin); brew.text = unzipped.toString(); + brew.textBin = undefined; } return brew; }; From a322812cd82b6866d57b9fb511f0af932e9fceb9 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 19 Oct 2026 13:29:42 -0500 Subject: [PATCH 2/9] Revert package-lock.json changes --- package-lock.json | 147 +++++++++++++++++++++++++--------------------- 1 file changed, 79 insertions(+), 68 deletions(-) diff --git a/package-lock.json b/package-lock.json index d17c0ace2..0e4277d3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2360,7 +2360,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2372,7 +2371,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -2383,7 +2381,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -3649,7 +3646,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.4.tgz", "integrity": "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -3786,7 +3782,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3807,7 +3802,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3828,7 +3822,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3849,7 +3842,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3870,7 +3862,9 @@ "cpu": [ "arm" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3891,7 +3885,9 @@ "cpu": [ "arm" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3912,7 +3908,9 @@ "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3933,7 +3931,9 @@ "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3954,7 +3954,9 @@ "cpu": [ "x64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -3975,7 +3977,9 @@ "cpu": [ "x64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -3996,7 +4000,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4017,7 +4020,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4035,7 +4037,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "license": "MIT", "optional": true, "engines": { @@ -4164,6 +4165,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4180,6 +4184,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -4196,6 +4203,9 @@ "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4212,6 +4222,9 @@ "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4228,6 +4241,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -4244,6 +4260,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -4385,7 +4404,6 @@ "version": "0.10.4", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -4895,7 +4913,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4909,7 +4926,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4923,7 +4939,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4937,7 +4952,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4951,7 +4965,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4965,7 +4978,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4979,7 +4991,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4993,7 +5004,9 @@ "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5007,7 +5020,9 @@ "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5021,7 +5036,9 @@ "cpu": [ "loong64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5035,7 +5052,9 @@ "cpu": [ "loong64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5049,7 +5068,9 @@ "cpu": [ "ppc64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5063,7 +5084,9 @@ "cpu": [ "riscv64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5077,7 +5100,9 @@ "cpu": [ "riscv64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5091,7 +5116,9 @@ "cpu": [ "s390x" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5105,7 +5132,9 @@ "cpu": [ "x64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -5119,7 +5148,9 @@ "cpu": [ "x64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -5133,7 +5164,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5147,7 +5177,6 @@ "cpu": [ "wasm32" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -5166,7 +5195,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5180,7 +5208,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5194,7 +5221,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -11252,6 +11278,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -11272,6 +11301,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -11292,6 +11324,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -11312,6 +11347,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -11869,33 +11907,6 @@ "url": "https://opencollective.com/mongoose" } }, - "node_modules/mongoose/node_modules/gcp-metadata": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", - "integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/mongoose/node_modules/google-logging-utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.2.0.tgz", - "integrity": "sha512-WE9av4wKDZgRjBwgVUabocx8T6/7o3Ca1Fat46FXDhXVAFibzNadedcOXrdgd1Kzmk8tsk/9ZH89Wyf/SqeZ3A==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - } - }, "node_modules/mongoose/node_modules/mongodb": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.7.0.tgz", @@ -14714,7 +14725,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, + "devOptional": true, "license": "0BSD" }, "node_modules/type-check": { From d65aa2d7f080919ec8351366697f1772c80e3417 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 21 Oct 2026 19:47:57 +0000 Subject: [PATCH 3/9] Unwind stub/nostub saving logic --- server/homebrew.api.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 2fd81e4f2..8f18543dc 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -447,16 +447,14 @@ const api = { console.error(err); res.status(err.status || 500).send(err.message || 'Unable to save brew to Homebrewery database'); }; - let saved; - if(!brew._id) { - // if the brew does not have a stub id, create and save it, then write the new value back to the brew. - saved = await new HomebrewModel(brew).save().catch(saveError); - } else { - // if the brew does have a stub id, update it using the stub id as the key. + + if(brew._id) // if the brew has a stub id, fetch and merge into Mongo stub document brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew); - saved = await brew.save() - .catch(saveError); - } + else // if not, create a new Mongo document + brew = new HomebrewModel(brew); + + let saved = await brew.save().catch(saveError); + if(!saved) return; // Call and wait for afterSave to complete const after = await afterSave(); From e1ddac766ff798711a5f9fd956eb6a75869bb0d2 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 21 Oct 2026 20:07:45 +0000 Subject: [PATCH 4/9] Unwind google deletion logic --- server/homebrew.api.js | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 8f18543dc..77a2dff6d 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -398,20 +398,12 @@ const api = { brew.description = brew.description.trim() || ''; brew.text = api.mergeBrewText(brew); + //=====----- Update to or remove from Google Drive -----=========// const googleId = brew.googleId; const { saveToGoogle, removeFromGoogle } = req.query; - let afterSave = async ()=>true; 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 - afterSave = async ()=>{ - return await api.deleteGoogleBrew(req.account, googleId, brew.editId, res) - .catch((err)=>{ - console.error(err); - res.status(err?.status || err?.response?.status || 500).send(err.message || err); - }); - }; - + // If the google id exists and we're removing it from google, mark the brew's google id as undefined brew.googleId = undefined; } else if(!brew.googleId && saveToGoogle) { // If we don't have a google id and the user wants to save to google, create the google brew and set the google id on the brew @@ -425,8 +417,9 @@ const api = { if(!updated) return; } + //=====----- Update to Mongo -----=====// if(brew.googleId) { - // If the google id exists after all those actions, exclude the props that are stored in google and aren't needed for rendering the brew items + // If google id exists after above actions, Mongo will store only a stub; exclude non-stub properties from update brew = api.excludeStubProps(brew); } else { // Compress brew text to binary before saving @@ -454,11 +447,17 @@ const api = { brew = new HomebrewModel(brew); let saved = await brew.save().catch(saveError); - if(!saved) return; - // Call and wait for afterSave to complete - const after = await afterSave(); - if(!after) return; + + if(googleId && removeFromGoogle) { + const deleted = await api.deleteGoogleBrew(req.account, googleId, brew.editId, res) + .catch((err)=>{ + console.error(err); + res.status(err?.status || err?.response?.status || 500).send(err.message || err); + }); + + if(!deleted) return; + } saved.textBin = undefined; // Remove textBin from the saved object to save bandwidth From a8312ba3ff7f50881a0030db41307c9509f19b52 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 21 Oct 2026 20:08:41 +0000 Subject: [PATCH 5/9] Remove redundant excludeGoogleProps from newGoogleBrew call --- 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 77a2dff6d..5715378ae 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -407,7 +407,7 @@ const api = { brew.googleId = undefined; } else if(!brew.googleId && saveToGoogle) { // If we don't have a google id and the user wants to save to google, create the google brew and set the google id on the brew - brew.googleId = await api.newGoogleBrew(req.account, api.excludeGoogleProps(brew), res); + brew.googleId = await api.newGoogleBrew(req.account, brew, res); if(!brew.googleId) return; } else if(brew.googleId) { From 7bd6e7b7ab998391b8535389528a3603e957bc68 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 21 Oct 2026 20:24:33 +0000 Subject: [PATCH 6/9] Group brew-normalizing steps together --- server/homebrew.api.js | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 5715378ae..53f3c6e11 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -397,23 +397,26 @@ const api = { brew.title = brew.title.trim(); brew.description = brew.description.trim() || ''; brew.text = api.mergeBrewText(brew); + brew.updatedAt = new Date(); + brew.version = (brew.version || 1) + 1; + if(req.account) { + brew.authors = _.uniq(_.concat(brew.authors, req.account.username)); + brew.invitedAuthors = _.uniq(_.filter(brew.invitedAuthors, (a)=>req.account.username !== a)); + } //=====----- Update to or remove from Google Drive -----=========// const googleId = brew.googleId; const { saveToGoogle, removeFromGoogle } = req.query; - if(brew.googleId && removeFromGoogle) { - // If the google id exists and we're removing it from google, mark the brew's google id as undefined + if(brew.googleId && removeFromGoogle) { // If removing from google, remove the brew's googleId brew.googleId = undefined; - } else if(!brew.googleId && saveToGoogle) { - // If we don't have a google id and the user wants to save to google, create the google brew and set the google id on the brew + } + else if(!brew.googleId && saveToGoogle) { // If adding to google, create new google document and record the googleId brew.googleId = await api.newGoogleBrew(req.account, brew, res); - if(!brew.googleId) return; - } else if(brew.googleId) { - // If the google id exists and no other actions are being performed, update the google brew + } + else if(brew.googleId) { // If already on google, update the google brew const updated = await GoogleActions.updateGoogleBrew(api.excludeGoogleProps(brew), req.ip); - if(!updated) return; } @@ -427,13 +430,6 @@ const api = { // Delete the non-binary text field since it's not needed anymore brew.text = undefined; } - brew.updatedAt = new Date(); - brew.version = (brew.version || 1) + 1; - - if(req.account) { - brew.authors = _.uniq(_.concat(brew.authors, req.account.username)); - brew.invitedAuthors = _.uniq(_.filter(brew.invitedAuthors, (a)=>req.account.username !== a)); - } // define a function to catch our save errors const saveError = (err)=>{ From a430a5c3ef9dad0c2a7f9de935764ff136973636 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Wed, 21 Oct 2026 20:40:04 +0000 Subject: [PATCH 7/9] Inline the "saveError" function --- server/homebrew.api.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 53f3c6e11..6bcd293b0 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -223,7 +223,7 @@ const api = { return _.omit(brew, ['_id', 'views', 'lastViewed']); }, excludeGoogleProps : (brew)=>{ //Remove props that should not be saved to Google (only stored to Homebrewery stub) - return _.omit(brew, ['version', 'tags', 'systems', 'published', 'authors', 'owner', 'views', 'thumbnail']); + return _.omit(brew, ['version', 'tags', 'systems', 'published', 'authors', 'invitedAuthors', 'owner', 'views', 'thumbnail']); }, excludeStubProps : (brew)=>{ //Remove props that should not be saved to stub-only brews brew.text = brew.textBin = undefined; // Can't use _.omit because this brew is a Mongoose object @@ -345,7 +345,6 @@ const api = { return res.status(200).send(returnObj); }, 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); const brewFromServer = req.brew; @@ -405,7 +404,7 @@ const api = { } //=====----- Update to or remove from Google Drive -----=========// - const googleId = brew.googleId; + const originalGoogleId = brew.googleId; const { saveToGoogle, removeFromGoogle } = req.query; if(brew.googleId && removeFromGoogle) { // If removing from google, remove the brew's googleId @@ -431,22 +430,21 @@ const api = { brew.text = undefined; } - // define a function to catch our save errors - const saveError = (err)=>{ - console.error(err); - res.status(err.status || 500).send(err.message || 'Unable to save brew to Homebrewery database'); - }; - if(brew._id) // if the brew has a stub id, fetch and merge into Mongo stub document brew = _.assign(await HomebrewModel.findOne({ _id: brew._id }), brew); else // if not, create a new Mongo document brew = new HomebrewModel(brew); - let saved = await brew.save().catch(saveError); + let saved = await brew.save() + .catch((err)=>{ + console.error(err); + res.status(err.status || 500).send(err.message || 'Unable to save brew to Homebrewery database'); + }); + if(!saved) return; - if(googleId && removeFromGoogle) { - const deleted = await api.deleteGoogleBrew(req.account, googleId, brew.editId, res) + if(originalGoogleId && removeFromGoogle) { + const deleted = await api.deleteGoogleBrew(req.account, originalGoogleId, brew.editId, res) .catch((err)=>{ console.error(err); res.status(err?.status || err?.response?.status || 500).send(err.message || err); From 720aaba3b335304282145b885bbc78d551e2063f Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 22 Oct 2026 16:36:00 +0000 Subject: [PATCH 8/9] Fix tests for metadata order changed --- server/homebrew.api.js | 2 +- server/homebrew.api.spec.js | 122 ++++++++++++++++++------------------ 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 37fded14b..34c620096 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -208,7 +208,7 @@ const api = { metadata.trimSize = { width: brew?.trimSize?.width, height: brew?.trimSize?.height }; text = `\`\`\`metadata\n` + - `${yaml.dump(metadata)}\n` + + `${yaml.dump(metadata)}` + `\`\`\`\n\n` + `${text}`; return text; diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 68aeec616..ad6d3ac7e 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -1,6 +1,7 @@ /* eslint-disable max-lines */ import { splitTextStyleAndMetadata } from '../shared/helpers.js'; +import dedent from 'dedent'; describe('Tests for api', ()=>{ let api; @@ -493,35 +494,35 @@ describe('Tests for api', ()=>{ }, }); - expect(result).toEqual(`\`\`\`metadata -title: some title -description: this is a description -tags: - - something - - fun -renderer: v3 -theme: phb -bleedSize: - top: .125in - bottom: .125in - inner: .125in - outer: .125in -safetySpace: - top: .25in - bottom: .25in - outer: .25in - inner: .5in -trimSize: - width: 8.5in - height: 11in -columns: '2' -columnGutter: .125in -license: None -legalAuthors: '' + expect(result).toEqual(dedent` + \`\`\`metadata + title: some title + description: this is a description + tags: + - something + - fun + renderer: v3 + theme: phb + columns: '2' + columnGutter: .125in + license: None + legalAuthors: '' + bleedSize: + top: .125in + bottom: .125in + inner: .125in + outer: .125in + safetySpace: + top: .25in + bottom: .25in + outer: .25in + inner: .5in + trimSize: + width: 8.5in + height: 11in + \`\`\` -\`\`\` - -brew`); + brew`); }); it('should set metadata and style', ()=>{ @@ -556,39 +557,39 @@ brew`); }, }); - expect(result).toEqual(`\`\`\`metadata -title: some title -description: this is a description -tags: - - something - - fun -renderer: v3 -theme: phb -bleedSize: - top: .125in - bottom: .125in - inner: .125in - outer: .125in -safetySpace: - top: .25in - bottom: .25in - outer: .25in - inner: .5in -trimSize: - width: 8.5in - height: 11in -columns: '2' -columnGutter: .125in -license: None -legalAuthors: '' + expect(result).toEqual(dedent` + \`\`\`metadata + title: some title + description: this is a description + tags: + - something + - fun + renderer: v3 + theme: phb + columns: '2' + columnGutter: .125in + license: None + legalAuthors: '' + bleedSize: + top: .125in + bottom: .125in + inner: .125in + outer: .125in + safetySpace: + top: .25in + bottom: .25in + outer: .25in + inner: .5in + trimSize: + width: 8.5in + height: 11in + \`\`\` -\`\`\` + \`\`\`css + hello yes i am css + \`\`\` -\`\`\`css -hello yes i am css -\`\`\` - -brew`); + brew`); }); }); describe('exclusion methods', ()=>{ @@ -704,12 +705,11 @@ brew`); 'title: asdf\n' + 'bleedSize: {}\n' + 'safetySpace: {}\n' + - 'trimSize: {}\n' + + 'trimSize: {}' + '\n' + '```\n' + '\n' + 'asdf', - textBin : undefined, theme : '5ePHB', thumbnail : '', title : 'asdf', From 3c935299953fb04683dc89e02c8dfad54341f67e Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 22 Oct 2026 17:24:15 +0000 Subject: [PATCH 9/9] Small logic fix to brew.save pre --- server/homebrew.api.js | 4 ++-- server/homebrew.model.js | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 34c620096..c572b2cec 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -402,7 +402,7 @@ const api = { const originalGoogleId = brew.googleId; const { saveToGoogle, removeFromGoogle } = req.query; - if(brew.googleId && removeFromGoogle) { // If removing from google, remove the brew's googleId + if(brew.googleId && removeFromGoogle) { // If removing from google, remove the brew's googleId brew.googleId = undefined; } else if(!brew.googleId && saveToGoogle) { // If adding to google, create new google document and record the googleId @@ -425,7 +425,7 @@ const api = { else // if not, create a new Mongo document brew = new HomebrewModel(brew); - let saved = await brew.save() + const saved = await brew.save() .catch((err)=>{ console.error(err); res.status(err.status || 500).send(err.message || 'Unable to save brew to Homebrewery database'); diff --git a/server/homebrew.model.js b/server/homebrew.model.js index b78ece631..eceb08440 100644 --- a/server/homebrew.model.js +++ b/server/homebrew.model.js @@ -32,8 +32,8 @@ const HomebrewSchema = mongoose.Schema({ lock : { type: Object, index: true } }, { versionKey: false }); -HomebrewSchema.pre('save', ()=>{ - if(!this.googleId) { +HomebrewSchema.pre('save', function() { + if(this.text !== undefined) { this.textBin = zlib.deflateRawSync(this.text); this.text = undefined; } @@ -44,9 +44,9 @@ HomebrewSchema.statics.increaseView = async function(query) { brew.lastViewed = new Date(); brew.views = brew.views + 1; await brew.save() - .catch((err)=>{ - return err; - }); + .catch((err)=>{ + return err; + }); return brew; };