Recipe sharing platform built on AT Protocol
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Initial commit with app password auth, lexicons and create recipes with discover feed

Nic Coates 27147564

+3189
+4
.gitignore
··· 1 + node_modules/ 2 + .env 3 + *.log 4 + .DS_Store
+52
app.js
··· 1 + require("dotenv").config(); 2 + const express = require("express"); 3 + const session = require("express-session"); 4 + const path = require("path"); 5 + 6 + const app = express(); 7 + const PORT = process.env.PORT || 3000; 8 + 9 + // View engine setup 10 + app.set("view engine", "ejs"); 11 + app.set("views", path.join(__dirname, "views")); 12 + 13 + // Middleware 14 + app.use(express.json()); 15 + app.use(express.urlencoded({ extended: true })); 16 + app.use(express.static(path.join(__dirname, "public"))); 17 + 18 + // Session configuration 19 + app.use( 20 + session({ 21 + secret: process.env.SESSION_SECRET, 22 + resave: false, 23 + saveUninitialized: false, 24 + cookie: { 25 + secure: process.env.NODE_ENV === "production", 26 + httpOnly: true, 27 + maxAge: 24 * 60 * 60 * 1000, // 24 hours 28 + }, 29 + }), 30 + ); 31 + 32 + app.use("/", require("./routes/index")); 33 + app.use("/auth", require("./routes/auth")); 34 + app.use("/recipe", require("./routes/recipe")); 35 + // app.use('/user', require('./routes/user')); 36 + 37 + // 404 handler 38 + app.use((req, res) => { 39 + res.status(404).send("Page not found"); 40 + }); 41 + 42 + // Error handler 43 + app.use((err, req, res, next) => { 44 + console.error(err.stack); 45 + res.status(500).send("Something went wrong!"); 46 + }); 47 + 48 + // Start server 49 + app.listen(PORT, () => { 50 + console.log(`BlueRecipes running on http://localhost:${PORT}`); 51 + console.log(`Environment: ${process.env.NODE_ENV}`); 52 + });
+8
config/database.js
··· 1 + const { createClient } = require("@libsql/client"); 2 + 3 + const db = createClient({ 4 + url: process.env.TURSO_DATABASE_URL, 5 + authToken: process.env.TURSO_AUTH_TOKEN, 6 + }); 7 + 8 + module.exports = db;
+27
config/init-db.js
··· 1 + require("dotenv").config(); 2 + const db = require("./database"); 3 + const fs = require("fs"); 4 + const path = require("path"); 5 + 6 + async function initDatabase() { 7 + try { 8 + const schema = fs.readFileSync(path.join(__dirname, "schema.sql"), "utf-8"); 9 + 10 + // Split by semicolon and filter out empty statements 11 + const statements = schema 12 + .split(";") 13 + .map((s) => s.trim()) 14 + .filter((s) => s.length > 0); 15 + 16 + // Execute each statement separately 17 + for (const statement of statements) { 18 + await db.execute(statement); 19 + } 20 + 21 + console.log("✅ Database initialized successfully"); 22 + } catch (error) { 23 + console.error("❌ Database initialization failed:", error); 24 + } 25 + } 26 + 27 + initDatabase();
+32
config/schema.sql
··· 1 + -- Users table 2 + CREATE TABLE IF NOT EXISTS users ( 3 + id INTEGER PRIMARY KEY AUTOINCREMENT, 4 + did TEXT UNIQUE NOT NULL, 5 + handle TEXT NOT NULL, 6 + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, 7 + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP 8 + ); 9 + 10 + -- Recipes table 11 + CREATE TABLE IF NOT EXISTS recipes ( 12 + id INTEGER PRIMARY KEY AUTOINCREMENT, 13 + did TEXT NOT NULL, 14 + title TEXT NOT NULL, 15 + description TEXT, 16 + prep_time INTEGER NOT NULL, 17 + cook_time INTEGER NOT NULL, 18 + servings TEXT NOT NULL, 19 + ingredients TEXT NOT NULL, 20 + steps TEXT NOT NULL, 21 + type TEXT NOT NULL, 22 + at_uri TEXT UNIQUE NOT NULL, 23 + cid TEXT NOT NULL, 24 + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, 25 + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, 26 + FOREIGN KEY (did) REFERENCES users(did) 27 + ); 28 + 29 + -- Index for faster lookups 30 + CREATE INDEX IF NOT EXISTS idx_recipes_did ON recipes(did); 31 + CREATE INDEX IF NOT EXISTS idx_recipes_type ON recipes(type); 32 + CREATE INDEX IF NOT EXISTS idx_recipes_created ON recipes(created_at DESC);
+75
lexicons/net.bluerecipes.recipe.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "net.bluerecipes.recipe", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "A recipe post on BlueRecipes", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": [ 12 + "title", 13 + "prepTime", 14 + "cookTime", 15 + "servings", 16 + "ingredients", 17 + "steps", 18 + "type", 19 + "createdAt" 20 + ], 21 + "properties": { 22 + "title": { 23 + "type": "string", 24 + "maxLength": 300, 25 + "description": "Recipe title" 26 + }, 27 + "description": { 28 + "type": "string", 29 + "maxLength": 1000, 30 + "description": "Short description of the recipe" 31 + }, 32 + "prepTime": { 33 + "type": "integer", 34 + "description": "Preparation time in minutes" 35 + }, 36 + "cookTime": { 37 + "type": "integer", 38 + "description": "Cooking time in minutes" 39 + }, 40 + "servings": { 41 + "type": "string", 42 + "maxLength": 50, 43 + "description": "Number of servings (e.g. '4-6' or '8')" 44 + }, 45 + "ingredients": { 46 + "type": "string", 47 + "maxLength": 10000, 48 + "description": "Recipe ingredients as text" 49 + }, 50 + "steps": { 51 + "type": "string", 52 + "maxLength": 10000, 53 + "description": "Recipe steps/instructions as text" 54 + }, 55 + "type": { 56 + "type": "string", 57 + "knownValues": [ 58 + "breakfast", 59 + "lunch", 60 + "dinner", 61 + "snacks", 62 + "dessert" 63 + ], 64 + "description": "Recipe category" 65 + }, 66 + "createdAt": { 67 + "type": "string", 68 + "format": "datetime", 69 + "description": "When the recipe was created" 70 + } 71 + } 72 + } 73 + } 74 + } 75 + }
+2141
package-lock.json
··· 1 + { 2 + "name": "bluerecipes", 3 + "version": "1.0.0", 4 + "lockfileVersion": 3, 5 + "requires": true, 6 + "packages": { 7 + "": { 8 + "name": "bluerecipes", 9 + "version": "1.0.0", 10 + "license": "ISC", 11 + "dependencies": { 12 + "@atproto/api": "^0.18.18", 13 + "@atproto/oauth-client-node": "^0.3.16", 14 + "@libsql/client": "^0.17.0", 15 + "dotenv": "^17.2.3", 16 + "ejs": "^4.0.1", 17 + "express": "^5.2.1", 18 + "express-session": "^1.19.0" 19 + }, 20 + "devDependencies": { 21 + "nodemon": "^3.1.11" 22 + } 23 + }, 24 + "node_modules/@atproto-labs/did-resolver": { 25 + "version": "0.2.6", 26 + "resolved": "https://registry.npmjs.org/@atproto-labs/did-resolver/-/did-resolver-0.2.6.tgz", 27 + "integrity": "sha512-2K1bC04nI2fmgNcvof+yA28IhGlpWn2JKYlPa7To9JTKI45FINCGkQSGiL2nyXlyzDJJ34fZ1aq6/IRFIOIiqg==", 28 + "license": "MIT", 29 + "dependencies": { 30 + "@atproto-labs/fetch": "0.2.3", 31 + "@atproto-labs/pipe": "0.1.1", 32 + "@atproto-labs/simple-store": "0.3.0", 33 + "@atproto-labs/simple-store-memory": "0.1.4", 34 + "@atproto/did": "0.3.0", 35 + "zod": "^3.23.8" 36 + } 37 + }, 38 + "node_modules/@atproto-labs/fetch": { 39 + "version": "0.2.3", 40 + "resolved": "https://registry.npmjs.org/@atproto-labs/fetch/-/fetch-0.2.3.tgz", 41 + "integrity": "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw==", 42 + "license": "MIT", 43 + "dependencies": { 44 + "@atproto-labs/pipe": "0.1.1" 45 + } 46 + }, 47 + "node_modules/@atproto-labs/fetch-node": { 48 + "version": "0.2.0", 49 + "resolved": "https://registry.npmjs.org/@atproto-labs/fetch-node/-/fetch-node-0.2.0.tgz", 50 + "integrity": "sha512-Krq09nH/aeoiU2s9xdHA0FjTEFWG9B5FFenipv1iRixCcPc7V3DhTNDawxG9gI8Ny0k4dBVS9WTRN/IDzBx86Q==", 51 + "license": "MIT", 52 + "dependencies": { 53 + "@atproto-labs/fetch": "0.2.3", 54 + "@atproto-labs/pipe": "0.1.1", 55 + "ipaddr.js": "^2.1.0", 56 + "undici": "^6.14.1" 57 + }, 58 + "engines": { 59 + "node": ">=18.7.0" 60 + } 61 + }, 62 + "node_modules/@atproto-labs/fetch-node/node_modules/ipaddr.js": { 63 + "version": "2.3.0", 64 + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", 65 + "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", 66 + "license": "MIT", 67 + "engines": { 68 + "node": ">= 10" 69 + } 70 + }, 71 + "node_modules/@atproto-labs/handle-resolver": { 72 + "version": "0.3.6", 73 + "resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver/-/handle-resolver-0.3.6.tgz", 74 + "integrity": "sha512-qnSTXvOBNj1EHhp2qTWSX8MS5q3AwYU5LKlt5fBvSbCjgmTr2j0URHCv+ydrwO55KvsojIkTMgeMOh4YuY4fCA==", 75 + "license": "MIT", 76 + "dependencies": { 77 + "@atproto-labs/simple-store": "0.3.0", 78 + "@atproto-labs/simple-store-memory": "0.1.4", 79 + "@atproto/did": "0.3.0", 80 + "zod": "^3.23.8" 81 + } 82 + }, 83 + "node_modules/@atproto-labs/handle-resolver-node": { 84 + "version": "0.1.25", 85 + "resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver-node/-/handle-resolver-node-0.1.25.tgz", 86 + "integrity": "sha512-NY9WYM2VLd3IuMGRkkmvGBg8xqVEaK/fitv1vD8SMXqFTekdpjOLCCyv7EFtqVHouzmDcL83VOvWRfHVa8V9Yw==", 87 + "license": "MIT", 88 + "dependencies": { 89 + "@atproto-labs/fetch-node": "0.2.0", 90 + "@atproto-labs/handle-resolver": "0.3.6", 91 + "@atproto/did": "0.3.0" 92 + }, 93 + "engines": { 94 + "node": ">=18.7.0" 95 + } 96 + }, 97 + "node_modules/@atproto-labs/identity-resolver": { 98 + "version": "0.3.6", 99 + "resolved": "https://registry.npmjs.org/@atproto-labs/identity-resolver/-/identity-resolver-0.3.6.tgz", 100 + "integrity": "sha512-qoWqBDRobln0NR8L8dQjSp79E0chGkBhibEgxQa2f9WD+JbJdjQ0YvwwO5yeQn05pJoJmAwmI2wyJ45zjU7aWg==", 101 + "license": "MIT", 102 + "dependencies": { 103 + "@atproto-labs/did-resolver": "0.2.6", 104 + "@atproto-labs/handle-resolver": "0.3.6" 105 + } 106 + }, 107 + "node_modules/@atproto-labs/pipe": { 108 + "version": "0.1.1", 109 + "resolved": "https://registry.npmjs.org/@atproto-labs/pipe/-/pipe-0.1.1.tgz", 110 + "integrity": "sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg==", 111 + "license": "MIT" 112 + }, 113 + "node_modules/@atproto-labs/simple-store": { 114 + "version": "0.3.0", 115 + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store/-/simple-store-0.3.0.tgz", 116 + "integrity": "sha512-nOb6ONKBRJHRlukW1sVawUkBqReLlLx6hT35VS3imaNPwiXDxLnTK7lxw3Lrl9k5yugSBDQAkZAq3MPTEFSUBQ==", 117 + "license": "MIT" 118 + }, 119 + "node_modules/@atproto-labs/simple-store-memory": { 120 + "version": "0.1.4", 121 + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.4.tgz", 122 + "integrity": "sha512-3mKY4dP8I7yKPFj9VKpYyCRzGJOi5CEpOLPlRhoJyLmgs3J4RzDrjn323Oakjz2Aj2JzRU/AIvWRAZVhpYNJHw==", 123 + "license": "MIT", 124 + "dependencies": { 125 + "@atproto-labs/simple-store": "0.3.0", 126 + "lru-cache": "^10.2.0" 127 + } 128 + }, 129 + "node_modules/@atproto/api": { 130 + "version": "0.18.18", 131 + "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.18.18.tgz", 132 + "integrity": "sha512-Vg7/sjbwDQZDj8fXtb4E48U4gA+6RC1iSt7onGnH2NyR0E25uds1KnqSKMzqcphdJXrz5GXrgHWc747XPGibzg==", 133 + "license": "MIT", 134 + "dependencies": { 135 + "@atproto/common-web": "^0.4.14", 136 + "@atproto/lexicon": "^0.6.1", 137 + "@atproto/syntax": "^0.4.3", 138 + "@atproto/xrpc": "^0.7.7", 139 + "await-lock": "^2.2.2", 140 + "multiformats": "^9.9.0", 141 + "tlds": "^1.234.0", 142 + "zod": "^3.23.8" 143 + } 144 + }, 145 + "node_modules/@atproto/common-web": { 146 + "version": "0.4.14", 147 + "resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.14.tgz", 148 + "integrity": "sha512-rMU8Q+kpyPpirUS9OqT7aOD1hxKa+diem3vc7BA0lOkj0tU6wcAxegxmbPZ8JaOsR7SSYhP/jCt/5wbT4qqkuQ==", 149 + "license": "MIT", 150 + "dependencies": { 151 + "@atproto/lex-data": "0.0.9", 152 + "@atproto/lex-json": "0.0.9", 153 + "@atproto/syntax": "0.4.3", 154 + "zod": "^3.23.8" 155 + } 156 + }, 157 + "node_modules/@atproto/did": { 158 + "version": "0.3.0", 159 + "resolved": "https://registry.npmjs.org/@atproto/did/-/did-0.3.0.tgz", 160 + "integrity": "sha512-raUPzUGegtW/6OxwCmM8bhZvuIMzxG5t9oWsth6Tp91Kb5fTnHV2h/KKNF1C82doeA4BdXCErTyg7ISwLbQkzA==", 161 + "license": "MIT", 162 + "dependencies": { 163 + "zod": "^3.23.8" 164 + } 165 + }, 166 + "node_modules/@atproto/jwk": { 167 + "version": "0.6.0", 168 + "resolved": "https://registry.npmjs.org/@atproto/jwk/-/jwk-0.6.0.tgz", 169 + "integrity": "sha512-bDoJPvt7TrQVi/rBfBrSSpGykhtIriKxeYCYQTiPRKFfyRhbgpElF0wPXADjIswnbzZdOwbY63az4E/CFVT3Tw==", 170 + "license": "MIT", 171 + "dependencies": { 172 + "multiformats": "^9.9.0", 173 + "zod": "^3.23.8" 174 + } 175 + }, 176 + "node_modules/@atproto/jwk-jose": { 177 + "version": "0.1.11", 178 + "resolved": "https://registry.npmjs.org/@atproto/jwk-jose/-/jwk-jose-0.1.11.tgz", 179 + "integrity": "sha512-i4Fnr2sTBYmMmHXl7NJh8GrCH+tDQEVWrcDMDnV5DjJfkgT17wIqvojIw9SNbSL4Uf0OtfEv6AgG0A+mgh8b5Q==", 180 + "license": "MIT", 181 + "dependencies": { 182 + "@atproto/jwk": "0.6.0", 183 + "jose": "^5.2.0" 184 + } 185 + }, 186 + "node_modules/@atproto/jwk-webcrypto": { 187 + "version": "0.2.0", 188 + "resolved": "https://registry.npmjs.org/@atproto/jwk-webcrypto/-/jwk-webcrypto-0.2.0.tgz", 189 + "integrity": "sha512-UmgRrrEAkWvxwhlwe30UmDOdTEFidlIzBC7C3cCbeJMcBN1x8B3KH+crXrsTqfWQBG58mXgt8wgSK3Kxs2LhFg==", 190 + "license": "MIT", 191 + "dependencies": { 192 + "@atproto/jwk": "0.6.0", 193 + "@atproto/jwk-jose": "0.1.11", 194 + "zod": "^3.23.8" 195 + } 196 + }, 197 + "node_modules/@atproto/lex-data": { 198 + "version": "0.0.9", 199 + "resolved": "https://registry.npmjs.org/@atproto/lex-data/-/lex-data-0.0.9.tgz", 200 + "integrity": "sha512-1slwe4sG0cyWtsq16+rBoWIxNDqGPkkvN+PV6JuzA7dgUK9bjUmXBGQU4eZlUPSS43X1Nhmr/9VjgKmEzU9vDw==", 201 + "license": "MIT", 202 + "dependencies": { 203 + "multiformats": "^9.9.0", 204 + "tslib": "^2.8.1", 205 + "uint8arrays": "3.0.0", 206 + "unicode-segmenter": "^0.14.0" 207 + } 208 + }, 209 + "node_modules/@atproto/lex-json": { 210 + "version": "0.0.9", 211 + "resolved": "https://registry.npmjs.org/@atproto/lex-json/-/lex-json-0.0.9.tgz", 212 + "integrity": "sha512-Q2v1EVZcnd+ndyZj1r2UlGikA7q6It24CFPLbxokcf5Ba4RBupH8IkkQX7mqUDSRWPgQdmZYIdW9wUln+MKDqw==", 213 + "license": "MIT", 214 + "dependencies": { 215 + "@atproto/lex-data": "0.0.9", 216 + "tslib": "^2.8.1" 217 + } 218 + }, 219 + "node_modules/@atproto/lexicon": { 220 + "version": "0.6.1", 221 + "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.6.1.tgz", 222 + "integrity": "sha512-/vI1kVlY50Si+5MXpvOucelnYwb0UJ6Qto5mCp+7Q5C+Jtp+SoSykAPVvjVtTnQUH2vrKOFOwpb3C375vSKzXw==", 223 + "license": "MIT", 224 + "dependencies": { 225 + "@atproto/common-web": "^0.4.13", 226 + "@atproto/syntax": "^0.4.3", 227 + "iso-datestring-validator": "^2.2.2", 228 + "multiformats": "^9.9.0", 229 + "zod": "^3.23.8" 230 + } 231 + }, 232 + "node_modules/@atproto/oauth-client": { 233 + "version": "0.5.14", 234 + "resolved": "https://registry.npmjs.org/@atproto/oauth-client/-/oauth-client-0.5.14.tgz", 235 + "integrity": "sha512-sPH+vcdq9maTEAhJI0HzmFcFAMrkCS19np+RUssNkX6kS8Xr3OYr57tvYRCbkcnIyYTfYcxKQgpwHKx3RVEaYw==", 236 + "license": "MIT", 237 + "dependencies": { 238 + "@atproto-labs/did-resolver": "0.2.6", 239 + "@atproto-labs/fetch": "0.2.3", 240 + "@atproto-labs/handle-resolver": "0.3.6", 241 + "@atproto-labs/identity-resolver": "0.3.6", 242 + "@atproto-labs/simple-store": "0.3.0", 243 + "@atproto-labs/simple-store-memory": "0.1.4", 244 + "@atproto/did": "0.3.0", 245 + "@atproto/jwk": "0.6.0", 246 + "@atproto/oauth-types": "0.6.2", 247 + "@atproto/xrpc": "0.7.7", 248 + "core-js": "^3", 249 + "multiformats": "^9.9.0", 250 + "zod": "^3.23.8" 251 + } 252 + }, 253 + "node_modules/@atproto/oauth-client-node": { 254 + "version": "0.3.16", 255 + "resolved": "https://registry.npmjs.org/@atproto/oauth-client-node/-/oauth-client-node-0.3.16.tgz", 256 + "integrity": "sha512-2dooMzxAkiQ4MkOAZlEQ3iwbB9SEovrbIKMNuBbVCLQYORVNxe20tMdjs3lvhrzdpzvaHLlQnJJhw5dA9VELFw==", 257 + "license": "MIT", 258 + "dependencies": { 259 + "@atproto-labs/did-resolver": "0.2.6", 260 + "@atproto-labs/handle-resolver-node": "0.1.25", 261 + "@atproto-labs/simple-store": "0.3.0", 262 + "@atproto/did": "0.3.0", 263 + "@atproto/jwk": "0.6.0", 264 + "@atproto/jwk-jose": "0.1.11", 265 + "@atproto/jwk-webcrypto": "0.2.0", 266 + "@atproto/oauth-client": "0.5.14", 267 + "@atproto/oauth-types": "0.6.2" 268 + }, 269 + "engines": { 270 + "node": ">=18.7.0" 271 + } 272 + }, 273 + "node_modules/@atproto/oauth-types": { 274 + "version": "0.6.2", 275 + "resolved": "https://registry.npmjs.org/@atproto/oauth-types/-/oauth-types-0.6.2.tgz", 276 + "integrity": "sha512-2cuboM4RQBCYR8NQC5uGRkW6KgCgKyq/B5/+tnMmWZYtZGVUQvsUWQHK/ZiMCnVXbcDNtc/RIEJQJDZ8FXMoxg==", 277 + "license": "MIT", 278 + "dependencies": { 279 + "@atproto/did": "0.3.0", 280 + "@atproto/jwk": "0.6.0", 281 + "zod": "^3.23.8" 282 + } 283 + }, 284 + "node_modules/@atproto/syntax": { 285 + "version": "0.4.3", 286 + "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.3.tgz", 287 + "integrity": "sha512-YoZUz40YAJr5nPwvCDWgodEOlt5IftZqPJvA0JDWjuZKD8yXddTwSzXSaKQAzGOpuM+/A3uXRtPzJJqlScc+iA==", 288 + "license": "MIT", 289 + "dependencies": { 290 + "tslib": "^2.8.1" 291 + } 292 + }, 293 + "node_modules/@atproto/xrpc": { 294 + "version": "0.7.7", 295 + "resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.7.tgz", 296 + "integrity": "sha512-K1ZyO/BU8JNtXX5dmPp7b5UrkLMMqpsIa/Lrj5D3Su+j1Xwq1m6QJ2XJ1AgjEjkI1v4Muzm7klianLE6XGxtmA==", 297 + "license": "MIT", 298 + "dependencies": { 299 + "@atproto/lexicon": "^0.6.0", 300 + "zod": "^3.23.8" 301 + } 302 + }, 303 + "node_modules/@libsql/client": { 304 + "version": "0.17.0", 305 + "resolved": "https://registry.npmjs.org/@libsql/client/-/client-0.17.0.tgz", 306 + "integrity": "sha512-TLjSU9Otdpq0SpKHl1tD1Nc9MKhrsZbCFGot3EbCxRa8m1E5R1mMwoOjKMMM31IyF7fr+hPNHLpYfwbMKNusmg==", 307 + "license": "MIT", 308 + "dependencies": { 309 + "@libsql/core": "^0.17.0", 310 + "@libsql/hrana-client": "^0.9.0", 311 + "js-base64": "^3.7.5", 312 + "libsql": "^0.5.22", 313 + "promise-limit": "^2.7.0" 314 + } 315 + }, 316 + "node_modules/@libsql/core": { 317 + "version": "0.17.0", 318 + "resolved": "https://registry.npmjs.org/@libsql/core/-/core-0.17.0.tgz", 319 + "integrity": "sha512-hnZRnJHiS+nrhHKLGYPoJbc78FE903MSDrFJTbftxo+e52X+E0Y0fHOCVYsKWcg6XgB7BbJYUrz/xEkVTSaipw==", 320 + "license": "MIT", 321 + "dependencies": { 322 + "js-base64": "^3.7.5" 323 + } 324 + }, 325 + "node_modules/@libsql/darwin-arm64": { 326 + "version": "0.5.22", 327 + "resolved": "https://registry.npmjs.org/@libsql/darwin-arm64/-/darwin-arm64-0.5.22.tgz", 328 + "integrity": "sha512-4B8ZlX3nIDPndfct7GNe0nI3Yw6ibocEicWdC4fvQbSs/jdq/RC2oCsoJxJ4NzXkvktX70C1J4FcmmoBy069UA==", 329 + "cpu": [ 330 + "arm64" 331 + ], 332 + "license": "MIT", 333 + "optional": true, 334 + "os": [ 335 + "darwin" 336 + ] 337 + }, 338 + "node_modules/@libsql/darwin-x64": { 339 + "version": "0.5.22", 340 + "resolved": "https://registry.npmjs.org/@libsql/darwin-x64/-/darwin-x64-0.5.22.tgz", 341 + "integrity": "sha512-ny2HYWt6lFSIdNFzUFIJ04uiW6finXfMNJ7wypkAD8Pqdm6nAByO+Fdqu8t7sD0sqJGeUCiOg480icjyQ2/8VA==", 342 + "cpu": [ 343 + "x64" 344 + ], 345 + "license": "MIT", 346 + "optional": true, 347 + "os": [ 348 + "darwin" 349 + ] 350 + }, 351 + "node_modules/@libsql/hrana-client": { 352 + "version": "0.9.0", 353 + "resolved": "https://registry.npmjs.org/@libsql/hrana-client/-/hrana-client-0.9.0.tgz", 354 + "integrity": "sha512-pxQ1986AuWfPX4oXzBvLwBnfgKDE5OMhAdR/5cZmRaB4Ygz5MecQybvwZupnRz341r2CtFmbk/BhSu7k2Lm+Jw==", 355 + "license": "MIT", 356 + "dependencies": { 357 + "@libsql/isomorphic-ws": "^0.1.5", 358 + "cross-fetch": "^4.0.0", 359 + "js-base64": "^3.7.5", 360 + "node-fetch": "^3.3.2" 361 + } 362 + }, 363 + "node_modules/@libsql/isomorphic-ws": { 364 + "version": "0.1.5", 365 + "resolved": "https://registry.npmjs.org/@libsql/isomorphic-ws/-/isomorphic-ws-0.1.5.tgz", 366 + "integrity": "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==", 367 + "license": "MIT", 368 + "dependencies": { 369 + "@types/ws": "^8.5.4", 370 + "ws": "^8.13.0" 371 + } 372 + }, 373 + "node_modules/@libsql/linux-arm-gnueabihf": { 374 + "version": "0.5.22", 375 + "resolved": "https://registry.npmjs.org/@libsql/linux-arm-gnueabihf/-/linux-arm-gnueabihf-0.5.22.tgz", 376 + "integrity": "sha512-3Uo3SoDPJe/zBnyZKosziRGtszXaEtv57raWrZIahtQDsjxBVjuzYQinCm9LRCJCUT5t2r5Z5nLDPJi2CwZVoA==", 377 + "cpu": [ 378 + "arm" 379 + ], 380 + "license": "MIT", 381 + "optional": true, 382 + "os": [ 383 + "linux" 384 + ] 385 + }, 386 + "node_modules/@libsql/linux-arm-musleabihf": { 387 + "version": "0.5.22", 388 + "resolved": "https://registry.npmjs.org/@libsql/linux-arm-musleabihf/-/linux-arm-musleabihf-0.5.22.tgz", 389 + "integrity": "sha512-LCsXh07jvSojTNJptT9CowOzwITznD+YFGGW+1XxUr7fS+7/ydUrpDfsMX7UqTqjm7xG17eq86VkWJgHJfvpNg==", 390 + "cpu": [ 391 + "arm" 392 + ], 393 + "license": "MIT", 394 + "optional": true, 395 + "os": [ 396 + "linux" 397 + ] 398 + }, 399 + "node_modules/@libsql/linux-arm64-gnu": { 400 + "version": "0.5.22", 401 + "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-gnu/-/linux-arm64-gnu-0.5.22.tgz", 402 + "integrity": "sha512-KSdnOMy88c9mpOFKUEzPskSaF3VLflfSUCBwas/pn1/sV3pEhtMF6H8VUCd2rsedwoukeeCSEONqX7LLnQwRMA==", 403 + "cpu": [ 404 + "arm64" 405 + ], 406 + "license": "MIT", 407 + "optional": true, 408 + "os": [ 409 + "linux" 410 + ] 411 + }, 412 + "node_modules/@libsql/linux-arm64-musl": { 413 + "version": "0.5.22", 414 + "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-musl/-/linux-arm64-musl-0.5.22.tgz", 415 + "integrity": "sha512-mCHSMAsDTLK5YH//lcV3eFEgiR23Ym0U9oEvgZA0667gqRZg/2px+7LshDvErEKv2XZ8ixzw3p1IrBzLQHGSsw==", 416 + "cpu": [ 417 + "arm64" 418 + ], 419 + "license": "MIT", 420 + "optional": true, 421 + "os": [ 422 + "linux" 423 + ] 424 + }, 425 + "node_modules/@libsql/linux-x64-gnu": { 426 + "version": "0.5.22", 427 + "resolved": "https://registry.npmjs.org/@libsql/linux-x64-gnu/-/linux-x64-gnu-0.5.22.tgz", 428 + "integrity": "sha512-kNBHaIkSg78Y4BqAdgjcR2mBilZXs4HYkAmi58J+4GRwDQZh5fIUWbnQvB9f95DkWUIGVeenqLRFY2pcTmlsew==", 429 + "cpu": [ 430 + "x64" 431 + ], 432 + "license": "MIT", 433 + "optional": true, 434 + "os": [ 435 + "linux" 436 + ] 437 + }, 438 + "node_modules/@libsql/linux-x64-musl": { 439 + "version": "0.5.22", 440 + "resolved": "https://registry.npmjs.org/@libsql/linux-x64-musl/-/linux-x64-musl-0.5.22.tgz", 441 + "integrity": "sha512-UZ4Xdxm4pu3pQXjvfJiyCzZop/9j/eA2JjmhMaAhe3EVLH2g11Fy4fwyUp9sT1QJYR1kpc2JLuybPM0kuXv/Tg==", 442 + "cpu": [ 443 + "x64" 444 + ], 445 + "license": "MIT", 446 + "optional": true, 447 + "os": [ 448 + "linux" 449 + ] 450 + }, 451 + "node_modules/@libsql/win32-x64-msvc": { 452 + "version": "0.5.22", 453 + "resolved": "https://registry.npmjs.org/@libsql/win32-x64-msvc/-/win32-x64-msvc-0.5.22.tgz", 454 + "integrity": "sha512-Fj0j8RnBpo43tVZUVoNK6BV/9AtDUM5S7DF3LB4qTYg1LMSZqi3yeCneUTLJD6XomQJlZzbI4mst89yspVSAnA==", 455 + "cpu": [ 456 + "x64" 457 + ], 458 + "license": "MIT", 459 + "optional": true, 460 + "os": [ 461 + "win32" 462 + ] 463 + }, 464 + "node_modules/@neon-rs/load": { 465 + "version": "0.0.4", 466 + "resolved": "https://registry.npmjs.org/@neon-rs/load/-/load-0.0.4.tgz", 467 + "integrity": "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==", 468 + "license": "MIT" 469 + }, 470 + "node_modules/@types/node": { 471 + "version": "25.1.0", 472 + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.1.0.tgz", 473 + "integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==", 474 + "license": "MIT", 475 + "dependencies": { 476 + "undici-types": "~7.16.0" 477 + } 478 + }, 479 + "node_modules/@types/ws": { 480 + "version": "8.18.1", 481 + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", 482 + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", 483 + "license": "MIT", 484 + "dependencies": { 485 + "@types/node": "*" 486 + } 487 + }, 488 + "node_modules/accepts": { 489 + "version": "2.0.0", 490 + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", 491 + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", 492 + "license": "MIT", 493 + "dependencies": { 494 + "mime-types": "^3.0.0", 495 + "negotiator": "^1.0.0" 496 + }, 497 + "engines": { 498 + "node": ">= 0.6" 499 + } 500 + }, 501 + "node_modules/anymatch": { 502 + "version": "3.1.3", 503 + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 504 + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 505 + "dev": true, 506 + "license": "ISC", 507 + "dependencies": { 508 + "normalize-path": "^3.0.0", 509 + "picomatch": "^2.0.4" 510 + }, 511 + "engines": { 512 + "node": ">= 8" 513 + } 514 + }, 515 + "node_modules/async": { 516 + "version": "3.2.6", 517 + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", 518 + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", 519 + "license": "MIT" 520 + }, 521 + "node_modules/await-lock": { 522 + "version": "2.2.2", 523 + "resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz", 524 + "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==", 525 + "license": "MIT" 526 + }, 527 + "node_modules/balanced-match": { 528 + "version": "1.0.2", 529 + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 530 + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 531 + "license": "MIT" 532 + }, 533 + "node_modules/binary-extensions": { 534 + "version": "2.3.0", 535 + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 536 + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 537 + "dev": true, 538 + "license": "MIT", 539 + "engines": { 540 + "node": ">=8" 541 + }, 542 + "funding": { 543 + "url": "https://github.com/sponsors/sindresorhus" 544 + } 545 + }, 546 + "node_modules/body-parser": { 547 + "version": "2.2.2", 548 + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", 549 + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", 550 + "license": "MIT", 551 + "dependencies": { 552 + "bytes": "^3.1.2", 553 + "content-type": "^1.0.5", 554 + "debug": "^4.4.3", 555 + "http-errors": "^2.0.0", 556 + "iconv-lite": "^0.7.0", 557 + "on-finished": "^2.4.1", 558 + "qs": "^6.14.1", 559 + "raw-body": "^3.0.1", 560 + "type-is": "^2.0.1" 561 + }, 562 + "engines": { 563 + "node": ">=18" 564 + }, 565 + "funding": { 566 + "type": "opencollective", 567 + "url": "https://opencollective.com/express" 568 + } 569 + }, 570 + "node_modules/brace-expansion": { 571 + "version": "2.0.2", 572 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", 573 + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", 574 + "license": "MIT", 575 + "dependencies": { 576 + "balanced-match": "^1.0.0" 577 + } 578 + }, 579 + "node_modules/braces": { 580 + "version": "3.0.3", 581 + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 582 + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 583 + "dev": true, 584 + "license": "MIT", 585 + "dependencies": { 586 + "fill-range": "^7.1.1" 587 + }, 588 + "engines": { 589 + "node": ">=8" 590 + } 591 + }, 592 + "node_modules/bytes": { 593 + "version": "3.1.2", 594 + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 595 + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 596 + "license": "MIT", 597 + "engines": { 598 + "node": ">= 0.8" 599 + } 600 + }, 601 + "node_modules/call-bind-apply-helpers": { 602 + "version": "1.0.2", 603 + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", 604 + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", 605 + "license": "MIT", 606 + "dependencies": { 607 + "es-errors": "^1.3.0", 608 + "function-bind": "^1.1.2" 609 + }, 610 + "engines": { 611 + "node": ">= 0.4" 612 + } 613 + }, 614 + "node_modules/call-bound": { 615 + "version": "1.0.4", 616 + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", 617 + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", 618 + "license": "MIT", 619 + "dependencies": { 620 + "call-bind-apply-helpers": "^1.0.2", 621 + "get-intrinsic": "^1.3.0" 622 + }, 623 + "engines": { 624 + "node": ">= 0.4" 625 + }, 626 + "funding": { 627 + "url": "https://github.com/sponsors/ljharb" 628 + } 629 + }, 630 + "node_modules/chokidar": { 631 + "version": "3.6.0", 632 + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 633 + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 634 + "dev": true, 635 + "license": "MIT", 636 + "dependencies": { 637 + "anymatch": "~3.1.2", 638 + "braces": "~3.0.2", 639 + "glob-parent": "~5.1.2", 640 + "is-binary-path": "~2.1.0", 641 + "is-glob": "~4.0.1", 642 + "normalize-path": "~3.0.0", 643 + "readdirp": "~3.6.0" 644 + }, 645 + "engines": { 646 + "node": ">= 8.10.0" 647 + }, 648 + "funding": { 649 + "url": "https://paulmillr.com/funding/" 650 + }, 651 + "optionalDependencies": { 652 + "fsevents": "~2.3.2" 653 + } 654 + }, 655 + "node_modules/concat-map": { 656 + "version": "0.0.1", 657 + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 658 + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 659 + "dev": true, 660 + "license": "MIT" 661 + }, 662 + "node_modules/content-disposition": { 663 + "version": "1.0.1", 664 + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", 665 + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", 666 + "license": "MIT", 667 + "engines": { 668 + "node": ">=18" 669 + }, 670 + "funding": { 671 + "type": "opencollective", 672 + "url": "https://opencollective.com/express" 673 + } 674 + }, 675 + "node_modules/content-type": { 676 + "version": "1.0.5", 677 + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 678 + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 679 + "license": "MIT", 680 + "engines": { 681 + "node": ">= 0.6" 682 + } 683 + }, 684 + "node_modules/cookie": { 685 + "version": "0.7.2", 686 + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", 687 + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", 688 + "license": "MIT", 689 + "engines": { 690 + "node": ">= 0.6" 691 + } 692 + }, 693 + "node_modules/cookie-signature": { 694 + "version": "1.2.2", 695 + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", 696 + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", 697 + "license": "MIT", 698 + "engines": { 699 + "node": ">=6.6.0" 700 + } 701 + }, 702 + "node_modules/core-js": { 703 + "version": "3.48.0", 704 + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", 705 + "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", 706 + "hasInstallScript": true, 707 + "license": "MIT", 708 + "funding": { 709 + "type": "opencollective", 710 + "url": "https://opencollective.com/core-js" 711 + } 712 + }, 713 + "node_modules/cross-fetch": { 714 + "version": "4.1.0", 715 + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", 716 + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", 717 + "license": "MIT", 718 + "dependencies": { 719 + "node-fetch": "^2.7.0" 720 + } 721 + }, 722 + "node_modules/cross-fetch/node_modules/node-fetch": { 723 + "version": "2.7.0", 724 + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", 725 + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", 726 + "license": "MIT", 727 + "dependencies": { 728 + "whatwg-url": "^5.0.0" 729 + }, 730 + "engines": { 731 + "node": "4.x || >=6.0.0" 732 + }, 733 + "peerDependencies": { 734 + "encoding": "^0.1.0" 735 + }, 736 + "peerDependenciesMeta": { 737 + "encoding": { 738 + "optional": true 739 + } 740 + } 741 + }, 742 + "node_modules/data-uri-to-buffer": { 743 + "version": "4.0.1", 744 + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", 745 + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", 746 + "license": "MIT", 747 + "engines": { 748 + "node": ">= 12" 749 + } 750 + }, 751 + "node_modules/debug": { 752 + "version": "4.4.3", 753 + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", 754 + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", 755 + "license": "MIT", 756 + "dependencies": { 757 + "ms": "^2.1.3" 758 + }, 759 + "engines": { 760 + "node": ">=6.0" 761 + }, 762 + "peerDependenciesMeta": { 763 + "supports-color": { 764 + "optional": true 765 + } 766 + } 767 + }, 768 + "node_modules/depd": { 769 + "version": "2.0.0", 770 + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 771 + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 772 + "license": "MIT", 773 + "engines": { 774 + "node": ">= 0.8" 775 + } 776 + }, 777 + "node_modules/detect-libc": { 778 + "version": "2.0.2", 779 + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", 780 + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", 781 + "license": "Apache-2.0", 782 + "engines": { 783 + "node": ">=8" 784 + } 785 + }, 786 + "node_modules/dotenv": { 787 + "version": "17.2.3", 788 + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", 789 + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", 790 + "license": "BSD-2-Clause", 791 + "engines": { 792 + "node": ">=12" 793 + }, 794 + "funding": { 795 + "url": "https://dotenvx.com" 796 + } 797 + }, 798 + "node_modules/dunder-proto": { 799 + "version": "1.0.1", 800 + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", 801 + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", 802 + "license": "MIT", 803 + "dependencies": { 804 + "call-bind-apply-helpers": "^1.0.1", 805 + "es-errors": "^1.3.0", 806 + "gopd": "^1.2.0" 807 + }, 808 + "engines": { 809 + "node": ">= 0.4" 810 + } 811 + }, 812 + "node_modules/ee-first": { 813 + "version": "1.1.1", 814 + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 815 + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", 816 + "license": "MIT" 817 + }, 818 + "node_modules/ejs": { 819 + "version": "4.0.1", 820 + "resolved": "https://registry.npmjs.org/ejs/-/ejs-4.0.1.tgz", 821 + "integrity": "sha512-krvQtxc0btwSm/nvnt1UpnaFDFVJpJ0fdckmALpCgShsr/iGYHTnJiUliZTgmzq/UxTX33TtOQVKaNigMQp/6Q==", 822 + "license": "Apache-2.0", 823 + "dependencies": { 824 + "jake": "^10.9.1" 825 + }, 826 + "bin": { 827 + "ejs": "bin/cli.js" 828 + }, 829 + "engines": { 830 + "node": ">=0.12.18" 831 + } 832 + }, 833 + "node_modules/encodeurl": { 834 + "version": "2.0.0", 835 + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 836 + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", 837 + "license": "MIT", 838 + "engines": { 839 + "node": ">= 0.8" 840 + } 841 + }, 842 + "node_modules/es-define-property": { 843 + "version": "1.0.1", 844 + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", 845 + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", 846 + "license": "MIT", 847 + "engines": { 848 + "node": ">= 0.4" 849 + } 850 + }, 851 + "node_modules/es-errors": { 852 + "version": "1.3.0", 853 + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 854 + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 855 + "license": "MIT", 856 + "engines": { 857 + "node": ">= 0.4" 858 + } 859 + }, 860 + "node_modules/es-object-atoms": { 861 + "version": "1.1.1", 862 + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", 863 + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", 864 + "license": "MIT", 865 + "dependencies": { 866 + "es-errors": "^1.3.0" 867 + }, 868 + "engines": { 869 + "node": ">= 0.4" 870 + } 871 + }, 872 + "node_modules/escape-html": { 873 + "version": "1.0.3", 874 + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 875 + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", 876 + "license": "MIT" 877 + }, 878 + "node_modules/etag": { 879 + "version": "1.8.1", 880 + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 881 + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 882 + "license": "MIT", 883 + "engines": { 884 + "node": ">= 0.6" 885 + } 886 + }, 887 + "node_modules/express": { 888 + "version": "5.2.1", 889 + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", 890 + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", 891 + "license": "MIT", 892 + "dependencies": { 893 + "accepts": "^2.0.0", 894 + "body-parser": "^2.2.1", 895 + "content-disposition": "^1.0.0", 896 + "content-type": "^1.0.5", 897 + "cookie": "^0.7.1", 898 + "cookie-signature": "^1.2.1", 899 + "debug": "^4.4.0", 900 + "depd": "^2.0.0", 901 + "encodeurl": "^2.0.0", 902 + "escape-html": "^1.0.3", 903 + "etag": "^1.8.1", 904 + "finalhandler": "^2.1.0", 905 + "fresh": "^2.0.0", 906 + "http-errors": "^2.0.0", 907 + "merge-descriptors": "^2.0.0", 908 + "mime-types": "^3.0.0", 909 + "on-finished": "^2.4.1", 910 + "once": "^1.4.0", 911 + "parseurl": "^1.3.3", 912 + "proxy-addr": "^2.0.7", 913 + "qs": "^6.14.0", 914 + "range-parser": "^1.2.1", 915 + "router": "^2.2.0", 916 + "send": "^1.1.0", 917 + "serve-static": "^2.2.0", 918 + "statuses": "^2.0.1", 919 + "type-is": "^2.0.1", 920 + "vary": "^1.1.2" 921 + }, 922 + "engines": { 923 + "node": ">= 18" 924 + }, 925 + "funding": { 926 + "type": "opencollective", 927 + "url": "https://opencollective.com/express" 928 + } 929 + }, 930 + "node_modules/express-session": { 931 + "version": "1.19.0", 932 + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.19.0.tgz", 933 + "integrity": "sha512-0csaMkGq+vaiZTmSMMGkfdCOabYv192VbytFypcvI0MANrp+4i/7yEkJ0sbAEhycQjntaKGzYfjfXQyVb7BHMA==", 934 + "license": "MIT", 935 + "dependencies": { 936 + "cookie": "~0.7.2", 937 + "cookie-signature": "~1.0.7", 938 + "debug": "~2.6.9", 939 + "depd": "~2.0.0", 940 + "on-headers": "~1.1.0", 941 + "parseurl": "~1.3.3", 942 + "safe-buffer": "~5.2.1", 943 + "uid-safe": "~2.1.5" 944 + }, 945 + "engines": { 946 + "node": ">= 0.8.0" 947 + }, 948 + "funding": { 949 + "type": "opencollective", 950 + "url": "https://opencollective.com/express" 951 + } 952 + }, 953 + "node_modules/express-session/node_modules/cookie-signature": { 954 + "version": "1.0.7", 955 + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", 956 + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", 957 + "license": "MIT" 958 + }, 959 + "node_modules/express-session/node_modules/debug": { 960 + "version": "2.6.9", 961 + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 962 + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 963 + "license": "MIT", 964 + "dependencies": { 965 + "ms": "2.0.0" 966 + } 967 + }, 968 + "node_modules/express-session/node_modules/ms": { 969 + "version": "2.0.0", 970 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 971 + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 972 + "license": "MIT" 973 + }, 974 + "node_modules/fetch-blob": { 975 + "version": "3.2.0", 976 + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", 977 + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", 978 + "funding": [ 979 + { 980 + "type": "github", 981 + "url": "https://github.com/sponsors/jimmywarting" 982 + }, 983 + { 984 + "type": "paypal", 985 + "url": "https://paypal.me/jimmywarting" 986 + } 987 + ], 988 + "license": "MIT", 989 + "dependencies": { 990 + "node-domexception": "^1.0.0", 991 + "web-streams-polyfill": "^3.0.3" 992 + }, 993 + "engines": { 994 + "node": "^12.20 || >= 14.13" 995 + } 996 + }, 997 + "node_modules/filelist": { 998 + "version": "1.0.4", 999 + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", 1000 + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", 1001 + "license": "Apache-2.0", 1002 + "dependencies": { 1003 + "minimatch": "^5.0.1" 1004 + } 1005 + }, 1006 + "node_modules/fill-range": { 1007 + "version": "7.1.1", 1008 + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 1009 + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 1010 + "dev": true, 1011 + "license": "MIT", 1012 + "dependencies": { 1013 + "to-regex-range": "^5.0.1" 1014 + }, 1015 + "engines": { 1016 + "node": ">=8" 1017 + } 1018 + }, 1019 + "node_modules/finalhandler": { 1020 + "version": "2.1.1", 1021 + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", 1022 + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", 1023 + "license": "MIT", 1024 + "dependencies": { 1025 + "debug": "^4.4.0", 1026 + "encodeurl": "^2.0.0", 1027 + "escape-html": "^1.0.3", 1028 + "on-finished": "^2.4.1", 1029 + "parseurl": "^1.3.3", 1030 + "statuses": "^2.0.1" 1031 + }, 1032 + "engines": { 1033 + "node": ">= 18.0.0" 1034 + }, 1035 + "funding": { 1036 + "type": "opencollective", 1037 + "url": "https://opencollective.com/express" 1038 + } 1039 + }, 1040 + "node_modules/formdata-polyfill": { 1041 + "version": "4.0.10", 1042 + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", 1043 + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", 1044 + "license": "MIT", 1045 + "dependencies": { 1046 + "fetch-blob": "^3.1.2" 1047 + }, 1048 + "engines": { 1049 + "node": ">=12.20.0" 1050 + } 1051 + }, 1052 + "node_modules/forwarded": { 1053 + "version": "0.2.0", 1054 + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 1055 + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 1056 + "license": "MIT", 1057 + "engines": { 1058 + "node": ">= 0.6" 1059 + } 1060 + }, 1061 + "node_modules/fresh": { 1062 + "version": "2.0.0", 1063 + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", 1064 + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", 1065 + "license": "MIT", 1066 + "engines": { 1067 + "node": ">= 0.8" 1068 + } 1069 + }, 1070 + "node_modules/fsevents": { 1071 + "version": "2.3.3", 1072 + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1073 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1074 + "dev": true, 1075 + "hasInstallScript": true, 1076 + "license": "MIT", 1077 + "optional": true, 1078 + "os": [ 1079 + "darwin" 1080 + ], 1081 + "engines": { 1082 + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1083 + } 1084 + }, 1085 + "node_modules/function-bind": { 1086 + "version": "1.1.2", 1087 + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 1088 + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 1089 + "license": "MIT", 1090 + "funding": { 1091 + "url": "https://github.com/sponsors/ljharb" 1092 + } 1093 + }, 1094 + "node_modules/get-intrinsic": { 1095 + "version": "1.3.0", 1096 + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", 1097 + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", 1098 + "license": "MIT", 1099 + "dependencies": { 1100 + "call-bind-apply-helpers": "^1.0.2", 1101 + "es-define-property": "^1.0.1", 1102 + "es-errors": "^1.3.0", 1103 + "es-object-atoms": "^1.1.1", 1104 + "function-bind": "^1.1.2", 1105 + "get-proto": "^1.0.1", 1106 + "gopd": "^1.2.0", 1107 + "has-symbols": "^1.1.0", 1108 + "hasown": "^2.0.2", 1109 + "math-intrinsics": "^1.1.0" 1110 + }, 1111 + "engines": { 1112 + "node": ">= 0.4" 1113 + }, 1114 + "funding": { 1115 + "url": "https://github.com/sponsors/ljharb" 1116 + } 1117 + }, 1118 + "node_modules/get-proto": { 1119 + "version": "1.0.1", 1120 + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", 1121 + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", 1122 + "license": "MIT", 1123 + "dependencies": { 1124 + "dunder-proto": "^1.0.1", 1125 + "es-object-atoms": "^1.0.0" 1126 + }, 1127 + "engines": { 1128 + "node": ">= 0.4" 1129 + } 1130 + }, 1131 + "node_modules/glob-parent": { 1132 + "version": "5.1.2", 1133 + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1134 + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1135 + "dev": true, 1136 + "license": "ISC", 1137 + "dependencies": { 1138 + "is-glob": "^4.0.1" 1139 + }, 1140 + "engines": { 1141 + "node": ">= 6" 1142 + } 1143 + }, 1144 + "node_modules/gopd": { 1145 + "version": "1.2.0", 1146 + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", 1147 + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", 1148 + "license": "MIT", 1149 + "engines": { 1150 + "node": ">= 0.4" 1151 + }, 1152 + "funding": { 1153 + "url": "https://github.com/sponsors/ljharb" 1154 + } 1155 + }, 1156 + "node_modules/has-flag": { 1157 + "version": "3.0.0", 1158 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1159 + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 1160 + "dev": true, 1161 + "license": "MIT", 1162 + "engines": { 1163 + "node": ">=4" 1164 + } 1165 + }, 1166 + "node_modules/has-symbols": { 1167 + "version": "1.1.0", 1168 + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", 1169 + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", 1170 + "license": "MIT", 1171 + "engines": { 1172 + "node": ">= 0.4" 1173 + }, 1174 + "funding": { 1175 + "url": "https://github.com/sponsors/ljharb" 1176 + } 1177 + }, 1178 + "node_modules/hasown": { 1179 + "version": "2.0.2", 1180 + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 1181 + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 1182 + "license": "MIT", 1183 + "dependencies": { 1184 + "function-bind": "^1.1.2" 1185 + }, 1186 + "engines": { 1187 + "node": ">= 0.4" 1188 + } 1189 + }, 1190 + "node_modules/http-errors": { 1191 + "version": "2.0.1", 1192 + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", 1193 + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", 1194 + "license": "MIT", 1195 + "dependencies": { 1196 + "depd": "~2.0.0", 1197 + "inherits": "~2.0.4", 1198 + "setprototypeof": "~1.2.0", 1199 + "statuses": "~2.0.2", 1200 + "toidentifier": "~1.0.1" 1201 + }, 1202 + "engines": { 1203 + "node": ">= 0.8" 1204 + }, 1205 + "funding": { 1206 + "type": "opencollective", 1207 + "url": "https://opencollective.com/express" 1208 + } 1209 + }, 1210 + "node_modules/iconv-lite": { 1211 + "version": "0.7.2", 1212 + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", 1213 + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", 1214 + "license": "MIT", 1215 + "dependencies": { 1216 + "safer-buffer": ">= 2.1.2 < 3.0.0" 1217 + }, 1218 + "engines": { 1219 + "node": ">=0.10.0" 1220 + }, 1221 + "funding": { 1222 + "type": "opencollective", 1223 + "url": "https://opencollective.com/express" 1224 + } 1225 + }, 1226 + "node_modules/ignore-by-default": { 1227 + "version": "1.0.1", 1228 + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 1229 + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", 1230 + "dev": true, 1231 + "license": "ISC" 1232 + }, 1233 + "node_modules/inherits": { 1234 + "version": "2.0.4", 1235 + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1236 + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1237 + "license": "ISC" 1238 + }, 1239 + "node_modules/ipaddr.js": { 1240 + "version": "1.9.1", 1241 + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 1242 + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 1243 + "license": "MIT", 1244 + "engines": { 1245 + "node": ">= 0.10" 1246 + } 1247 + }, 1248 + "node_modules/is-binary-path": { 1249 + "version": "2.1.0", 1250 + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1251 + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1252 + "dev": true, 1253 + "license": "MIT", 1254 + "dependencies": { 1255 + "binary-extensions": "^2.0.0" 1256 + }, 1257 + "engines": { 1258 + "node": ">=8" 1259 + } 1260 + }, 1261 + "node_modules/is-extglob": { 1262 + "version": "2.1.1", 1263 + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1264 + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1265 + "dev": true, 1266 + "license": "MIT", 1267 + "engines": { 1268 + "node": ">=0.10.0" 1269 + } 1270 + }, 1271 + "node_modules/is-glob": { 1272 + "version": "4.0.3", 1273 + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1274 + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1275 + "dev": true, 1276 + "license": "MIT", 1277 + "dependencies": { 1278 + "is-extglob": "^2.1.1" 1279 + }, 1280 + "engines": { 1281 + "node": ">=0.10.0" 1282 + } 1283 + }, 1284 + "node_modules/is-number": { 1285 + "version": "7.0.0", 1286 + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1287 + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1288 + "dev": true, 1289 + "license": "MIT", 1290 + "engines": { 1291 + "node": ">=0.12.0" 1292 + } 1293 + }, 1294 + "node_modules/is-promise": { 1295 + "version": "4.0.0", 1296 + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", 1297 + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", 1298 + "license": "MIT" 1299 + }, 1300 + "node_modules/iso-datestring-validator": { 1301 + "version": "2.2.2", 1302 + "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", 1303 + "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==", 1304 + "license": "MIT" 1305 + }, 1306 + "node_modules/jake": { 1307 + "version": "10.9.4", 1308 + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", 1309 + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", 1310 + "license": "Apache-2.0", 1311 + "dependencies": { 1312 + "async": "^3.2.6", 1313 + "filelist": "^1.0.4", 1314 + "picocolors": "^1.1.1" 1315 + }, 1316 + "bin": { 1317 + "jake": "bin/cli.js" 1318 + }, 1319 + "engines": { 1320 + "node": ">=10" 1321 + } 1322 + }, 1323 + "node_modules/jose": { 1324 + "version": "5.10.0", 1325 + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", 1326 + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", 1327 + "license": "MIT", 1328 + "funding": { 1329 + "url": "https://github.com/sponsors/panva" 1330 + } 1331 + }, 1332 + "node_modules/js-base64": { 1333 + "version": "3.7.8", 1334 + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", 1335 + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", 1336 + "license": "BSD-3-Clause" 1337 + }, 1338 + "node_modules/libsql": { 1339 + "version": "0.5.22", 1340 + "resolved": "https://registry.npmjs.org/libsql/-/libsql-0.5.22.tgz", 1341 + "integrity": "sha512-NscWthMQt7fpU8lqd7LXMvT9pi+KhhmTHAJWUB/Lj6MWa0MKFv0F2V4C6WKKpjCVZl0VwcDz4nOI3CyaT1DDiA==", 1342 + "cpu": [ 1343 + "x64", 1344 + "arm64", 1345 + "wasm32", 1346 + "arm" 1347 + ], 1348 + "license": "MIT", 1349 + "os": [ 1350 + "darwin", 1351 + "linux", 1352 + "win32" 1353 + ], 1354 + "dependencies": { 1355 + "@neon-rs/load": "^0.0.4", 1356 + "detect-libc": "2.0.2" 1357 + }, 1358 + "optionalDependencies": { 1359 + "@libsql/darwin-arm64": "0.5.22", 1360 + "@libsql/darwin-x64": "0.5.22", 1361 + "@libsql/linux-arm-gnueabihf": "0.5.22", 1362 + "@libsql/linux-arm-musleabihf": "0.5.22", 1363 + "@libsql/linux-arm64-gnu": "0.5.22", 1364 + "@libsql/linux-arm64-musl": "0.5.22", 1365 + "@libsql/linux-x64-gnu": "0.5.22", 1366 + "@libsql/linux-x64-musl": "0.5.22", 1367 + "@libsql/win32-x64-msvc": "0.5.22" 1368 + } 1369 + }, 1370 + "node_modules/lru-cache": { 1371 + "version": "10.4.3", 1372 + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", 1373 + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", 1374 + "license": "ISC" 1375 + }, 1376 + "node_modules/math-intrinsics": { 1377 + "version": "1.1.0", 1378 + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", 1379 + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", 1380 + "license": "MIT", 1381 + "engines": { 1382 + "node": ">= 0.4" 1383 + } 1384 + }, 1385 + "node_modules/media-typer": { 1386 + "version": "1.1.0", 1387 + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", 1388 + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", 1389 + "license": "MIT", 1390 + "engines": { 1391 + "node": ">= 0.8" 1392 + } 1393 + }, 1394 + "node_modules/merge-descriptors": { 1395 + "version": "2.0.0", 1396 + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", 1397 + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", 1398 + "license": "MIT", 1399 + "engines": { 1400 + "node": ">=18" 1401 + }, 1402 + "funding": { 1403 + "url": "https://github.com/sponsors/sindresorhus" 1404 + } 1405 + }, 1406 + "node_modules/mime-db": { 1407 + "version": "1.54.0", 1408 + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", 1409 + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", 1410 + "license": "MIT", 1411 + "engines": { 1412 + "node": ">= 0.6" 1413 + } 1414 + }, 1415 + "node_modules/mime-types": { 1416 + "version": "3.0.2", 1417 + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", 1418 + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", 1419 + "license": "MIT", 1420 + "dependencies": { 1421 + "mime-db": "^1.54.0" 1422 + }, 1423 + "engines": { 1424 + "node": ">=18" 1425 + }, 1426 + "funding": { 1427 + "type": "opencollective", 1428 + "url": "https://opencollective.com/express" 1429 + } 1430 + }, 1431 + "node_modules/minimatch": { 1432 + "version": "5.1.6", 1433 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", 1434 + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", 1435 + "license": "ISC", 1436 + "dependencies": { 1437 + "brace-expansion": "^2.0.1" 1438 + }, 1439 + "engines": { 1440 + "node": ">=10" 1441 + } 1442 + }, 1443 + "node_modules/ms": { 1444 + "version": "2.1.3", 1445 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1446 + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1447 + "license": "MIT" 1448 + }, 1449 + "node_modules/multiformats": { 1450 + "version": "9.9.0", 1451 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", 1452 + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", 1453 + "license": "(Apache-2.0 AND MIT)" 1454 + }, 1455 + "node_modules/negotiator": { 1456 + "version": "1.0.0", 1457 + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", 1458 + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", 1459 + "license": "MIT", 1460 + "engines": { 1461 + "node": ">= 0.6" 1462 + } 1463 + }, 1464 + "node_modules/node-domexception": { 1465 + "version": "1.0.0", 1466 + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", 1467 + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", 1468 + "deprecated": "Use your platform's native DOMException instead", 1469 + "funding": [ 1470 + { 1471 + "type": "github", 1472 + "url": "https://github.com/sponsors/jimmywarting" 1473 + }, 1474 + { 1475 + "type": "github", 1476 + "url": "https://paypal.me/jimmywarting" 1477 + } 1478 + ], 1479 + "license": "MIT", 1480 + "engines": { 1481 + "node": ">=10.5.0" 1482 + } 1483 + }, 1484 + "node_modules/node-fetch": { 1485 + "version": "3.3.2", 1486 + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", 1487 + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", 1488 + "license": "MIT", 1489 + "dependencies": { 1490 + "data-uri-to-buffer": "^4.0.0", 1491 + "fetch-blob": "^3.1.4", 1492 + "formdata-polyfill": "^4.0.10" 1493 + }, 1494 + "engines": { 1495 + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1496 + }, 1497 + "funding": { 1498 + "type": "opencollective", 1499 + "url": "https://opencollective.com/node-fetch" 1500 + } 1501 + }, 1502 + "node_modules/nodemon": { 1503 + "version": "3.1.11", 1504 + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", 1505 + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", 1506 + "dev": true, 1507 + "license": "MIT", 1508 + "dependencies": { 1509 + "chokidar": "^3.5.2", 1510 + "debug": "^4", 1511 + "ignore-by-default": "^1.0.1", 1512 + "minimatch": "^3.1.2", 1513 + "pstree.remy": "^1.1.8", 1514 + "semver": "^7.5.3", 1515 + "simple-update-notifier": "^2.0.0", 1516 + "supports-color": "^5.5.0", 1517 + "touch": "^3.1.0", 1518 + "undefsafe": "^2.0.5" 1519 + }, 1520 + "bin": { 1521 + "nodemon": "bin/nodemon.js" 1522 + }, 1523 + "engines": { 1524 + "node": ">=10" 1525 + }, 1526 + "funding": { 1527 + "type": "opencollective", 1528 + "url": "https://opencollective.com/nodemon" 1529 + } 1530 + }, 1531 + "node_modules/nodemon/node_modules/brace-expansion": { 1532 + "version": "1.1.12", 1533 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", 1534 + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", 1535 + "dev": true, 1536 + "license": "MIT", 1537 + "dependencies": { 1538 + "balanced-match": "^1.0.0", 1539 + "concat-map": "0.0.1" 1540 + } 1541 + }, 1542 + "node_modules/nodemon/node_modules/minimatch": { 1543 + "version": "3.1.2", 1544 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1545 + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1546 + "dev": true, 1547 + "license": "ISC", 1548 + "dependencies": { 1549 + "brace-expansion": "^1.1.7" 1550 + }, 1551 + "engines": { 1552 + "node": "*" 1553 + } 1554 + }, 1555 + "node_modules/normalize-path": { 1556 + "version": "3.0.0", 1557 + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1558 + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1559 + "dev": true, 1560 + "license": "MIT", 1561 + "engines": { 1562 + "node": ">=0.10.0" 1563 + } 1564 + }, 1565 + "node_modules/object-inspect": { 1566 + "version": "1.13.4", 1567 + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", 1568 + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", 1569 + "license": "MIT", 1570 + "engines": { 1571 + "node": ">= 0.4" 1572 + }, 1573 + "funding": { 1574 + "url": "https://github.com/sponsors/ljharb" 1575 + } 1576 + }, 1577 + "node_modules/on-finished": { 1578 + "version": "2.4.1", 1579 + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 1580 + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 1581 + "license": "MIT", 1582 + "dependencies": { 1583 + "ee-first": "1.1.1" 1584 + }, 1585 + "engines": { 1586 + "node": ">= 0.8" 1587 + } 1588 + }, 1589 + "node_modules/on-headers": { 1590 + "version": "1.1.0", 1591 + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", 1592 + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", 1593 + "license": "MIT", 1594 + "engines": { 1595 + "node": ">= 0.8" 1596 + } 1597 + }, 1598 + "node_modules/once": { 1599 + "version": "1.4.0", 1600 + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1601 + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1602 + "license": "ISC", 1603 + "dependencies": { 1604 + "wrappy": "1" 1605 + } 1606 + }, 1607 + "node_modules/parseurl": { 1608 + "version": "1.3.3", 1609 + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 1610 + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 1611 + "license": "MIT", 1612 + "engines": { 1613 + "node": ">= 0.8" 1614 + } 1615 + }, 1616 + "node_modules/path-to-regexp": { 1617 + "version": "8.3.0", 1618 + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", 1619 + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", 1620 + "license": "MIT", 1621 + "funding": { 1622 + "type": "opencollective", 1623 + "url": "https://opencollective.com/express" 1624 + } 1625 + }, 1626 + "node_modules/picocolors": { 1627 + "version": "1.1.1", 1628 + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1629 + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1630 + "license": "ISC" 1631 + }, 1632 + "node_modules/picomatch": { 1633 + "version": "2.3.1", 1634 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1635 + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1636 + "dev": true, 1637 + "license": "MIT", 1638 + "engines": { 1639 + "node": ">=8.6" 1640 + }, 1641 + "funding": { 1642 + "url": "https://github.com/sponsors/jonschlinkert" 1643 + } 1644 + }, 1645 + "node_modules/promise-limit": { 1646 + "version": "2.7.0", 1647 + "resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz", 1648 + "integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==", 1649 + "license": "ISC" 1650 + }, 1651 + "node_modules/proxy-addr": { 1652 + "version": "2.0.7", 1653 + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 1654 + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 1655 + "license": "MIT", 1656 + "dependencies": { 1657 + "forwarded": "0.2.0", 1658 + "ipaddr.js": "1.9.1" 1659 + }, 1660 + "engines": { 1661 + "node": ">= 0.10" 1662 + } 1663 + }, 1664 + "node_modules/pstree.remy": { 1665 + "version": "1.1.8", 1666 + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 1667 + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", 1668 + "dev": true, 1669 + "license": "MIT" 1670 + }, 1671 + "node_modules/qs": { 1672 + "version": "6.14.1", 1673 + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", 1674 + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", 1675 + "license": "BSD-3-Clause", 1676 + "dependencies": { 1677 + "side-channel": "^1.1.0" 1678 + }, 1679 + "engines": { 1680 + "node": ">=0.6" 1681 + }, 1682 + "funding": { 1683 + "url": "https://github.com/sponsors/ljharb" 1684 + } 1685 + }, 1686 + "node_modules/random-bytes": { 1687 + "version": "1.0.0", 1688 + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", 1689 + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", 1690 + "license": "MIT", 1691 + "engines": { 1692 + "node": ">= 0.8" 1693 + } 1694 + }, 1695 + "node_modules/range-parser": { 1696 + "version": "1.2.1", 1697 + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 1698 + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 1699 + "license": "MIT", 1700 + "engines": { 1701 + "node": ">= 0.6" 1702 + } 1703 + }, 1704 + "node_modules/raw-body": { 1705 + "version": "3.0.2", 1706 + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", 1707 + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", 1708 + "license": "MIT", 1709 + "dependencies": { 1710 + "bytes": "~3.1.2", 1711 + "http-errors": "~2.0.1", 1712 + "iconv-lite": "~0.7.0", 1713 + "unpipe": "~1.0.0" 1714 + }, 1715 + "engines": { 1716 + "node": ">= 0.10" 1717 + } 1718 + }, 1719 + "node_modules/readdirp": { 1720 + "version": "3.6.0", 1721 + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1722 + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1723 + "dev": true, 1724 + "license": "MIT", 1725 + "dependencies": { 1726 + "picomatch": "^2.2.1" 1727 + }, 1728 + "engines": { 1729 + "node": ">=8.10.0" 1730 + } 1731 + }, 1732 + "node_modules/router": { 1733 + "version": "2.2.0", 1734 + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", 1735 + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", 1736 + "license": "MIT", 1737 + "dependencies": { 1738 + "debug": "^4.4.0", 1739 + "depd": "^2.0.0", 1740 + "is-promise": "^4.0.0", 1741 + "parseurl": "^1.3.3", 1742 + "path-to-regexp": "^8.0.0" 1743 + }, 1744 + "engines": { 1745 + "node": ">= 18" 1746 + } 1747 + }, 1748 + "node_modules/safe-buffer": { 1749 + "version": "5.2.1", 1750 + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1751 + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1752 + "funding": [ 1753 + { 1754 + "type": "github", 1755 + "url": "https://github.com/sponsors/feross" 1756 + }, 1757 + { 1758 + "type": "patreon", 1759 + "url": "https://www.patreon.com/feross" 1760 + }, 1761 + { 1762 + "type": "consulting", 1763 + "url": "https://feross.org/support" 1764 + } 1765 + ], 1766 + "license": "MIT" 1767 + }, 1768 + "node_modules/safer-buffer": { 1769 + "version": "2.1.2", 1770 + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1771 + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1772 + "license": "MIT" 1773 + }, 1774 + "node_modules/semver": { 1775 + "version": "7.7.3", 1776 + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", 1777 + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", 1778 + "dev": true, 1779 + "license": "ISC", 1780 + "bin": { 1781 + "semver": "bin/semver.js" 1782 + }, 1783 + "engines": { 1784 + "node": ">=10" 1785 + } 1786 + }, 1787 + "node_modules/send": { 1788 + "version": "1.2.1", 1789 + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", 1790 + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", 1791 + "license": "MIT", 1792 + "dependencies": { 1793 + "debug": "^4.4.3", 1794 + "encodeurl": "^2.0.0", 1795 + "escape-html": "^1.0.3", 1796 + "etag": "^1.8.1", 1797 + "fresh": "^2.0.0", 1798 + "http-errors": "^2.0.1", 1799 + "mime-types": "^3.0.2", 1800 + "ms": "^2.1.3", 1801 + "on-finished": "^2.4.1", 1802 + "range-parser": "^1.2.1", 1803 + "statuses": "^2.0.2" 1804 + }, 1805 + "engines": { 1806 + "node": ">= 18" 1807 + }, 1808 + "funding": { 1809 + "type": "opencollective", 1810 + "url": "https://opencollective.com/express" 1811 + } 1812 + }, 1813 + "node_modules/serve-static": { 1814 + "version": "2.2.1", 1815 + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", 1816 + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", 1817 + "license": "MIT", 1818 + "dependencies": { 1819 + "encodeurl": "^2.0.0", 1820 + "escape-html": "^1.0.3", 1821 + "parseurl": "^1.3.3", 1822 + "send": "^1.2.0" 1823 + }, 1824 + "engines": { 1825 + "node": ">= 18" 1826 + }, 1827 + "funding": { 1828 + "type": "opencollective", 1829 + "url": "https://opencollective.com/express" 1830 + } 1831 + }, 1832 + "node_modules/setprototypeof": { 1833 + "version": "1.2.0", 1834 + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 1835 + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 1836 + "license": "ISC" 1837 + }, 1838 + "node_modules/side-channel": { 1839 + "version": "1.1.0", 1840 + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", 1841 + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", 1842 + "license": "MIT", 1843 + "dependencies": { 1844 + "es-errors": "^1.3.0", 1845 + "object-inspect": "^1.13.3", 1846 + "side-channel-list": "^1.0.0", 1847 + "side-channel-map": "^1.0.1", 1848 + "side-channel-weakmap": "^1.0.2" 1849 + }, 1850 + "engines": { 1851 + "node": ">= 0.4" 1852 + }, 1853 + "funding": { 1854 + "url": "https://github.com/sponsors/ljharb" 1855 + } 1856 + }, 1857 + "node_modules/side-channel-list": { 1858 + "version": "1.0.0", 1859 + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", 1860 + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", 1861 + "license": "MIT", 1862 + "dependencies": { 1863 + "es-errors": "^1.3.0", 1864 + "object-inspect": "^1.13.3" 1865 + }, 1866 + "engines": { 1867 + "node": ">= 0.4" 1868 + }, 1869 + "funding": { 1870 + "url": "https://github.com/sponsors/ljharb" 1871 + } 1872 + }, 1873 + "node_modules/side-channel-map": { 1874 + "version": "1.0.1", 1875 + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", 1876 + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", 1877 + "license": "MIT", 1878 + "dependencies": { 1879 + "call-bound": "^1.0.2", 1880 + "es-errors": "^1.3.0", 1881 + "get-intrinsic": "^1.2.5", 1882 + "object-inspect": "^1.13.3" 1883 + }, 1884 + "engines": { 1885 + "node": ">= 0.4" 1886 + }, 1887 + "funding": { 1888 + "url": "https://github.com/sponsors/ljharb" 1889 + } 1890 + }, 1891 + "node_modules/side-channel-weakmap": { 1892 + "version": "1.0.2", 1893 + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", 1894 + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", 1895 + "license": "MIT", 1896 + "dependencies": { 1897 + "call-bound": "^1.0.2", 1898 + "es-errors": "^1.3.0", 1899 + "get-intrinsic": "^1.2.5", 1900 + "object-inspect": "^1.13.3", 1901 + "side-channel-map": "^1.0.1" 1902 + }, 1903 + "engines": { 1904 + "node": ">= 0.4" 1905 + }, 1906 + "funding": { 1907 + "url": "https://github.com/sponsors/ljharb" 1908 + } 1909 + }, 1910 + "node_modules/simple-update-notifier": { 1911 + "version": "2.0.0", 1912 + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", 1913 + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", 1914 + "dev": true, 1915 + "license": "MIT", 1916 + "dependencies": { 1917 + "semver": "^7.5.3" 1918 + }, 1919 + "engines": { 1920 + "node": ">=10" 1921 + } 1922 + }, 1923 + "node_modules/statuses": { 1924 + "version": "2.0.2", 1925 + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", 1926 + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", 1927 + "license": "MIT", 1928 + "engines": { 1929 + "node": ">= 0.8" 1930 + } 1931 + }, 1932 + "node_modules/supports-color": { 1933 + "version": "5.5.0", 1934 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1935 + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1936 + "dev": true, 1937 + "license": "MIT", 1938 + "dependencies": { 1939 + "has-flag": "^3.0.0" 1940 + }, 1941 + "engines": { 1942 + "node": ">=4" 1943 + } 1944 + }, 1945 + "node_modules/tlds": { 1946 + "version": "1.261.0", 1947 + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz", 1948 + "integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==", 1949 + "license": "MIT", 1950 + "bin": { 1951 + "tlds": "bin.js" 1952 + } 1953 + }, 1954 + "node_modules/to-regex-range": { 1955 + "version": "5.0.1", 1956 + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1957 + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1958 + "dev": true, 1959 + "license": "MIT", 1960 + "dependencies": { 1961 + "is-number": "^7.0.0" 1962 + }, 1963 + "engines": { 1964 + "node": ">=8.0" 1965 + } 1966 + }, 1967 + "node_modules/toidentifier": { 1968 + "version": "1.0.1", 1969 + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 1970 + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 1971 + "license": "MIT", 1972 + "engines": { 1973 + "node": ">=0.6" 1974 + } 1975 + }, 1976 + "node_modules/touch": { 1977 + "version": "3.1.1", 1978 + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", 1979 + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", 1980 + "dev": true, 1981 + "license": "ISC", 1982 + "bin": { 1983 + "nodetouch": "bin/nodetouch.js" 1984 + } 1985 + }, 1986 + "node_modules/tr46": { 1987 + "version": "0.0.3", 1988 + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 1989 + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", 1990 + "license": "MIT" 1991 + }, 1992 + "node_modules/tslib": { 1993 + "version": "2.8.1", 1994 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 1995 + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 1996 + "license": "0BSD" 1997 + }, 1998 + "node_modules/type-is": { 1999 + "version": "2.0.1", 2000 + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", 2001 + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", 2002 + "license": "MIT", 2003 + "dependencies": { 2004 + "content-type": "^1.0.5", 2005 + "media-typer": "^1.1.0", 2006 + "mime-types": "^3.0.0" 2007 + }, 2008 + "engines": { 2009 + "node": ">= 0.6" 2010 + } 2011 + }, 2012 + "node_modules/uid-safe": { 2013 + "version": "2.1.5", 2014 + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", 2015 + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", 2016 + "license": "MIT", 2017 + "dependencies": { 2018 + "random-bytes": "~1.0.0" 2019 + }, 2020 + "engines": { 2021 + "node": ">= 0.8" 2022 + } 2023 + }, 2024 + "node_modules/uint8arrays": { 2025 + "version": "3.0.0", 2026 + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", 2027 + "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", 2028 + "license": "MIT", 2029 + "dependencies": { 2030 + "multiformats": "^9.4.2" 2031 + } 2032 + }, 2033 + "node_modules/undefsafe": { 2034 + "version": "2.0.5", 2035 + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", 2036 + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", 2037 + "dev": true, 2038 + "license": "MIT" 2039 + }, 2040 + "node_modules/undici": { 2041 + "version": "6.23.0", 2042 + "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", 2043 + "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", 2044 + "license": "MIT", 2045 + "engines": { 2046 + "node": ">=18.17" 2047 + } 2048 + }, 2049 + "node_modules/undici-types": { 2050 + "version": "7.16.0", 2051 + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", 2052 + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", 2053 + "license": "MIT" 2054 + }, 2055 + "node_modules/unicode-segmenter": { 2056 + "version": "0.14.5", 2057 + "resolved": "https://registry.npmjs.org/unicode-segmenter/-/unicode-segmenter-0.14.5.tgz", 2058 + "integrity": "sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==", 2059 + "license": "MIT" 2060 + }, 2061 + "node_modules/unpipe": { 2062 + "version": "1.0.0", 2063 + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 2064 + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 2065 + "license": "MIT", 2066 + "engines": { 2067 + "node": ">= 0.8" 2068 + } 2069 + }, 2070 + "node_modules/vary": { 2071 + "version": "1.1.2", 2072 + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 2073 + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 2074 + "license": "MIT", 2075 + "engines": { 2076 + "node": ">= 0.8" 2077 + } 2078 + }, 2079 + "node_modules/web-streams-polyfill": { 2080 + "version": "3.3.3", 2081 + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", 2082 + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", 2083 + "license": "MIT", 2084 + "engines": { 2085 + "node": ">= 8" 2086 + } 2087 + }, 2088 + "node_modules/webidl-conversions": { 2089 + "version": "3.0.1", 2090 + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 2091 + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", 2092 + "license": "BSD-2-Clause" 2093 + }, 2094 + "node_modules/whatwg-url": { 2095 + "version": "5.0.0", 2096 + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 2097 + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 2098 + "license": "MIT", 2099 + "dependencies": { 2100 + "tr46": "~0.0.3", 2101 + "webidl-conversions": "^3.0.0" 2102 + } 2103 + }, 2104 + "node_modules/wrappy": { 2105 + "version": "1.0.2", 2106 + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2107 + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 2108 + "license": "ISC" 2109 + }, 2110 + "node_modules/ws": { 2111 + "version": "8.19.0", 2112 + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", 2113 + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", 2114 + "license": "MIT", 2115 + "engines": { 2116 + "node": ">=10.0.0" 2117 + }, 2118 + "peerDependencies": { 2119 + "bufferutil": "^4.0.1", 2120 + "utf-8-validate": ">=5.0.2" 2121 + }, 2122 + "peerDependenciesMeta": { 2123 + "bufferutil": { 2124 + "optional": true 2125 + }, 2126 + "utf-8-validate": { 2127 + "optional": true 2128 + } 2129 + } 2130 + }, 2131 + "node_modules/zod": { 2132 + "version": "3.25.76", 2133 + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", 2134 + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", 2135 + "license": "MIT", 2136 + "funding": { 2137 + "url": "https://github.com/sponsors/colinhacks" 2138 + } 2139 + } 2140 + } 2141 + }
+26
package.json
··· 1 + { 2 + "name": "bluerecipes", 3 + "version": "1.0.0", 4 + "description": "Recipe sharing platform built on AT Protocol", 5 + "license": "ISC", 6 + "author": "Nic Coates", 7 + "type": "commonjs", 8 + "main": "app.js", 9 + "scripts": { 10 + "start": "node app.js", 11 + "dev": "nodemon app.js", 12 + "init-db": "node config/init-db.js" 13 + }, 14 + "dependencies": { 15 + "@atproto/api": "^0.18.18", 16 + "@atproto/oauth-client-node": "^0.3.16", 17 + "@libsql/client": "^0.17.0", 18 + "dotenv": "^17.2.3", 19 + "ejs": "^4.0.1", 20 + "express": "^5.2.1", 21 + "express-session": "^1.19.0" 22 + }, 23 + "devDependencies": { 24 + "nodemon": "^3.1.11" 25 + } 26 + }
+282
public/css/style.css
··· 1 + :root { 2 + --bg: #ffffff; 3 + --text: #1a1a1a; 4 + --text-muted: #c9c8c8; 5 + --border: #e5e5e5; 6 + --link: #0066cc; 7 + } 8 + 9 + @media (prefers-color-scheme: dark) { 10 + :root { 11 + --bg: #0a0a0a; 12 + --text: #ffffff; 13 + --text-muted: #c9c8c8; 14 + --border: #2a2a2a; 15 + --link: #4d9fff; 16 + } 17 + } 18 + 19 + * { 20 + margin: 0; 21 + padding: 0; 22 + box-sizing: border-box; 23 + } 24 + 25 + body { 26 + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; 27 + background: var(--bg); 28 + color: var(--text); 29 + font-size: 16px; 30 + line-height: 1.6; 31 + } 32 + 33 + a { 34 + color: var(--text); 35 + text-decoration: none; 36 + } 37 + 38 + a:hover { 39 + color: var(--link); 40 + } 41 + 42 + /* Layout */ 43 + .container { 44 + display: grid; 45 + grid-template-columns: 280px 1fr; 46 + max-width: 920px; 47 + margin: 0 auto; 48 + min-height: 100vh; 49 + } 50 + 51 + /* Sidebar */ 52 + .sidebar { 53 + padding: 80px 40px 40px 80px; 54 + display: flex; 55 + flex-direction: column; 56 + justify-content: space-between; 57 + position: sticky; 58 + top: 0; 59 + height: 100vh; 60 + overflow-y: auto; 61 + } 62 + 63 + .sidebar .logo { 64 + margin-bottom: 16px; 65 + } 66 + .sidebar .logo img { 67 + height: 35px; 68 + width: 35px; 69 + } 70 + 71 + .sidebar nav ul { 72 + list-style: none; 73 + margin-bottom: 40px; 74 + } 75 + 76 + .sidebar nav li { 77 + margin-bottom: 16px; 78 + } 79 + 80 + .sidebar nav a { 81 + color: var(--text-muted); 82 + font-size: 16px; 83 + } 84 + 85 + .sidebar nav a:hover { 86 + color: var(--text); 87 + } 88 + 89 + .sidebar .active { 90 + font-weight: 500; 91 + color: var(--text); 92 + } 93 + 94 + .sidebar hr { 95 + border: none; 96 + border-top: 1px solid var(--border); 97 + margin-bottom: 40px; 98 + } 99 + 100 + .sidebar-bottom { 101 + color: var(--text-muted); 102 + font-size: 14px; 103 + } 104 + 105 + /* Content */ 106 + .content { 107 + padding: 80px 80px 80px 40px; 108 + max-width: 900px; 109 + } 110 + 111 + .content h1 { 112 + font-size: 32px; 113 + font-weight: 600; 114 + margin-bottom: 24px; 115 + line-height: 1.1; 116 + } 117 + 118 + .content .subtitle { 119 + color: var(--text-muted); 120 + font-size: 16px; 121 + margin-bottom: 80px; 122 + } 123 + 124 + .recipe-list { 125 + list-style: none; 126 + } 127 + 128 + .recipe-card { 129 + margin-bottom: 48px; 130 + padding-bottom: 48px; 131 + border-bottom: 1px solid var(--border); 132 + } 133 + 134 + .recipe-card:last-child { 135 + border-bottom: none; 136 + } 137 + 138 + .recipe-card h2 { 139 + font-size: 28px; 140 + font-weight: 600; 141 + margin-bottom: 12px; 142 + } 143 + 144 + .recipe-meta { 145 + color: var(--text-muted); 146 + font-size: 15px; 147 + margin-bottom: 16px; 148 + } 149 + 150 + .recipe-meta span { 151 + margin-right: 20px; 152 + } 153 + 154 + .recipe-card p { 155 + color: var(--text-muted); 156 + font-size: 16px; 157 + line-height: 1.7; 158 + } 159 + 160 + .empty-state { 161 + color: var(--text-muted); 162 + font-size: 18px; 163 + } 164 + 165 + /* Forms */ 166 + .form-center { 167 + min-height: 100vh; 168 + display: flex; 169 + align-items: center; 170 + justify-content: center; 171 + padding: 40px; 172 + } 173 + 174 + .form-box { 175 + max-width: 440px; 176 + width: 100%; 177 + } 178 + 179 + .form-box h1 { 180 + font-size: 40px; 181 + font-weight: 600; 182 + margin-bottom: 40px; 183 + } 184 + 185 + .form-group { 186 + margin-bottom: 28px; 187 + } 188 + 189 + .form-group label { 190 + display: block; 191 + margin-bottom: 10px; 192 + font-weight: 500; 193 + font-size: 15px; 194 + } 195 + 196 + .form-group input { 197 + width: 100%; 198 + padding: 14px 16px; 199 + border: 1px solid var(--border); 200 + border-radius: 6px; 201 + background: var(--bg); 202 + color: var(--text); 203 + font-size: 16px; 204 + } 205 + 206 + .form-group input:focus { 207 + outline: none; 208 + border-color: var(--link); 209 + } 210 + 211 + .form-group small { 212 + display: block; 213 + margin-top: 8px; 214 + color: var(--text-muted); 215 + font-size: 14px; 216 + } 217 + 218 + .form-group select, 219 + .form-group textarea { 220 + width: 100%; 221 + padding: 14px 16px; 222 + border: 1px solid var(--border); 223 + border-radius: 6px; 224 + background: var(--bg); 225 + color: var(--text); 226 + font-size: 16px; 227 + font-family: inherit; 228 + } 229 + 230 + .form-group select:focus, 231 + .form-group textarea:focus { 232 + outline: none; 233 + border-color: var(--link); 234 + } 235 + 236 + .form-group textarea { 237 + resize: vertical; 238 + min-height: 100px; 239 + } 240 + 241 + button { 242 + padding: 14px 28px; 243 + background: var(--text); 244 + color: var(--bg); 245 + border: none; 246 + border-radius: 6px; 247 + font-size: 16px; 248 + font-weight: 600; 249 + cursor: pointer; 250 + } 251 + 252 + button:hover { 253 + opacity: 0.9; 254 + } 255 + 256 + .error { 257 + background: rgba(255, 0, 0, 0.1); 258 + border: 1px solid rgba(255, 0, 0, 0.3); 259 + color: #dd0000; 260 + padding: 16px 20px; 261 + border-radius: 6px; 262 + margin-bottom: 28px; 263 + font-size: 15px; 264 + } 265 + 266 + @media (max-width: 900px) { 267 + .container { 268 + grid-template-columns: 1fr; 269 + } 270 + 271 + .sidebar { 272 + padding: 40px; 273 + } 274 + 275 + .content { 276 + padding: 40px; 277 + } 278 + 279 + .content h1 { 280 + font-size: 48px; 281 + } 282 + }
+9
public/images/bluerecipes.svg
··· 1 + <svg width="96" height="96" viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 + <rect width="96" height="96" rx="10" fill="#3B82F6"/> 3 + <path d="M25.6204 37.4013C25.6204 36.7805 26.1236 36.2772 26.7445 36.2772H69.46C70.0808 36.2772 70.5841 36.7805 70.5841 37.4013V64.3795C70.5841 67.4836 68.0678 70 64.9637 70H31.2408C28.1367 70 25.6204 67.4836 25.6204 64.3795V37.4013Z" stroke="white" stroke-width="5.3895"/> 4 + <circle cx="22.8102" cy="43.5838" r="2.81024" fill="white"/> 5 + <circle cx="73.3945" cy="43.5838" r="2.81024" fill="white"/> 6 + <rect x="35.7373" y="20.5399" width="3.37228" height="7.86866" rx="1.68614" fill="white"/> 7 + <rect x="45.8542" y="19" width="3.37228" height="7.86866" rx="1.68614" fill="white"/> 8 + <rect x="55.9709" y="20.5399" width="3.37228" height="7.86866" rx="1.68614" fill="white"/> 9 + </svg>
+68
routes/auth.js
··· 1 + const express = require("express"); 2 + const router = express.Router(); 3 + const atproto = require("../services/atproto"); 4 + const db = require("../config/database"); 5 + 6 + // Login page 7 + router.get("/login", (req, res) => { 8 + res.render("auth/login", { 9 + title: "Sign in - BlueRecipes", 10 + error: null, 11 + }); 12 + }); 13 + 14 + // Handle login 15 + router.post("/login", async (req, res) => { 16 + const { handle, appPassword } = req.body; 17 + 18 + if (!handle || !appPassword) { 19 + return res.render("auth/login", { 20 + title: "Sign in - BlueRecipes", 21 + error: "Please provide both handle and app password", 22 + }); 23 + } 24 + 25 + const result = await atproto.login(handle, appPassword); 26 + 27 + if (!result.success) { 28 + return res.render("auth/login", { 29 + title: "Sign in - BlueRecipes", 30 + error: "Login failed. Check your handle and app password.", 31 + }); 32 + } 33 + 34 + // Store user in database if they don't exist 35 + try { 36 + await db.execute({ 37 + sql: "INSERT OR IGNORE INTO users (did, handle) VALUES (?, ?)", 38 + args: [result.did, result.handle], 39 + }); 40 + 41 + // Update handle in case it changed 42 + await db.execute({ 43 + sql: "UPDATE users SET handle = ?, updated_at = CURRENT_TIMESTAMP WHERE did = ?", 44 + args: [result.handle, result.did], 45 + }); 46 + } catch (error) { 47 + console.error("Error saving user:", error); 48 + } 49 + 50 + // Store user in session 51 + req.session.user = { 52 + did: result.did, 53 + handle: result.handle, 54 + }; 55 + 56 + res.redirect("/"); 57 + }); 58 + 59 + // Logout 60 + router.get("/logout", (req, res) => { 61 + if (req.session.user) { 62 + atproto.logout(req.session.user.did); 63 + req.session.destroy(); 64 + } 65 + res.redirect("/"); 66 + }); 67 + 68 + module.exports = router;
+31
routes/index.js
··· 1 + const express = require("express"); 2 + const router = express.Router(); 3 + const db = require("../config/database"); 4 + 5 + // Homepage - discovery feed 6 + router.get("/", async (req, res) => { 7 + try { 8 + // Get latest recipes from database 9 + const result = await db.execute({ 10 + sql: "SELECT * FROM recipes ORDER BY created_at DESC LIMIT 20", 11 + args: [], 12 + }); 13 + 14 + const recipes = result.rows; 15 + 16 + res.render("index", { 17 + title: "BlueRecipes - Discover Recipes", 18 + recipes: recipes, 19 + user: req.session.user || null, 20 + }); 21 + } catch (error) { 22 + console.error("Error loading recipes:", error); 23 + res.render("index", { 24 + title: "BlueRecipes - Discover Recipes", 25 + recipes: [], 26 + user: req.session.user || null, 27 + }); 28 + } 29 + }); 30 + 31 + module.exports = router;
+106
routes/recipe.js
··· 1 + const express = require("express"); 2 + const router = express.Router(); 3 + const atproto = require("../services/atproto"); 4 + const db = require("../config/database"); 5 + 6 + // Middleware to check if user is logged in 7 + function requireAuth(req, res, next) { 8 + if (!req.session.user) { 9 + return res.redirect("/auth/login"); 10 + } 11 + next(); 12 + } 13 + 14 + // Show new recipe form 15 + router.get("/new", requireAuth, (req, res) => { 16 + res.render("recipe/new", { 17 + title: "New Recipe - BlueRecipes", 18 + user: req.session.user, 19 + error: null, 20 + }); 21 + }); 22 + 23 + // Handle recipe creation 24 + router.post("/new", requireAuth, async (req, res) => { 25 + const { 26 + title, 27 + description, 28 + prepTime, 29 + cookTime, 30 + servings, 31 + ingredients, 32 + steps, 33 + type, 34 + } = req.body; 35 + 36 + // Validation 37 + if ( 38 + !title || 39 + !prepTime || 40 + !cookTime || 41 + !servings || 42 + !ingredients || 43 + !steps || 44 + !type 45 + ) { 46 + return res.render("recipe/new", { 47 + title: "New Recipe - BlueRecipes", 48 + user: req.session.user, 49 + error: "All fields except description are required", 50 + }); 51 + } 52 + 53 + try { 54 + // Create record on user's PDS 55 + const result = await atproto.createRecipe(req.session.user.did, { 56 + title, 57 + description, 58 + prepTime, 59 + cookTime, 60 + servings, 61 + ingredients, 62 + steps, 63 + type, 64 + }); 65 + 66 + if (!result.success) { 67 + return res.render("recipe/new", { 68 + title: "New Recipe - BlueRecipes", 69 + user: req.session.user, 70 + error: "Failed to create recipe: " + result.error, 71 + }); 72 + } 73 + 74 + // Store in our database for indexing 75 + await db.execute({ 76 + sql: `INSERT INTO recipes 77 + (did, title, description, prep_time, cook_time, servings, ingredients, steps, type, at_uri, cid) 78 + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, 79 + args: [ 80 + req.session.user.did, 81 + title, 82 + description || null, 83 + parseInt(prepTime), 84 + parseInt(cookTime), 85 + servings, 86 + ingredients, 87 + steps, 88 + type, 89 + result.uri, 90 + result.cid, 91 + ], 92 + }); 93 + 94 + // Redirect to home to see the new recipe 95 + res.redirect("/"); 96 + } catch (error) { 97 + console.error("Error creating recipe:", error); 98 + res.render("recipe/new", { 99 + title: "New Recipe - BlueRecipes", 100 + user: req.session.user, 101 + error: "Something went wrong. Please try again.", 102 + }); 103 + } 104 + }); 105 + 106 + module.exports = router;
+93
services/atproto.js
··· 1 + const { AtpAgent } = require("@atproto/api"); 2 + 3 + class ATProtoService { 4 + constructor() { 5 + this.agents = new Map(); // Store agents per user session 6 + } 7 + 8 + // Login with handle and app password 9 + async login(handle, appPassword) { 10 + try { 11 + const agent = new AtpAgent({ 12 + service: "https://bsky.social", 13 + }); 14 + 15 + await agent.login({ 16 + identifier: handle, 17 + password: appPassword, 18 + }); 19 + 20 + // Store agent for this session 21 + const sessionKey = agent.session.did; 22 + this.agents.set(sessionKey, agent); 23 + 24 + return { 25 + success: true, 26 + did: agent.session.did, 27 + handle: agent.session.handle, 28 + }; 29 + } catch (error) { 30 + console.error("Login failed:", error); 31 + return { 32 + success: false, 33 + error: error.message, 34 + }; 35 + } 36 + } 37 + 38 + // Get agent for a user 39 + getAgent(did) { 40 + return this.agents.get(did); 41 + } 42 + 43 + // Logout 44 + logout(did) { 45 + this.agents.delete(did); 46 + } 47 + 48 + // Create a recipe record on the user's PDS 49 + async createRecipe(did, recipeData) { 50 + const agent = this.getAgent(did); 51 + if (!agent) { 52 + throw new Error("Not authenticated"); 53 + } 54 + 55 + try { 56 + // Create the recipe record 57 + const record = { 58 + $type: "net.bluerecipes.recipe", 59 + title: recipeData.title, 60 + description: recipeData.description || "", 61 + prepTime: parseInt(recipeData.prepTime), 62 + cookTime: parseInt(recipeData.cookTime), 63 + servings: recipeData.servings, 64 + ingredients: recipeData.ingredients, 65 + steps: recipeData.steps, 66 + type: recipeData.type, 67 + createdAt: new Date().toISOString(), 68 + }; 69 + 70 + // Post to the user's PDS 71 + const response = await agent.com.atproto.repo.createRecord({ 72 + repo: agent.session.did, 73 + collection: "net.bluerecipes.recipe", 74 + record: record, 75 + }); 76 + 77 + return { 78 + success: true, 79 + uri: response.data.uri, 80 + cid: response.data.cid, 81 + }; 82 + } catch (error) { 83 + console.error("Failed to create recipe:", error); 84 + return { 85 + success: false, 86 + error: error.message, 87 + }; 88 + } 89 + } 90 + } 91 + 92 + // Export a singleton instance 93 + module.exports = new ATProtoService();
+37
views/auth/login.ejs
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 + <title><%= title %></title> 7 + <link rel="stylesheet" href="/css/style.css"> 8 + </head> 9 + <body> 10 + <div class="form-center"> 11 + <div class="form-box"> 12 + <h1>Sign in to BlueRecipes</h1> 13 + 14 + <% if (error) { %> 15 + <div class="error"><%= error %></div> 16 + <% } %> 17 + 18 + <form method="POST" action="/auth/login"> 19 + <div class="form-group"> 20 + <label for="handle">Bluesky Handle</label> 21 + <input type="text" id="handle" name="handle" placeholder="yourname.bsky.social" required> 22 + </div> 23 + 24 + <div class="form-group"> 25 + <label for="appPassword">App Password</label> 26 + <input type="password" id="appPassword" name="appPassword" required> 27 + <small>Generate at <a href="https://bsky.app/settings/app-passwords" target="_blank">bsky.app/settings/app-passwords</a></small> 28 + </div> 29 + 30 + <button type="submit">Sign in</button> 31 + </form> 32 + 33 + <p style="margin-top: 24px;"><a href="/">← Back</a></p> 34 + </div> 35 + </div> 36 + </body> 37 + </html>
+84
views/index.ejs
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 + <title><%= title %></title> 7 + <link rel="stylesheet" href="/css/style.css" /> 8 + </head> 9 + <body> 10 + <div class="container"> 11 + <aside class="sidebar"> 12 + <div class="sidebar-top"> 13 + <div class="logo"> 14 + <img 15 + src="/images/bluerecipes.svg" 16 + alt="Blue Recipes logo" 17 + /> 18 + </div> 19 + 20 + <nav> 21 + <ul> 22 + <li><a href="/" class="active">Discover</a></li> 23 + <% if (user) { %> 24 + <li><a href="/recipe/new">New Recipe</a></li> 25 + <li> 26 + <a href="/user/<%= user.handle %>" 27 + >My Recipes</a 28 + > 29 + </li> 30 + <li><a href="/auth/logout">Sign out</a></li> 31 + <% } else { %> 32 + <li><a href="/auth/login">Sign in</a></li> 33 + <% } %> 34 + </ul> 35 + </nav> 36 + 37 + <hr /> 38 + 39 + <nav> 40 + <ul> 41 + <li><a href="/?type=breakfast">Breakfast</a></li> 42 + <li><a href="/?type=lunch">Lunch</a></li> 43 + <li><a href="/?type=dinner">Dinner</a></li> 44 + <li><a href="/?type=snacks">Snacks</a></li> 45 + </ul> 46 + </nav> 47 + </div> 48 + 49 + <div class="sidebar-bottom"> 50 + <p>© 2026</p> 51 + </div> 52 + </aside> 53 + 54 + <main class="content"> 55 + <h1>Your recipes, your way.</h1> 56 + <p class="subtitle"> 57 + Share culinary creations on the open web. Powered by AT 58 + Protocol. 59 + </p> 60 + 61 + <% if (recipes.length === 0) { %> 62 + <div class="empty-state">No recipes yet.</div> 63 + <% } else { %> 64 + <ul class="recipe-list"> 65 + <% recipes.forEach(recipe => { %> 66 + <li class="recipe-card"> 67 + <h2><%= recipe.title %></h2> 68 + <div class="recipe-meta"> 69 + <span 70 + ><%= recipe.prep_time + recipe.cook_time 71 + %>min</span 72 + > 73 + <span><%= recipe.servings %></span> 74 + <span><%= recipe.type %></span> 75 + </div> 76 + <p><%= recipe.description %></p> 77 + </li> 78 + <% }) %> 79 + </ul> 80 + <% } %> 81 + </main> 82 + </div> 83 + </body> 84 + </html>
+114
views/recipe/new.ejs
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 + <title><%= title %></title> 7 + <link rel="stylesheet" href="/css/style.css"> 8 + </head> 9 + <body> 10 + <div class="container"> 11 + <aside class="sidebar"> 12 + <div class="sidebar-top"> 13 + <div class="logo"> 14 + <img src="/images/bluerecipes.svg" alt="BlueRecipes"> 15 + </div> 16 + 17 + <nav> 18 + <ul> 19 + <li><a href="/">Discover</a></li> 20 + <li><a href="/recipe/new" class="active">New Recipe</a></li> 21 + <li><a href="/user/<%= user.handle %>">My Recipes</a></li> 22 + <li><a href="/auth/logout">Sign out</a></li> 23 + </ul> 24 + </nav> 25 + 26 + <hr> 27 + 28 + <nav> 29 + <ul> 30 + <li><a href="/?type=breakfast">Breakfast</a></li> 31 + <li><a href="/?type=lunch">Lunch</a></li> 32 + <li><a href="/?type=dinner">Dinner</a></li> 33 + <li><a href="/?type=snacks">Snacks</a></li> 34 + </ul> 35 + </nav> 36 + </div> 37 + 38 + <div class="sidebar-bottom"> 39 + <p>© 2026</p> 40 + </div> 41 + </aside> 42 + 43 + <main class="content"> 44 + <h1>Share a recipe</h1> 45 + <p class="subtitle">Add your culinary creation to the open web.</p> 46 + 47 + <% if (error) { %> 48 + <div class="error"><%= error %></div> 49 + <% } %> 50 + 51 + <form method="POST" action="/recipe/new"> 52 + <div class="form-group"> 53 + <label for="title">Recipe Title</label> 54 + <input type="text" id="title" name="title" placeholder="Classic Chocolate Chip Cookies" required> 55 + </div> 56 + 57 + <div class="form-group"> 58 + <label for="description">Description</label> 59 + <input type="text" id="description" name="description" placeholder="Crispy on the outside, chewy on the inside..."> 60 + <small>Optional - a short summary of your recipe</small> 61 + </div> 62 + 63 + <div class="form-group"> 64 + <label for="type">Type</label> 65 + <select id="type" name="type" required> 66 + <option value="">Select a category...</option> 67 + <option value="breakfast">Breakfast</option> 68 + <option value="lunch">Lunch</option> 69 + <option value="dinner">Dinner</option> 70 + <option value="snacks">Snacks</option> 71 + <option value="dessert">Dessert</option> 72 + </select> 73 + </div> 74 + 75 + <div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px;"> 76 + <div class="form-group"> 77 + <label for="prepTime">Prep Time (mins)</label> 78 + <input type="number" id="prepTime" name="prepTime" placeholder="15" min="0" required> 79 + </div> 80 + 81 + <div class="form-group"> 82 + <label for="cookTime">Cook Time (mins)</label> 83 + <input type="number" id="cookTime" name="cookTime" placeholder="30" min="0" required> 84 + </div> 85 + 86 + <div class="form-group"> 87 + <label for="servings">Servings</label> 88 + <input type="text" id="servings" name="servings" placeholder="4-6" required> 89 + </div> 90 + </div> 91 + 92 + <div class="form-group"> 93 + <label for="ingredients">Ingredients</label> 94 + <textarea id="ingredients" name="ingredients" rows="8" placeholder="2 cups flour 95 + 1 cup sugar 96 + 3 eggs 97 + ..." required></textarea> 98 + <small>List each ingredient on a new line</small> 99 + </div> 100 + 101 + <div class="form-group"> 102 + <label for="steps">Instructions</label> 103 + <textarea id="steps" name="steps" rows="10" placeholder="1. Preheat oven to 180°C 104 + 2. Mix dry ingredients... 105 + 3. Combine wet ingredients..." required></textarea> 106 + <small>Write the steps to make your recipe</small> 107 + </div> 108 + 109 + <button type="submit">Share Recipe</button> 110 + </form> 111 + </main> 112 + </div> 113 + </body> 114 + </html>