From d28d8333ebe71e2937660b13d9afb1d516cf14f0 Mon Sep 17 00:00:00 2001 From: wlodekm Date: Fri, 15 Nov 2024 09:46:47 +0200 Subject: v1.0.2 --- client.ts | 68 +++++ deno.lock | 66 +---- elements.ts | 125 +++++++++ keys.js | 12 - logger.ts | 24 ++ main.ts | 5 +- package-lock.json | 785 ---------------------------------------------------- pnpm-lock.yaml | 571 -------------------------------------- screen.ts | 106 +++++++ screen/home.ts | 53 ++++ screen/login.ts | 55 ++++ screenbuilder.ts | 44 +++ strftime.js | 92 ++++++ v2/client.ts | 67 ----- v2/elements.ts | 124 --------- v2/logger.ts | 24 -- v2/screen.ts | 101 ------- v2/screen/home.ts | 53 ---- v2/screen/login.ts | 55 ---- v2/screenbuilder.ts | 43 --- v2/strftime.js | 92 ------ 21 files changed, 572 insertions(+), 1993 deletions(-) create mode 100644 client.ts create mode 100644 elements.ts delete mode 100644 keys.js create mode 100644 logger.ts delete mode 100644 package-lock.json delete mode 100644 pnpm-lock.yaml create mode 100644 screen.ts create mode 100644 screen/home.ts create mode 100644 screen/login.ts create mode 100644 screenbuilder.ts create mode 100644 strftime.js delete mode 100644 v2/client.ts delete mode 100644 v2/elements.ts delete mode 100644 v2/logger.ts delete mode 100644 v2/screen.ts delete mode 100644 v2/screen/home.ts delete mode 100644 v2/screen/login.ts delete mode 100644 v2/screenbuilder.ts delete mode 100644 v2/strftime.js diff --git a/client.ts b/client.ts new file mode 100644 index 0000000..5f47fb4 --- /dev/null +++ b/client.ts @@ -0,0 +1,68 @@ +// deno-lint-ignore-file no-explicit-any + +import { Screen } from "./screen.ts"; +import type { Text } from "./elements.ts"; +import strftime from "./strftime.js"; + +export let token: string; +export let account: any; +export const connection = new WebSocket("wss://api.meower.org/v0/cloudlink?v=1") + +export let home: any[] = []; + +let screen: Screen; + +export function setScreen(screenN: Screen) { + screen = screenN +} + +export async function login(username: string, password: string) { + screen.logs.push(`logging in as ${username}`) + const authr = await (await fetch("https://api.meower.org/auth/login", { + method: "post", + headers: { + "content-type": "application/json" + }, + body: JSON.stringify({ + username, + password + }) + })).json(); + screen.logs.push(`got auth response (${authr.error ? "error" : "not error"})`) + token = authr.token; + account = authr.account; + screen.logs.push(`Got token ${token}`); + connection.addEventListener("message", (ev) => { + const data = JSON.parse(ev.data.toString()); + screen.logs.push("INC: " + JSON.stringify(data)) + if(data.cmd != "post") return; + home.push(data.val); + const textHome: string[] = home.map(p => `[${strftime("%H:%M:%S", new Date(p.t.e * 1000))}] ${p.u}: ${p.p}`); + const homeElem: Text = screen.elements.get("home") as Text; + homeElem.text = textHome.join("\n")+"\n"; + screen.render() + }) +} + +export async function loadHome(screen: Screen) { + home = (await (await fetch("https://api.meower.org/home")).json()).autoget.reverse(); + const textHome: string[] = home.map(p => `[${strftime("%H:%M:%S")}] ${p.u}: ${p.p}`); + const homeElem: Text = screen.elements.get("home") as Text; + homeElem.text = textHome.join("\n")+"\n"; + screen.logs.push("loadHome ran", home.length.toString()) + screen.render() +} + +export function sendHome(post:string) { + screen.logs.push("sendHome ran", home.length.toString()) + fetch("https://api.meower.org/home", { + method: "POST", + headers: { + token, + "content-type": "application/json" + }, + body: JSON.stringify({ + content: post + }) + }).then(async r=>screen.logs.push(`Got send response (${r.status} ${r.statusText}) ${await r.text()}`)) +} diff --git a/deno.lock b/deno.lock index f598709..6c70a29 100644 --- a/deno.lock +++ b/deno.lock @@ -1,73 +1,11 @@ { "version": "4", - "remote": { - "https://deno.land/x/crayon@3.3.3/mod.ts": "82ad225583a483c4837577971629cddaa22614093af8353da6426b9366de9780", - "https://deno.land/x/crayon@3.3.3/src/conversions.ts": "9bfd3b1fbe412bcba092890ac558b6beaad4c3aa399cd99d45fadb324d28afd6", - "https://deno.land/x/crayon@3.3.3/src/crayon.ts": "6b237baa08a31c903436e040afd2228a7fffaa5d11dddc58e3c402f79b3c1d04", - "https://deno.land/x/crayon@3.3.3/src/styles.ts": "aa588b57b2c0482dc5c6f53109b4287831a9827c0aeef9a88129beae1172c1ee", - "https://deno.land/x/crayon@3.3.3/src/util.ts": "af8884a917488de76ac0c2b92482093ade74514ece77a4c64e5eb5b0f6ed68e6", - "https://deno.land/x/tui@2.1.11/mod.ts": "b32347385f2efc7dd90a9e5f6386fded9bde505e3f1c4b07b8509c77206d15a6", - "https://deno.land/x/tui@2.1.11/src/canvas/box.ts": "3f6a41af65942b069795d895c2a73d039a83ba35c01b5236ea88d1de65ba3ebf", - "https://deno.land/x/tui@2.1.11/src/canvas/canvas.ts": "31daa080882956f19f5bf8a6b52f7a946ebc34bdba103b007ce4e73c2b922409", - "https://deno.land/x/tui@2.1.11/src/canvas/draw_object.ts": "2b8a48f10c343aee61d9dc7f00ea7917119ea41374a994e1db7b5b1ee188f0f8", - "https://deno.land/x/tui@2.1.11/src/canvas/mod.ts": "9da429bfb1d4f53eed661c3e2a2ae4b610380526597aa5f35a6604b810a83ac7", - "https://deno.land/x/tui@2.1.11/src/canvas/text.ts": "e6c0f5ecb985a037e55397810bc212bae206240acd3e2b15fb786ae2746abdea", - "https://deno.land/x/tui@2.1.11/src/component.ts": "d7a35cd1a4bc8a6177b047595c86e1df3418b340701e343ee83a08ac7a8005de", - "https://deno.land/x/tui@2.1.11/src/components/box.ts": "bc0be923353e6b146dd5275097d5c12606f4e966cf9e1386f5482c2d49320be7", - "https://deno.land/x/tui@2.1.11/src/components/button.ts": "90128d9f919a4506c2324a2c49c029f7fb7dd4872ea2b7df45505a01c125d660", - "https://deno.land/x/tui@2.1.11/src/components/checkbox.ts": "d185ceb9a3508b62311fb9b553e4da4282932a763c4494e76f1f221afbf95e9c", - "https://deno.land/x/tui@2.1.11/src/components/combobox.ts": "3e52c6c41afb12d6721ebe9a2c22cbaa4ccba8f752b018762c866403985eaf33", - "https://deno.land/x/tui@2.1.11/src/components/frame.ts": "e2f1a5c67a52a3a06243af461f8418ebf68e3c84c9c3ac6a59d6996e88941d11", - "https://deno.land/x/tui@2.1.11/src/components/input.ts": "e1df616d36b2d1df3202947e2cd5176bc9c7b966219db0ed2cc2932a112b8daf", - "https://deno.land/x/tui@2.1.11/src/components/label.ts": "c6d82665745a0251f7cfcc50ca96163faf8f82cd4e54fe82f4df9558043d8ef4", - "https://deno.land/x/tui@2.1.11/src/components/mod.ts": "3b43cf7fe523a877a2fddbb7c42d64db886debe491a6bc664c0d67b1ed3ef9a5", - "https://deno.land/x/tui@2.1.11/src/components/progressbar.ts": "3e58aa1d00b59149ba6309f4bf23bde6151fcac264ac3294369181cabd9faaba", - "https://deno.land/x/tui@2.1.11/src/components/slider.ts": "d88565a13eb9f2c55d1343889f0bb9af525edc1bd200c8ba43b5b174efec9cbe", - "https://deno.land/x/tui@2.1.11/src/components/table.ts": "1ef221fa3442f9c619ac3ea63051913b947e379efdf1567d8c611561ecf8a032", - "https://deno.land/x/tui@2.1.11/src/components/text.ts": "ea9b427d0bd056cded424bebf73ece62c3b7257651db80b82a51482a801a4f4f", - "https://deno.land/x/tui@2.1.11/src/components/textbox.ts": "c8799b13c0fc8ba22d9a0dcf4d8917abf991f73a8e0475ea07c9638eeb524f8d", - "https://deno.land/x/tui@2.1.11/src/controls.ts": "e0e91f61a8a73fb044ce980fd3d070407c2f950635cbce73d97f060ef19a780e", - "https://deno.land/x/tui@2.1.11/src/event_emitter.ts": "e4ee1de2037c89952c5c4c54dc336b7992024f0cb41c9e49229944e773386824", - "https://deno.land/x/tui@2.1.11/src/input.ts": "4ddc4049718847b2f76c2d022b740694ed50f958c2c42bb3a2eacfe0b0d83b0d", - "https://deno.land/x/tui@2.1.11/src/input_reader/decoders/keyboard.ts": "70d4f54605a650612601e654bc28a5d4260374a893e27b8a86fe7181cb626377", - "https://deno.land/x/tui@2.1.11/src/input_reader/decoders/mouse.ts": "a119c6261a27fb9b5e1711ba3d5161c45eac5615ea0aa739e4e6bca759434e6e", - "https://deno.land/x/tui@2.1.11/src/input_reader/mod.ts": "4213a920c69fd51badd1091fe7c61eff1bd1ead32659785c16f976ae377491cc", - "https://deno.land/x/tui@2.1.11/src/input_reader/types.ts": "c940a6d656b2fbdc051c2e0508f8eeefa322dd16e60fc6a3bac8d1e9337f7d6c", - "https://deno.land/x/tui@2.1.11/src/layout/errors.ts": "3df98a8f7747657fd252f602b26e9b5ee130dbfb236bcb4b2d2c912d7ae1eef9", - "https://deno.land/x/tui@2.1.11/src/layout/grid_layout.ts": "7b2fca94d1a074c61d838c36800dca47f518f720c6539a33d0ad674081a29a76", - "https://deno.land/x/tui@2.1.11/src/layout/horizontal_layout.ts": "e2ea27519c44c124cb228f19d4b14aa314e7db2cc92ef83fccfa146ced29d4e4", - "https://deno.land/x/tui@2.1.11/src/layout/mod.ts": "65381a8dd7e8f6287742ebeffef866ae98932d16daf3ea3325f0180b37e327b8", - "https://deno.land/x/tui@2.1.11/src/layout/types.ts": "ebc78ef4adbf802a49f5319474d81183a2b9edc2947443d9f40f23c4730e16f3", - "https://deno.land/x/tui@2.1.11/src/layout/vertical_layout.ts": "41f1ec4b897a0f45478b6392f0c74d0c010a74693b99f36f532c85d5525dfca0", - "https://deno.land/x/tui@2.1.11/src/signals/computed.ts": "824428cfda7c9e4a6aed8caee32a9aa62cd257fac9e7ca64d54c99a15ea56019", - "https://deno.land/x/tui@2.1.11/src/signals/dependency_tracking.ts": "b89e933a912e8c32881e13ba1555201ec22cc0be69600862ff824f72f1bd6d55", - "https://deno.land/x/tui@2.1.11/src/signals/effect.ts": "b478ca6469a151e93970679108e01a786b6e121023294d15b7293476161ec049", - "https://deno.land/x/tui@2.1.11/src/signals/flusher.ts": "b47eeca9547a39487bef56ab82272f050883474995d5e92191296aec936180cb", - "https://deno.land/x/tui@2.1.11/src/signals/lazy_computed.ts": "b4653efd855ce920657510b4cd086c58a8c72be6511465e3234f4e0b134bb9c6", - "https://deno.land/x/tui@2.1.11/src/signals/lazy_effect.ts": "b8bdebf29d4b5ae204bc8c0300f03d9c60ff097aef28e0df6515665497b919f0", - "https://deno.land/x/tui@2.1.11/src/signals/mod.ts": "e76b1303c74c257956d29f9169f3f12af410a0e8540c7a467e5405ba839cc431", - "https://deno.land/x/tui@2.1.11/src/signals/reactivity.ts": "8520655a0b948d979b1b3450139695726c1dfeb46b46d49b8e4159fe4651368d", - "https://deno.land/x/tui@2.1.11/src/signals/signal.ts": "5f351000a3316196ac3836fd9f3ef2a708aec85713df720a01c853d4859060be", - "https://deno.land/x/tui@2.1.11/src/signals/types.ts": "e04d088a849a58d184c30420fec9ab3726985e3bcbe2cdc1b4bbc218fb299dbe", - "https://deno.land/x/tui@2.1.11/src/theme.ts": "87f3da7e6a5bbbeb04c3c5384069225c244bcce0bac833a87828c5208af07cfc", - "https://deno.land/x/tui@2.1.11/src/tui.ts": "9b9bb4da296e96aadbe846520446d76570cf6105dcbc3c59e26a4301b4c6d2f4", - "https://deno.land/x/tui@2.1.11/src/types.ts": "7e39e8c59a1d28e379e54455dd7d7bb1a349191970d9af8d47a74b590e0de401", - "https://deno.land/x/tui@2.1.11/src/utils/ansi_codes.ts": "be83f249ab09d33b64540adda5191c58580d386cc7627b8d10ea3363c9a6d23d", - "https://deno.land/x/tui@2.1.11/src/utils/async.ts": "3f3bfe526c05467313237c434bc951a02344935dba61fe7b4e14d818d03ba1ca", - "https://deno.land/x/tui@2.1.11/src/utils/component.ts": "a7f5396b480c7ed437c5e08ec56c3e5c85a55963ee8520c2e5cc7a185577f1a3", - "https://deno.land/x/tui@2.1.11/src/utils/mod.ts": "4daef102e2406625f32faf08d238b702a26b3dc87232c35e97a215b9dbf9e781", - "https://deno.land/x/tui@2.1.11/src/utils/numbers.ts": "9d4322b7a184e111184f37507ccdf0d4a29ee7eb8f2ce8f942f078bd165f8941", - "https://deno.land/x/tui@2.1.11/src/utils/signals.ts": "a78893aa2e379468df65045a4d1f45e0111237b24e18c19bf5a92b6ee9074c4a", - "https://deno.land/x/tui@2.1.11/src/utils/sorted_array.ts": "d7b55e9c6489102fbee46d632040449f960f2ed3ae0d6bc3326e6d6ec1450d97", - "https://deno.land/x/tui@2.1.11/src/utils/strings.ts": "0f7d24072e3d2ed4993f0f2692f148b0af4d9b7a665193dec835101af4dabf7b", - "https://deno.land/x/tui@2.1.11/src/view.ts": "77c9dfdb3632f95c2456036c5e30f90cfbbad62cbb4f370cba48b992523aa619" - }, + "remote": {}, "workspace": { "packageJson": { "dependencies": [ "npm:@types/node@^22.9.0", - "npm:chalk@^5.3.0", - "npm:express@^4.21.1" + "npm:chalk@^5.3.0" ] } } diff --git a/elements.ts b/elements.ts new file mode 100644 index 0000000..d089931 --- /dev/null +++ b/elements.ts @@ -0,0 +1,125 @@ +// deno-lint-ignore-file no-case-declarations ban-ts-comment no-process-globals +import chalk from "chalk"; +import { type Key } from 'node:readline'; +import { type Screen } from "./screen.ts"; + +export abstract class Element { + focusable: boolean = false; + focused: boolean = false; + // screen property is asigned by the addElement function of Scren + //@ts-ignore + screen: Screen; + abstract render(): void; + onkeypres(_key: Key): void {}; +} + +export class Text extends Element { + text: string; + + processText: (text: string) => string; + + constructor(text: string, processText = (t:string)=>t) { + super(); + this.text = text; + this.processText = processText + } + render() { + process.stdout.write(this.processText(this.text)) + } +} + +export class HR extends Element { + constructor() { + super() + } + render(): void { + console.log('-'.repeat(process.stdout.columns)) + } +} + +export class BR extends Element { + constructor() { + super() + } + render(): void { + console.log() + } +} + +export class Input extends Element { + override focusable: boolean = true; + value: string = ""; + + textarea = false; + br = false; + + isPassword: boolean = false; + + render(): void { + let text = this.value + if (this.isPassword) text = text.replace(/[^]/g, '*'); + if (this.focused) text += "_" + process.stdout.write(text) + } + + override onkeypres(key: Key): void { + //@ts-ignore + if (key.meta || key.code || ["return", "backspace"].includes(key.name)) { + switch (key.name) { + case "return": + if(this.textarea) { + this.value += '\n' + break; + } + this.focused = false; + const focusableIDs = Object.keys(this.screen.getFocusable()); + const focusedIndex = focusableIDs.indexOf(this.screen.focusedElementId); + this.screen.focus(focusableIDs[(focusedIndex + 1) % focusableIDs.length]); + break; + + case "backspace": + const prevValue = '' + this.value + // logs.push(`doing backspace : before ${prevValue}, after ${prevValue.substring(0, prevValue.length - 1)} : 0-${prevValue.length - 1}`) + this.value = prevValue.substring(0, prevValue.length - 1) + break; + } + this.screen.render() + return; + } + // check if the character ism't typable + // checks: + // sequience length > 1 (eg ^[ ^[[A) + // key name != sequence (and if name exists) + //@ts-ignore + if (!key.sequence || key.sequence.length > 1 || key.name != key.sequence?.toLowerCase() && !["space"].includes(key.name) && key.name) return; + this.value += key.sequence; + this.screen.render() + } + + constructor(isPassword: boolean = false, br: boolean = false, textarea: boolean = false) { + super() + this.br = br + this.isPassword = isPassword; + this.textarea = textarea; + } +} + +export class Button extends Text { + override focusable: boolean = true; + onclick: ()=>void; + constructor (text: string, onclick=()=>{}) { + super(text); + this.onclick = onclick + } + + override render(): void { + process.stdout.write(`(${(this.focused ? chalk.bgWhite : (a:string)=>a)(this.text)})`) + } + + override onkeypres(key: Key): void { + //@ts-ignore + if (["return", "space"].includes(key.name)) { + this.onclick.call(this.screen) + } + } +} diff --git a/keys.js b/keys.js deleted file mode 100644 index 3884908..0000000 --- a/keys.js +++ /dev/null @@ -1,12 +0,0 @@ -// util for figuring out key stuff -// run this, press a key, and it'll give you the json :+1: -import readline from 'node:readline'; - -readline.emitKeypressEvents(process.stdin); - -if (process.stdin.isTTY) process.stdin.setRawMode(true); - -process.stdin.on('keypress', (chunk, key) => { - console.log(JSON.stringify(key)) - process.exit(); -}); \ No newline at end of file diff --git a/logger.ts b/logger.ts new file mode 100644 index 0000000..641a406 --- /dev/null +++ b/logger.ts @@ -0,0 +1,24 @@ +class Log { + time: number = Number(new Date()); + data: string = ""; + constructor (data: string, time?: number) { + this.data = data; + if(time) this.time = time; + } +} + +class Logger { + logs: Log[] = []; + + constructor () { + + } + + log (data: string) { + this.logs.push(new Log(data)) + } + + dump (): string[] { + return this.logs.map(log => ``) + } +} \ No newline at end of file diff --git a/main.ts b/main.ts index 435e4af..82d54f8 100644 --- a/main.ts +++ b/main.ts @@ -1,5 +1,6 @@ -import LoginScreen from "./v2/screen/login.ts"; -import { build } from "./v2/screenbuilder.ts"; +// deno-lint-ignore-file no-process-globals +import LoginScreen from "./screen/login.ts"; +import { build } from "./screenbuilder.ts"; import readline from 'node:readline'; readline.emitKeypressEvents(process.stdin); diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index bbcb2b7..0000000 --- a/package-lock.json +++ /dev/null @@ -1,785 +0,0 @@ -{ - "name": "http-meower", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@types/node": "^22.9.0", - "express": "^4.21.1" - } - }, - "node_modules/@types/node": { - "version": "22.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", - "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.8" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "license": "MIT" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - } - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index 08c530a..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,571 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@types/node': - specifier: ^22.9.0 - version: 22.9.0 - chalk: - specifier: ^5.3.0 - version: 5.3.0 - express: - specifier: ^4.21.1 - version: 4.21.1 - -packages: - - '@types/node@22.9.0': - resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} - - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} - engines: {node: '>= 0.4'} - - chalk@5.3.0: - resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} - engines: {node: '>= 0.6'} - - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - express@4.21.1: - resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} - engines: {node: '>= 0.10.0'} - - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} - engines: {node: '>= 0.8'} - - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} - engines: {node: '>= 0.4'} - - gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - - has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - - object-inspect@1.13.2: - resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} - engines: {node: '>= 0.4'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-to-regexp@0.1.10: - resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} - engines: {node: '>= 0.4'} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - -snapshots: - - '@types/node@22.9.0': - dependencies: - undici-types: 6.19.8 - - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - - array-flatten@1.1.1: {} - - body-parser@1.20.3: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - bytes@3.1.2: {} - - call-bind@1.0.7: - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - set-function-length: 1.2.2 - - chalk@5.3.0: {} - - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - - cookie-signature@1.0.6: {} - - cookie@0.7.1: {} - - debug@2.6.9: - dependencies: - ms: 2.0.0 - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - gopd: 1.0.1 - - depd@2.0.0: {} - - destroy@1.2.0: {} - - ee-first@1.1.1: {} - - encodeurl@1.0.2: {} - - encodeurl@2.0.0: {} - - es-define-property@1.0.0: - dependencies: - get-intrinsic: 1.2.4 - - es-errors@1.3.0: {} - - escape-html@1.0.3: {} - - etag@1.8.1: {} - - express@4.21.1: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.3 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.1 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.10 - proxy-addr: 2.0.7 - qs: 6.13.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.0 - serve-static: 1.16.2 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - finalhandler@1.3.1: - dependencies: - debug: 2.6.9 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - forwarded@0.2.0: {} - - fresh@0.5.2: {} - - function-bind@1.1.2: {} - - get-intrinsic@1.2.4: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 - - gopd@1.0.1: - dependencies: - get-intrinsic: 1.2.4 - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.0 - - has-proto@1.0.3: {} - - has-symbols@1.0.3: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - - inherits@2.0.4: {} - - ipaddr.js@1.9.1: {} - - media-typer@0.3.0: {} - - merge-descriptors@1.0.3: {} - - methods@1.1.2: {} - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@1.6.0: {} - - ms@2.0.0: {} - - ms@2.1.3: {} - - negotiator@0.6.3: {} - - object-inspect@1.13.2: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - parseurl@1.3.3: {} - - path-to-regexp@0.1.10: {} - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - qs@6.13.0: - dependencies: - side-channel: 1.0.6 - - range-parser@1.2.1: {} - - raw-body@2.5.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - - serve-static@1.16.2: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.0 - transitivePeerDependencies: - - supports-color - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-property-descriptors: 1.0.2 - - setprototypeof@1.2.0: {} - - side-channel@1.0.6: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.2 - - statuses@2.0.1: {} - - toidentifier@1.0.1: {} - - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - - undici-types@6.19.8: {} - - unpipe@1.0.0: {} - - utils-merge@1.0.1: {} - - vary@1.1.2: {} diff --git a/screen.ts b/screen.ts new file mode 100644 index 0000000..324ce7b --- /dev/null +++ b/screen.ts @@ -0,0 +1,106 @@ +// deno-lint-ignore-file no-process-globals ban-ts-comment no-explicit-any +// ^ problem solved +import { Key } from "node:readline"; +import type { Element, Input, Text, Button } from "./elements.ts" +import { Buffer } from "node:buffer"; + +const logs: string[] = []; + +function onexit() { + console.clear() + console.log("\nQuitting meower CL") + for (const log of logs) { + console.log(log) + } +} + +export class Screen { + elements: Map = new Map(); + name: string; + focusedElementId: string = ''; + logs = logs + + constructor(name: string) { + this.name = name; + } + + call(function_name:string, ...args:any) { + for (const element of this.elements) { + //@ts-ignore + element[1][function_name](...args) + } + } + + handleKeypress(_chunk: Buffer, key: Key, screen: Screen) { + const focusableIDs = Object.keys(screen.getFocusable()); + const focusedIndex = focusableIDs.indexOf(screen.focusedElementId); + if (key && key.name == 'escape' || key.name == "c" && key.ctrl) { + onexit(); + Deno.exit(0); + } + + if (['up', 'left'].includes(key.name ?? '') || key.name == "tab" && key.shift) { + // logs.push(`Got up key, moving focus upward ${focusedIndex} ${(focusedIndex - 1) % focusableIDs.length}`) + screen.focus(focusableIDs[(focusedIndex - 1) % focusableIDs.length]); + return screen.render() + } + if (['down', 'right'].includes(key.name ?? '') || key.name == "tab" && !key.shift) { + // logs.push(`Got down key, moving focus downward ${focusedIndex} ${(focusedIndex + 1) % focusableIDs.length}`) + screen.focus(focusableIDs[(focusedIndex + 1) % focusableIDs.length]); + return screen.render() + } + + // logs.push("pressed key, data: " + JSON.stringify(key)) + if (!screen.focusedElementId) return; + const focusedElement = screen.getFocusedElement(); + focusedElement?.onkeypres(key) + } + + getKeypressHandler(screen: Screen) { + return (chunk: Buffer, key: Key) => this.handleKeypress(chunk,key, screen); + } + + keypressHandler = this.getKeypressHandler(this) + + ready() { + process.stdin.on('keypress', this.keypressHandler); + this.render() + } + + off() { + process.stdin.off('keypress', this.keypressHandler) + } + + addElement(name: string, element: Element) { + if(this.elements.has(name)) throw new Error(); + element.screen = this; + this.elements.set(name, element); + } + + render() { + console.clear() + process.stdout.write("\u001b[2J") // use an ansi escape code to clear the screen if console.clear doesn't clear fully + this.elements.forEach(element => { + element.render() + }); + } + + getFocusable() { + return Object.fromEntries([...this.elements.entries()].filter(([_k, v]) => v.focusable)) + } + + getElements() { + return Object.fromEntries([...this.elements.entries()]) + } + + focus(id: string) { + this.elements.forEach(e => e.focused = false); + const focusElem = this.elements.get(id) as Element + focusElem.focused = true; + this.focusedElementId = id + } + + getFocusedElement(): Element|undefined { + return this.focusedElementId ? this.elements.get(this.focusedElementId) as Element : undefined + } +} diff --git a/screen/home.ts b/screen/home.ts new file mode 100644 index 0000000..0be3ef9 --- /dev/null +++ b/screen/home.ts @@ -0,0 +1,53 @@ +import { ElemType } from "../screenbuilder.ts"; +import { Screen } from "../screen.ts"; +import type { Input, Element, Text } from "../elements.ts"; +import * as client from "../client.ts" + +export default { + elements: [ + { + type: ElemType.TextElem, + id: 'home', + data: ["Loading home posts...\n", function (this: Text, text: string) { + const msgInput: Input = this.screen.elements.get("msg-input") as Input; + const inputValueHeight = msgInput.value.split("\n").length + 1; + const termHeight = process.stdout.rows; + const termWidth = process.stdout.columns; + + let splitText = this.text.split("\n"); + splitText = splitText.map(t => t.replace(new RegExp(`([^]){${termWidth}}`, "g"),"$1\n")); + splitText = splitText.join("\n").split("\n") + + splitText = splitText.slice(-(termHeight - inputValueHeight)); + + return splitText.join("\n") + }] + }, + { + type: ElemType.HR, + id: 'hr', + data: [] + }, + { + type: ElemType.InputElem, + id: 'msg-input', + data: [false, false, true] + }, + { + type: ElemType.ButtonElem, + id: 'done-btn', + data: ["Send", async function (this: Screen) { + const msgInput: Input = this.elements.get('msg-input') as Input + client.sendHome(msgInput.value); + msgInput.value = "" + this.render() + }] + } + ], + focus: "msg-input", + name: 'home', + onload (screen: Screen) { + client.setScreen(screen) + client.loadHome(screen) + } +} \ No newline at end of file diff --git a/screen/login.ts b/screen/login.ts new file mode 100644 index 0000000..bc39655 --- /dev/null +++ b/screen/login.ts @@ -0,0 +1,55 @@ +import { ElemType } from "../screenbuilder.ts"; +import { Screen } from "../screen.ts"; +import * as client from "../client.ts" +import { build } from "../screenbuilder.ts"; +import HomeScreen from "./home.ts"; + +export default { + elements: [ + { + type: ElemType.TextElem, + id: 'username-label', + data: ["Username: \n"] + }, + { + type: ElemType.InputElem, + id: 'username-input', + data: [false] + }, + { + type: ElemType.BR, + id: 'naoiuou' + }, + { + type: ElemType.TextElem, + id: 'password-label', + data: ["Password: \n"] + }, + { + type: ElemType.InputElem, + id: 'password-input', + data: [true] + }, + { + type: ElemType.BR, + id: 'faij0ifsj' + }, + { + type: ElemType.ButtonElem, + id: 'done-btn', + data: ["Done", async function (this: Screen) { + client.setScreen(this) + this.off() + this.logs.push(`clicked button`) + console.clear() + console.log("logging in...") + //@ts-ignore + await client.login(this.elements.get("username-input").value, this.elements.get("password-input").value) + build(HomeScreen); + client + }] + } + ], + focus: "username-input", + name: 'login' +} \ No newline at end of file diff --git a/screenbuilder.ts b/screenbuilder.ts new file mode 100644 index 0000000..98af374 --- /dev/null +++ b/screenbuilder.ts @@ -0,0 +1,44 @@ +// deno-lint-ignore-file no-explicit-any ban-ts-comment +import { Screen } from "./screen.ts"; +import * as elements from "./elements.ts"; + +export enum ElemType { + TextElem, + InputElem, + ButtonElem, + HR, + BR +} + +const types = { + 0: elements.Text, + 1: elements.Input, + 2: elements.Button, + 3: elements.HR, + 4: elements.BR +} + +type BuilderElem = { + type: ElemType, + id: string, + data?: any[], +} + +type Data = { + elements: BuilderElem[], + focus?: string, + name: string + onload?: (screen: Screen) => any +} + +export function build(data: Data) { + const screen = new Screen(data.name); + for (const element of data.elements) { + if (!element.data) element.data = [] + //@ts-ignore + screen.addElement(element.id, new types[element.type](...element.data)) + } + if (data.focus) screen.focus(data.focus); + screen.ready() + if (data.onload) data.onload(screen) +} \ No newline at end of file diff --git a/strftime.js b/strftime.js new file mode 100644 index 0000000..ecc3f77 --- /dev/null +++ b/strftime.js @@ -0,0 +1,92 @@ +/* Port of strftime(). Compatibility notes: + * + * %c - formatted string is slightly different + * %D - not implemented (use "%m/%d/%y" or "%d/%m/%y") + * %e - space is not added + * %E - not implemented + * %h - not implemented (use "%b") + * %k - space is not added + * %n - not implemented (use "\n") + * %O - not implemented + * %r - not implemented (use "%I:%M:%S %p") + * %R - not implemented (use "%H:%M") + * %t - not implemented (use "\t") + * %T - not implemented (use "%H:%M:%S") + * %U - not implemented + * %W - not implemented + * %+ - not implemented + * %% - not implemented (use "%") + * + * strftime() reference: + * http://man7.org/linux/man-pages/man3/strftime.3.html + * + * Day of year (%j) code based on Joe Orost's answer: + * http://stackoverflow.com/questions/8619879/javascript-calculate-the-day-of-the-year-1-366 + * + * Week number (%V) code based on Taco van den Broek's prototype: + * http://techblog.procurios.nl/k/news/view/33796/14863/calculate-iso-8601-week-and-year-in-javascript.html + */ +export default function strftime(sFormat, date) { + if (!(date instanceof Date)) date = new Date(); + let nDay = date.getDay(), + nDate = date.getDate(), + nMonth = date.getMonth(), + nYear = date.getFullYear(), + nHour = date.getHours(), + aDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + aMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + aDayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], + isLeapYear = function () { + return (nYear % 4 === 0 && nYear % 100 !== 0) || nYear % 400 === 0; + }, + getThursday = function () { + let target = new Date(date); + target.setDate(nDate - ((nDay + 6) % 7) + 3); + return target; + }, + zeroPad = function (nNum, nPad) { + return ('' + (Math.pow(10, nPad) + nNum)).slice(1); + }; + return sFormat.replace(/%[a-z]/gi, function (sMatch) { + return { + '%a': aDays[nDay].slice(0, 3), + '%A': aDays[nDay], + '%b': aMonths[nMonth].slice(0, 3), + '%B': aMonths[nMonth], + '%c': date.toUTCString(), + '%C': Math.floor(nYear / 100), + '%d': zeroPad(nDate, 2), + '%e': nDate, + '%F': date.toISOString().slice(0, 10), + '%G': getThursday().getFullYear(), + '%g': ('' + getThursday().getFullYear()).slice(2), + '%H': zeroPad(nHour, 2), + '%I': zeroPad((nHour + 11) % 12 + 1, 2), + '%j': zeroPad(aDayCount[nMonth] + nDate + ((nMonth > 1 && isLeapYear()) ? 1 : 0), 3), + '%k': '' + nHour, + '%l': (nHour + 11) % 12 + 1, + '%m': zeroPad(nMonth + 1, 2), + '%M': zeroPad(date.getMinutes(), 2), + '%p': (nHour < 12) ? 'AM' : 'PM', + '%P': (nHour < 12) ? 'am' : 'pm', + '%s': Math.round(date.getTime() / 1000), + '%S': zeroPad(date.getSeconds(), 2), + '%u': nDay || 7, + '%V': (function () { + let target = getThursday(), + n1stThu = target.valueOf(); + target.setMonth(0, 1); + let nJan1 = target.getDay(); + if (nJan1 !== 4) target.setMonth(0, 1 + ((4 - nJan1) + 7) % 7); + return zeroPad(1 + Math.ceil((n1stThu - target) / 604800000), 2); + })(), + '%w': '' + nDay, + '%x': date.toLocaleDateString(), + '%X': date.toLocaleTimeString(), + '%y': ('' + nYear).slice(2), + '%Y': nYear, + '%z': date.toTimeString().replace(/.+GMT([+-]\d+).+/, '$1'), + '%Z': date.toTimeString().replace(/.+\((.+?)\)$/, '$1') + }[sMatch] || sMatch; + }); +} \ No newline at end of file diff --git a/v2/client.ts b/v2/client.ts deleted file mode 100644 index 3e09f7e..0000000 --- a/v2/client.ts +++ /dev/null @@ -1,67 +0,0 @@ - -import { Screen } from "./screen.ts"; -import type { Text } from "./elements.ts"; -import strftime from "./strftime.js"; - -export let token: string; -export let account; -export const connection = new WebSocket("wss://api.meower.org/v0/cloudlink?v=1") - -export let home: any[] = []; - -let screen: Screen; - -export function setScreen(screenN: Screen) { - screen = screenN -} - -export async function login(username: string, password: string) { - screen.logs.push(`logging in as ${username}`) - const authr = await (await fetch("https://api.meower.org/auth/login", { - method: "post", - headers: { - "content-type": "application/json" - }, - body: JSON.stringify({ - username, - password - }) - })).json(); - screen.logs.push(`got auth response (${authr.error ? "error" : "not error"})`) - token = authr.token; - account = authr.account; - screen.logs.push(`Got token ${token}`); - connection.addEventListener("message", (ev) => { - const data = JSON.parse(ev.data.toString()); - screen.logs.push("INC: " + JSON.stringify(data)) - if(data.cmd != "post") return; - home.push(data.val); - const textHome: string[] = home.map(p => `[${strftime("%H:%M:%S", new Date(p.t.e * 1000))}] ${p.u}: ${p.p}`); - const homeElem: Text = screen.elements.get("home") as Text; - homeElem.text = textHome.join("\n")+"\n"; - screen.render() - }) -} - -export async function loadHome(screen: Screen) { - home = (await (await fetch("https://api.meower.org/home")).json()).autoget.reverse(); - const textHome: string[] = home.map(p => `[${strftime("%H:%M:%S")}] ${p.u}: ${p.p}`); - const homeElem: Text = screen.elements.get("home") as Text; - homeElem.text = textHome.join("\n")+"\n"; - screen.logs.push("loadHome ran", home.length.toString()) - screen.render() -} - -export async function sendHome(post:string) { - screen.logs.push("sendHome ran", home.length.toString()) - fetch("https://api.meower.org/home", { - method: "POST", - headers: { - token, - "content-type": "application/json" - }, - body: JSON.stringify({ - content: post - }) - }).then(async r=>screen.logs.push(`Got send response (${r.status} ${r.statusText}) ${await r.text()}`)) -} diff --git a/v2/elements.ts b/v2/elements.ts deleted file mode 100644 index c364930..0000000 --- a/v2/elements.ts +++ /dev/null @@ -1,124 +0,0 @@ -import chalk from "chalk"; -import { type Key } from 'node:readline'; -import { type Screen } from "./screen.ts"; - -export abstract class Element { - focusable: boolean = false; - focused: boolean = false; - // screen property is asigned by the addElement function of Scren - //@ts-ignore - screen: Screen; - abstract render(): void; - onkeypres(key: Key): void {}; -} - -export class Text extends Element { - text: string; - br: boolean; - - processText: (text: string) => string; - - constructor(text: string, processText = (t:string)=>t) { - super(); - this.text = text; - this.processText = processText - } - render() { - process.stdout.write(this.processText(this.text)) - } -} - -export class HR extends Element { - constructor() { - super() - } - render(): void { - console.log('-'.repeat(process.stdout.columns)) - } -} - -export class BR extends Element { - constructor() { - super() - } - render(): void { - console.log() - } -} - -export class Input extends Element { - focusable: boolean = true; - value: string = ""; - - textarea = false; - br = false; - - isPassword: boolean = false; - - render(): void { - let text = this.value - if (this.isPassword) text = text.replace(/[^]/g, '*'); - if (this.focused) text += "_" - process.stdout.write(text) - } - - onkeypres(key: Key): void { - //@ts-ignore - if (key.meta || key.code || ["return", "backspace"].includes(key.name)) { - switch (key.name) { - case "return": - if(this.textarea) { - this.value += '\n' - break; - } - this.focused = false; - const focusableIDs = Object.keys(this.screen.getFocusable()); - const focusedIndex = focusableIDs.indexOf(this.screen.focusedElementId); - this.screen.focus(focusableIDs[(focusedIndex + 1) % focusableIDs.length]); - break; - - case "backspace": - const prevValue = '' + this.value - // logs.push(`doing backspace : before ${prevValue}, after ${prevValue.substring(0, prevValue.length - 1)} : 0-${prevValue.length - 1}`) - this.value = prevValue.substring(0, prevValue.length - 1) - break; - } - this.screen.render() - return; - } - // check if the character ism't typable - // checks: - // sequience length > 1 (eg ^[ ^[[A) - // key name != sequence (and if name exists) - //@ts-ignore - if (!key.sequence || key.sequence.length > 1 || key.name != key.sequence?.toLowerCase() && !["space"].includes(key.name) && key.name) return; - this.value += key.sequence; - this.screen.render() - } - - constructor(isPassword: boolean = false, br: boolean = false, textarea: boolean = false) { - super() - this.br = br - this.isPassword = isPassword; - this.textarea = textarea; - } -} - -export class Button extends Text { - focusable: boolean = true; - onclick: ()=>void; - constructor (text: string, onclick=()=>{}) { - super(text); - this.onclick = onclick - } - render(): void { - process.stdout.write(`(${(this.focused ? chalk.bgWhite : (a:string)=>a)(this.text)})`) - } - - onkeypres(key: Key): void { - //@ts-ignore - if (["return", "space"].includes(key.name)) { - this.onclick.call(this.screen) - } - } -} diff --git a/v2/logger.ts b/v2/logger.ts deleted file mode 100644 index 641a406..0000000 --- a/v2/logger.ts +++ /dev/null @@ -1,24 +0,0 @@ -class Log { - time: number = Number(new Date()); - data: string = ""; - constructor (data: string, time?: number) { - this.data = data; - if(time) this.time = time; - } -} - -class Logger { - logs: Log[] = []; - - constructor () { - - } - - log (data: string) { - this.logs.push(new Log(data)) - } - - dump (): string[] { - return this.logs.map(log => ``) - } -} \ No newline at end of file diff --git a/v2/screen.ts b/v2/screen.ts deleted file mode 100644 index 5e09d57..0000000 --- a/v2/screen.ts +++ /dev/null @@ -1,101 +0,0 @@ -import type { Element, Input, Text, Button } from "./elements.ts" - -const logs: string[] = []; - -function onexit() { - console.clear() - console.log("\nQuitting meower CL") - for (const log of logs) { - console.log(log) - } -} - -export class Screen { - elements: Map = new Map(); - name: string; - focusedElementId: string = ''; - logs = logs - - constructor(name: string) { - this.name = name; - } - - call(function_name:string, ...args:any) { - for (const element of this.elements) { - element[1][function_name](...args) - } - } - - handleKeypress(chunk: any, key: any, screen: Screen) { - const focusableIDs = Object.keys(screen.getFocusable()); - const focusedIndex = focusableIDs.indexOf(screen.focusedElementId); - if (key && key.name == 'escape' || key.name == "c" && key.ctrl) { - onexit(); - process.exit(); - } - - if (['up', 'left'].includes(key.name) || key.name == "tab" && key.shift) { - // logs.push(`Got up key, moving focus upward ${focusedIndex} ${(focusedIndex - 1) % focusableIDs.length}`) - screen.focus(focusableIDs[(focusedIndex - 1) % focusableIDs.length]); - return screen.render() - } - if (['down', 'right'].includes(key.name) || key.name == "tab" && !key.shift) { - // logs.push(`Got down key, moving focus downward ${focusedIndex} ${(focusedIndex + 1) % focusableIDs.length}`) - screen.focus(focusableIDs[(focusedIndex + 1) % focusableIDs.length]); - return screen.render() - } - - // logs.push("pressed key, data: " + JSON.stringify(key)) - if (!screen.focusedElementId) return; - const focusedElement = screen.getFocusedElement(); - focusedElement?.onkeypres(key) - } - - getKeypressHandler(screen: Screen) { - return (chunk: any, key: any) => this.handleKeypress(chunk,key, screen); - } - - keypressHandler = this.getKeypressHandler(this) - - ready() { - process.stdin.on('keypress', this.keypressHandler); - this.render() - } - - off() { - process.stdin.off('keypress', this.keypressHandler) - } - - addElement(name: string, element: Element) { - if(this.elements.has(name)) throw new Error(); - element.screen = this; - this.elements.set(name, element); - } - - render() { - console.clear() - process.stdout.write("\u001b[2J") // use an ansi escape code to clear the screen if console.clear doesn't clear fully - this.elements.forEach(element => { - element.render() - }); - } - - getFocusable() { - return Object.fromEntries([...this.elements.entries()].filter(([k, v]) => v.focusable)) - } - - getElements() { - return Object.fromEntries([...this.elements.entries()]) - } - - focus(id: string) { - this.elements.forEach(e => e.focused = false); - const focusElem = this.elements.get(id) as Element - focusElem.focused = true; - this.focusedElementId = id - } - - getFocusedElement(): Element|undefined { - return this.focusedElementId ? this.elements.get(this.focusedElementId) as Element : undefined - } -} diff --git a/v2/screen/home.ts b/v2/screen/home.ts deleted file mode 100644 index 0be3ef9..0000000 --- a/v2/screen/home.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ElemType } from "../screenbuilder.ts"; -import { Screen } from "../screen.ts"; -import type { Input, Element, Text } from "../elements.ts"; -import * as client from "../client.ts" - -export default { - elements: [ - { - type: ElemType.TextElem, - id: 'home', - data: ["Loading home posts...\n", function (this: Text, text: string) { - const msgInput: Input = this.screen.elements.get("msg-input") as Input; - const inputValueHeight = msgInput.value.split("\n").length + 1; - const termHeight = process.stdout.rows; - const termWidth = process.stdout.columns; - - let splitText = this.text.split("\n"); - splitText = splitText.map(t => t.replace(new RegExp(`([^]){${termWidth}}`, "g"),"$1\n")); - splitText = splitText.join("\n").split("\n") - - splitText = splitText.slice(-(termHeight - inputValueHeight)); - - return splitText.join("\n") - }] - }, - { - type: ElemType.HR, - id: 'hr', - data: [] - }, - { - type: ElemType.InputElem, - id: 'msg-input', - data: [false, false, true] - }, - { - type: ElemType.ButtonElem, - id: 'done-btn', - data: ["Send", async function (this: Screen) { - const msgInput: Input = this.elements.get('msg-input') as Input - client.sendHome(msgInput.value); - msgInput.value = "" - this.render() - }] - } - ], - focus: "msg-input", - name: 'home', - onload (screen: Screen) { - client.setScreen(screen) - client.loadHome(screen) - } -} \ No newline at end of file diff --git a/v2/screen/login.ts b/v2/screen/login.ts deleted file mode 100644 index bc39655..0000000 --- a/v2/screen/login.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { ElemType } from "../screenbuilder.ts"; -import { Screen } from "../screen.ts"; -import * as client from "../client.ts" -import { build } from "../screenbuilder.ts"; -import HomeScreen from "./home.ts"; - -export default { - elements: [ - { - type: ElemType.TextElem, - id: 'username-label', - data: ["Username: \n"] - }, - { - type: ElemType.InputElem, - id: 'username-input', - data: [false] - }, - { - type: ElemType.BR, - id: 'naoiuou' - }, - { - type: ElemType.TextElem, - id: 'password-label', - data: ["Password: \n"] - }, - { - type: ElemType.InputElem, - id: 'password-input', - data: [true] - }, - { - type: ElemType.BR, - id: 'faij0ifsj' - }, - { - type: ElemType.ButtonElem, - id: 'done-btn', - data: ["Done", async function (this: Screen) { - client.setScreen(this) - this.off() - this.logs.push(`clicked button`) - console.clear() - console.log("logging in...") - //@ts-ignore - await client.login(this.elements.get("username-input").value, this.elements.get("password-input").value) - build(HomeScreen); - client - }] - } - ], - focus: "username-input", - name: 'login' -} \ No newline at end of file diff --git a/v2/screenbuilder.ts b/v2/screenbuilder.ts deleted file mode 100644 index e8ce587..0000000 --- a/v2/screenbuilder.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Screen } from "./screen.ts"; -import * as elements from "./elements.ts"; - -export enum ElemType { - TextElem, - InputElem, - ButtonElem, - HR, - BR -} - -const types = { - 0: elements.Text, - 1: elements.Input, - 2: elements.Button, - 3: elements.HR, - 4: elements.BR -} - -type BuilderElem = { - type: ElemType, - id: string, - data?: any[], -} - -type Data = { - elements: BuilderElem[], - focus?: string, - name: string - onload?: (screen: Screen) => any -} - -export function build(data: Data) { - const screen = new Screen(data.name); - for (const element of data.elements) { - if (!element.data) element.data = [] - //@ts-ignore - screen.addElement(element.id, new types[element.type](...element.data)) - } - if (data.focus) screen.focus(data.focus); - screen.ready() - if (data.onload) data.onload(screen) -} \ No newline at end of file diff --git a/v2/strftime.js b/v2/strftime.js deleted file mode 100644 index ecc3f77..0000000 --- a/v2/strftime.js +++ /dev/null @@ -1,92 +0,0 @@ -/* Port of strftime(). Compatibility notes: - * - * %c - formatted string is slightly different - * %D - not implemented (use "%m/%d/%y" or "%d/%m/%y") - * %e - space is not added - * %E - not implemented - * %h - not implemented (use "%b") - * %k - space is not added - * %n - not implemented (use "\n") - * %O - not implemented - * %r - not implemented (use "%I:%M:%S %p") - * %R - not implemented (use "%H:%M") - * %t - not implemented (use "\t") - * %T - not implemented (use "%H:%M:%S") - * %U - not implemented - * %W - not implemented - * %+ - not implemented - * %% - not implemented (use "%") - * - * strftime() reference: - * http://man7.org/linux/man-pages/man3/strftime.3.html - * - * Day of year (%j) code based on Joe Orost's answer: - * http://stackoverflow.com/questions/8619879/javascript-calculate-the-day-of-the-year-1-366 - * - * Week number (%V) code based on Taco van den Broek's prototype: - * http://techblog.procurios.nl/k/news/view/33796/14863/calculate-iso-8601-week-and-year-in-javascript.html - */ -export default function strftime(sFormat, date) { - if (!(date instanceof Date)) date = new Date(); - let nDay = date.getDay(), - nDate = date.getDate(), - nMonth = date.getMonth(), - nYear = date.getFullYear(), - nHour = date.getHours(), - aDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - aMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - aDayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], - isLeapYear = function () { - return (nYear % 4 === 0 && nYear % 100 !== 0) || nYear % 400 === 0; - }, - getThursday = function () { - let target = new Date(date); - target.setDate(nDate - ((nDay + 6) % 7) + 3); - return target; - }, - zeroPad = function (nNum, nPad) { - return ('' + (Math.pow(10, nPad) + nNum)).slice(1); - }; - return sFormat.replace(/%[a-z]/gi, function (sMatch) { - return { - '%a': aDays[nDay].slice(0, 3), - '%A': aDays[nDay], - '%b': aMonths[nMonth].slice(0, 3), - '%B': aMonths[nMonth], - '%c': date.toUTCString(), - '%C': Math.floor(nYear / 100), - '%d': zeroPad(nDate, 2), - '%e': nDate, - '%F': date.toISOString().slice(0, 10), - '%G': getThursday().getFullYear(), - '%g': ('' + getThursday().getFullYear()).slice(2), - '%H': zeroPad(nHour, 2), - '%I': zeroPad((nHour + 11) % 12 + 1, 2), - '%j': zeroPad(aDayCount[nMonth] + nDate + ((nMonth > 1 && isLeapYear()) ? 1 : 0), 3), - '%k': '' + nHour, - '%l': (nHour + 11) % 12 + 1, - '%m': zeroPad(nMonth + 1, 2), - '%M': zeroPad(date.getMinutes(), 2), - '%p': (nHour < 12) ? 'AM' : 'PM', - '%P': (nHour < 12) ? 'am' : 'pm', - '%s': Math.round(date.getTime() / 1000), - '%S': zeroPad(date.getSeconds(), 2), - '%u': nDay || 7, - '%V': (function () { - let target = getThursday(), - n1stThu = target.valueOf(); - target.setMonth(0, 1); - let nJan1 = target.getDay(); - if (nJan1 !== 4) target.setMonth(0, 1 + ((4 - nJan1) + 7) % 7); - return zeroPad(1 + Math.ceil((n1stThu - target) / 604800000), 2); - })(), - '%w': '' + nDay, - '%x': date.toLocaleDateString(), - '%X': date.toLocaleTimeString(), - '%y': ('' + nYear).slice(2), - '%Y': nYear, - '%z': date.toTimeString().replace(/.+GMT([+-]\d+).+/, '$1'), - '%Z': date.toTimeString().replace(/.+\((.+?)\)$/, '$1') - }[sMatch] || sMatch; - }); -} \ No newline at end of file -- cgit 1.4.1-2-gfad0