From: xangelo Date: Fri, 29 Sep 2023 16:12:39 +0000 (-0400) Subject: chore(release): 0.4.0 X-Git-Tag: v0.4.0 X-Git-Url: https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff_plain;h=v0.4.0;hp=v0.3.6;ds=sidebyside chore(release): 0.4.0 --- diff --git a/CHANGELOG.md b/CHANGELOG.md index c9a78dc..5c6ff07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [0.4.0](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.4.0;hp=v0.3.6;ds=sidebyside) (2023-09-29) + + +### ⚠ BREAKING CHANGES + +* dungeon traversal + +### Features + +* cleanup chat commands 074d6ad +* dungeon traversal 2ec43df +* min level for all locations 2be0160 +* psql based event system 43f0bc3 + + +### Bug Fixes + +* auto-enter dungeon if you are in it dfa62a7 +* remove log of 0 events being flushed 552c744 + ### [0.3.6](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.3.6;hp=v0.3.5;ds=sidebyside) (2023-09-06) diff --git a/data/dungeons/storage_cellar.json b/data/dungeons/storage_cellar.json new file mode 100644 index 0000000..ece9763 --- /dev/null +++ b/data/dungeons/storage_cellar.json @@ -0,0 +1,224 @@ +{ + "passages": [ + { + "text": "You stand at the bottom of the stairwell leading outside the cellar. You can make out a faint square of light above indicating the hatch that doesn't sit quite as flush as it once did.\n\n\n[[Head toward the torch->w1]]\n[[Forward->n1]]\n[[Head away from the torch->e1]]\n{{visit}}\n{{1}}\nYou climb down old wooden stairs into the dark cellar. The only light seems to be from the hatch you just climbed through.\n\n\"I'll close this up, otherwise one of those darned rats might get out\" Varun says. \n\nYou hear him grunt as he lifts the hatch and drops it into place. \n\nIt takes a minute for your eyes to adjust but soon you notice the torches on the wall.. it's not as dark down here as you imagined...\n{{/1}}\n{{/visit}}", + "links": [ + { + "name": "Head toward the torch", + "link": "w1", + "pid": "3" + }, + { + "name": "Forward", + "link": "n1", + "pid": "2" + }, + { + "name": "Head away from the torch", + "link": "e1", + "pid": "6" + } + ], + "props": { + "visit": { + "1": "You climb down old wooden stairs into the dark cellar. The only light seems to be from the hatch you just climbed through.\"I'll close this up, otherwise one of those darned rats might get out\" Varun says. You hear him grunt as he lifts the hatch and drops it into place. It takes a minute for your eyes to adjust but soon you notice the torches on the wall.. it's not as dark down here as you imagined..." + } + }, + "name": "start", + "pid": "1", + "position": { + "x": "800", + "y": "600" + } + }, + { + "text": " A few feet in front of the hatch the ground is fairly compacted... covered in footsteps upon footsteps. This must be the route Varun's helpers take to retrieve the grain. \n\n\n[[Step to the Left->w2n2]]\n[[Back toward Hatch->start]]\n[[Keep going forward->n2]]\n[[Head right->e2n2]]", + "links": [ + { + "name": "Step to the Left", + "link": "w2n2", + "pid": "4" + }, + { + "name": "Back toward Hatch", + "link": "start", + "pid": "1" + }, + { + "name": "Keep going forward", + "link": "n2", + "pid": "5" + }, + { + "name": "Head right", + "link": "e2n2", + "pid": "7" + } + ], + "name": "n1", + "pid": "2", + "position": { + "x": "800", + "y": "400" + } + }, + { + "text": "You step toward the torch. The light isn't bright enough to light up much... but you can see that the walls look a bit damp. Doesn't seem like ideal food storage conditions...\n\n\n\n[[Step forward along the wall->w2n2]]\n[[Back toward the hatch->start]]", + "links": [ + { + "name": "Step forward along the wall", + "link": "w2n2", + "pid": "4" + }, + { + "name": "Back toward the hatch", + "link": "start", + "pid": "1" + } + ], + "name": "w1", + "pid": "3", + "position": { + "x": "600", + "y": "600" + } + }, + { + "text": "You're not that far from the torch but already it feels like this area is getting no light. Your foot snags against something.\n\nInspecting closer you see the torn rags of some kind of sack...\n\nIt looks like it fell off the wooden crates in front of you\n\n[[Back toward the torch->w1]]\n[[Step to the right->n1]]\n{{fight}}\n{{monster_id}}2{{/monster_id}}\n{{one_time}}true{{/one_time}}\n{{/fight}}", + "links": [ + { + "name": "Back toward the torch", + "link": "w1", + "pid": "3" + }, + { + "name": "Step to the right", + "link": "n1", + "pid": "2" + } + ], + "props": { + "fight": { + "monster_id": "2", + "one_time": "true" + } + }, + "name": "w2n2", + "pid": "4", + "position": { + "x": "600", + "y": "400" + } + }, + { + "text": "You can see that a path has been cleared between the wooden crates. The crates have dug into the floor as they were pushed around. \n\nThe slain rat lies on the floor. \n\n[[Head forward->n3]]\n[[Head back->n1]]\n{{fight}}\n{{monster_id}}2{{/monster_id}}\n{{one_time}}true{{/one_time}}\n{{/fight}}", + "links": [ + { + "name": "Head forward", + "link": "n3", + "pid": "8" + }, + { + "name": "Head back", + "link": "n1", + "pid": "2" + } + ], + "props": { + "fight": { + "monster_id": "2", + "one_time": "true" + } + }, + "name": "n2", + "pid": "5", + "position": { + "x": "800", + "y": "200" + } + }, + { + "text": "As you step away from the torch, you're aware of how cold the cellar actually is. It's not that big, but the light barely reaches into this corner.\n\n\n[[Investigate the noise->e2n2]]\n[[Head back to the hatch->start]]\n{{visit}}\n\t{{1}}You hear some skittering up ahead{{/1}}\n{{/visit}}", + "links": [ + { + "name": "Investigate the noise", + "link": "e2n2", + "pid": "7" + }, + { + "name": "Head back to the hatch", + "link": "start", + "pid": "1" + } + ], + "props": { + "visit": { + "1": "You hear some skittering up ahead" + } + }, + "name": "e1", + "pid": "6", + "position": { + "x": "1000", + "y": "600" + } + }, + { + "text": "You see some bags in the corner.. and also the corpse of that Rat you dealt wtih.\n\nIn front of you you can see stacks of wooden crates, often topped by a burlap sack of some kind.\n\n\n[[Head back the way you came->e1]]\n[[Head toward the hatch->n1]]\n{{fight}}\n{{monster_id}}2{{/monster_id}}\n{{one_time}}true{{/one_time}}\n{{/fight}}\n{{visit}}\n{{1}}\nThat rat was way too big to be a regular rat... \n{{/1}}\n{{/visit}}", + "links": [ + { + "name": "Head back the way you came", + "link": "e1", + "pid": "6" + }, + { + "name": "Head toward the hatch", + "link": "n1", + "pid": "2" + } + ], + "props": { + "fight": { + "monster_id": "2", + "one_time": "true" + }, + "visit": { + "1": "That rat was way too big to be a regular rat... " + } + }, + "name": "e2n2", + "pid": "7", + "position": { + "x": "1000", + "y": "400" + } + }, + { + "text": "You reach the wall at the other end of the cellar.. you don't hear anything further.. maybe it's been cleared out?\n\n\n\n{{end}}true{{/end}}\n{{rewards}}\n\t{{base}}\n \t{{exp}}20{{/exp}}\n \t{{gold}}60{{/gold}}\n {{/base}}\n\t{{per_kill_bonus}}\n \t{{exp}}10{{/exp}}\n {{gold}}10{{/gold}}\n {{/per_kill_bonus}}\n{{/rewards}}", + "props": { + "end": "true", + "rewards": { + "base": { + "exp": "20", + "gold": "60" + }, + "per_kill_bonus": { + "exp": "10", + "gold": "10" + } + } + }, + "name": "n3", + "pid": "8", + "position": { + "x": "800", + "y": "0" + } + } + ], + "name": "Storage Cellar", + "startnode": "1", + "creator": "Twine", + "creator-version": "2.7.1", + "ifid": "0F34ADD6-2DC1-4A8C-9464-008386845215" +} diff --git a/migrations/20230908160725_dungeons.ts b/migrations/20230908160725_dungeons.ts new file mode 100644 index 0000000..73da240 --- /dev/null +++ b/migrations/20230908160725_dungeons.ts @@ -0,0 +1,44 @@ +import { Knex } from "knex"; + + +export async function up(knex: Knex): Promise { + return knex.schema.createTable('dungeons', function(table) { + table.string('id').primary().defaultTo(knex.raw('uuid_generate_v4()')); + table.string('name'); + table.uuid('starting_room'); + }).createTable('dungeon_rooms', function(table) { + table.uuid('id').defaultTo(knex.raw('uuid_generate_v4()')).primary(); + table.uuid('dungeon_id'); + table.text('description'); + table.json('exits').defaultTo(knex.raw("'[]'::json")); + table.json('settings').defaultTo('{}'); + }).createTable('dungeon_things', function(table) { + table.uuid('room_id'); + table.uuid('id').defaultTo(knex.raw('uuid_generate_v4()')).primary(); + table.string('name'); + table.json('properties').defaultTo({}) + }).createTable('dungeon_players', function(table) { + table.uuid('player_id').primary(); + table.uuid('dungeon_id'); + table.uuid('current_room_id'); + table.uuid('target_room_id'); // only used when movement is interrupted by a fight + }).createTable('dungeon_state', function(table) { + table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()')); + table.uuid('player_id'); + table.uuid('dungeon_id'); + table.string('event_name'); + table.json('event_props'); + table.timestamp('create_date').defaultTo(knex.raw('NOW()')) + table.index(['player_id', 'dungeon_id']); + table.index(['player_id', 'dungeon_id', 'event_name']); + }) +} + + +export async function down(knex: Knex): Promise { + return knex.schema.dropTable('dungeon_rooms') + .dropTable('dungeon_things') + .dropTable('dungeon_players') + .dropTable('dungeon_state') + .dropTable('dungeons'); +} diff --git a/migrations/20230915162829_events.ts b/migrations/20230915162829_events.ts new file mode 100644 index 0000000..b34437b --- /dev/null +++ b/migrations/20230915162829_events.ts @@ -0,0 +1,20 @@ +import { Knex } from "knex"; + + +export async function up(knex: Knex): Promise { + return knex.schema.createTable('events', function(table) { + table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()')); + table.string('event_name'); + table.uuid('player_id'); + table.integer('value').defaultTo(1); + table.string('app_version'); + table.json('props').defaultTo('{}'); + table.timestamp('created').defaultTo(knex.raw('NOW()')) + }); +} + + +export async function down(knex: Knex): Promise { + return knex.schema.dropTable('events'); +} + diff --git a/package-lock.json b/package-lock.json index 312fb12..5125160 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rising-legends", - "version": "0.3.6", + "version": "0.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "rising-legends", - "version": "0.3.6", + "version": "0.4.0", "dependencies": { "@honeycombio/opentelemetry-node": "^0.4.0", "@opentelemetry/auto-instrumentations-node": "^0.37.0", @@ -39,9 +39,11 @@ "@types/jest": "^29.5.3", "@types/jquery": "^3.5.16", "@types/lodash": "^4.14.195", + "@types/marked": "^5.0.1", "husky": "^8.0.0", "jest": "^29.6.2", "jquery": "^3.7.0", + "marked": "^9.0.0", "nodemon": "^2.0.20", "standard-version": "^9.5.0", "ts-jest": "^29.1.1", @@ -4320,6 +4322,12 @@ "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, + "node_modules/@types/marked": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-5.0.1.tgz", + "integrity": "sha512-Y3pAUzHKh605fN6fvASsz5FDSWbZcs/65Q6xYRmnIP9ZIYz27T4IOmXfH9gWJV1dpi7f1e7z7nBGUTx/a0ptpA==", + "dev": true + }, "node_modules/@types/memcached": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/@types/memcached/-/memcached-2.2.7.tgz", @@ -9025,6 +9033,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/marked": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-9.0.0.tgz", + "integrity": "sha512-37yoTpjU+TSXb9OBYY5n78z/CqXh76KiQj9xsKxEdztzU9fRLmbWO5YqKxgCVGKlNdexppnbKTkwB3RipVri8w==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 16" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -15110,6 +15130,12 @@ "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, + "@types/marked": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-5.0.1.tgz", + "integrity": "sha512-Y3pAUzHKh605fN6fvASsz5FDSWbZcs/65Q6xYRmnIP9ZIYz27T4IOmXfH9gWJV1dpi7f1e7z7nBGUTx/a0ptpA==", + "dev": true + }, "@types/memcached": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/@types/memcached/-/memcached-2.2.7.tgz", @@ -18696,6 +18722,12 @@ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true }, + "marked": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-9.0.0.tgz", + "integrity": "sha512-37yoTpjU+TSXb9OBYY5n78z/CqXh76KiQj9xsKxEdztzU9fRLmbWO5YqKxgCVGKlNdexppnbKTkwB3RipVri8w==", + "dev": true + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", diff --git a/package.json b/package.json index 3c242fc..7c8a2eb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "rising-legends", "private": true, - "version": "0.3.6", + "version": "0.4.0", "scripts": { "up": "npx prisma migrate dev --name \"init\"", "start": "pm2 start dist/server/api.js", @@ -12,7 +12,7 @@ "seed": "npx ts-node ./node_modules/knex/bin/cli.js seed:run", "seed:prod": "NODE_ENV=production npm run seed", "dev:client": "npx webpack -w", - "dev:server": "npx nodemon src/server/api.ts", + "dev": "npx nodemon src/server/api.ts", "prepare": "husky install", "release": "npx standard-version && npm run copy-changelog", "copy-changelog": "cp ./CHANGELOG.md ~/repos/xangelo.ca/static/", @@ -29,9 +29,11 @@ "@types/jest": "^29.5.3", "@types/jquery": "^3.5.16", "@types/lodash": "^4.14.195", + "@types/marked": "^5.0.1", "husky": "^8.0.0", "jest": "^29.6.2", "jquery": "^3.7.0", + "marked": "^9.0.0", "nodemon": "^2.0.20", "standard-version": "^9.5.0", "ts-jest": "^29.1.1", diff --git a/public/assets/bundle.js b/public/assets/bundle.js index 696b7fa..f2ca3ad 100644 --- a/public/assets/bundle.js +++ b/public/assets/bundle.js @@ -1 +1 @@ -(()=>{var e={802:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(804)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},804:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},669:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(231)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},231:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},618:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(224)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},224:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},628:function(e,t,s){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s);var r=Object.getOwnPropertyDescriptor(t,s);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[s]}}),Object.defineProperty(e,n,r)}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var s in e)"default"!==s&&Object.prototype.hasOwnProperty.call(e,s)&&n(t,e,s);return r(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.authToken=void 0;const i=s(46),a=s(182),c=o(s(454));function u(e,t=document){return t.querySelector(e)}function h(e,t=document){return Array.from(t.querySelectorAll(e))}function l(){return localStorage.getItem("authToken")||""}function d(){const e=p.gradientName(),t=u("body");let s;t.classList.value=e,t.classList.add(p.getTimePeriod()),s=p.get24Hour()>=5&&p.get24Hour()<9?"morning":p.get24Hour()>=9&&p.get24Hour()<17?"afternoon":p.get24Hour()>=17&&p.get24Hour()<20?"evening":"night",u("#time-of-day").innerHTML=` ${p.getHour()}${p.getAmPm()}`}t.authToken=l;const p=new a.TimeManager,f=(0,i.io)({extraHeaders:{"x-authtoken":l()}});d(),setInterval(d,6e4),f.on("connect",(()=>{console.log(`Connected: ${f.id}`)})),f.on("authToken",(e=>{console.log(`recv auth token ${e}`),localStorage.getItem("authToken")!==e&&(localStorage.setItem("authToken",e),window.location.reload())})),f.on("status",(e=>u("#server-stats").innerHTML=e)),f.on("chat",(function(e){u("#chat-messages").insertAdjacentHTML("beforeend",e),u("#chat-messages").scrollTop=u("#chat-messages").scrollHeight})),f.on("ready",(function(){console.log("Server connection verified"),h("nav a")[3].click()})),h("nav a").forEach((e=>{e.addEventListener("click",(e=>{const t=e.target;h("a",t.closest("nav")).forEach((e=>{e.classList.remove("active")})),t.classList.add("active");const s=u(t.getAttribute("hx-target").toString());Array.from(s.parentElement.children).forEach((e=>{e.classList.remove("active")})),s.classList.add("active")}))})),u("body").addEventListener("click",(e=>{var t;const s=e.target;if(s.parentElement.classList.contains("filter")){Array.from(s.parentElement.children).forEach((e=>e.classList.remove("active"))),s.classList.add("active");const e=s.getAttribute("data-filter"),t=u(`.filter-result[data-filter="${e}"]`,s.closest(".filter-container"));t&&Array.from(t.parentElement.children).forEach((t=>{t.getAttribute("data-filter")===e?(t.classList.remove("hidden"),t.classList.add("active")):(t.classList.add("hidden"),t.classList.remove("active"))}))}"dialog"===s.getAttribute("formmethod")&&"cancel"===s.getAttribute("value")&&(null===(t=s.closest("dialog"))||void 0===t||t.close())}));const g=new MutationObserver(((e,t)=>{const s={modal:!1,alert:!1};e.forEach((e=>{switch(e.target.id){case"modal-wrapper":s.modal=!0;break;case"alerts":s.alert=!0}})),s.modal&&u("#modal-wrapper").children.length&&h("#modal-wrapper dialog").forEach((e=>{e.open||e.showModal()})),s.alert&&u("#alerts").children.length&&h("#alerts .alert").forEach((e=>{if(!e.getAttribute("data-dismiss-at")){const t=Date.now()+c.ALERT_DISPLAY_LENGTH;e.setAttribute("data-dismiss-at",t.toString()),setTimeout((()=>{e.remove()}),c.ALERT_DISPLAY_LENGTH)}}))}));g.observe(u("#modal-wrapper"),{childList:!0}),g.observe(u("#alerts"),{childList:!0}),document.body.addEventListener("htmx:configRequest",(function(e){e.detail.headers["x-authtoken"]=l()})),document.body.addEventListener("htmx:load",(function(e){h(".disabled[data-block]").forEach((e=>{const t=parseInt(e.getAttribute("data-block")||"0");if(t>Date.now()){const s=t-Date.now();setTimeout((()=>{e.removeAttribute("disabled")}),s)}else e.removeAttribute("disabled")}))})),document.body.addEventListener("htmx:beforeSwap",(function(e){"chat-form"===e.target.id?u("#message").value="":"logout"===e.detail.serverResponse&&(localStorage.removeItem("authToken"),window.location.reload())}))},454:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ALERT_DISPLAY_LENGTH=t.STEP_DELAY=t.FIGHT_ATTACK_DELAY=void 0,t.FIGHT_ATTACK_DELAY=1500,t.STEP_DELAY=2e3,t.ALERT_DISPLAY_LENGTH=3e3},182:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TimeManager=void 0,t.TimeManager=class{constructor(e=120){this.dayLength=e,this.scaleFactor=30,this.dayLengthAsMS=60*e*1e3}dayScaleFactor(){return this.dayLength/30}getTimePeriod(){return this.isMorning()?"morning":this.isAfternoon()?"afternoon":this.isEvening()?"evening":this.isNight()?"night":void 0}getAmPm(){return this.get24Hour()<12?"am":"pm"}get24Hour(){const e=new Date,t=(e.getMinutes()+e.getHours()%2*(this.dayLength/2))/this.dayLength;return Math.floor(24*t)}getHour(){const e=this.get24Hour(),t=e>12?e-12:e;return 0===t?12:t}gradientName(){const e=Math.floor(this.get24Hour()/24*this.scaleFactor);return`sky-gradient-${e<10?"0":""}${e}`}isNight(){const e=this.get24Hour();return e>=0&&e<5||e>=21&&e<24}isMorning(){const e=this.get24Hour();return e>=5&&e<12}isAfternoon(){const e=this.get24Hour();return e>=12&&e<18}isEvening(){const e=this.get24Hour();return e>=18&&e<21}}},419:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasCORS=void 0;let s=!1;try{s="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(e){}t.hasCORS=s},754:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0,t.encode=function(e){let t="";for(let s in e)e.hasOwnProperty(s)&&(t.length&&(t+="&"),t+=encodeURIComponent(s)+"="+encodeURIComponent(e[s]));return t},t.decode=function(e){let t={},s=e.split("&");for(let e=0,n=s.length;e{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parse=void 0;const s=/^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,n=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];t.parse=function(e){const t=e,r=e.indexOf("["),o=e.indexOf("]");-1!=r&&-1!=o&&(e=e.substring(0,r)+e.substring(r,o).replace(/:/g,";")+e.substring(o,e.length));let i=s.exec(e||""),a={},c=14;for(;c--;)a[n[c]]=i[c]||"";return-1!=r&&-1!=o&&(a.source=t,a.host=a.host.substring(1,a.host.length-1).replace(/;/g,":"),a.authority=a.authority.replace("[","").replace("]","").replace(/;/g,":"),a.ipv6uri=!0),a.pathNames=function(e,t){const s=t.replace(/\/{2,9}/g,"/").split("/");return"/"!=t.slice(0,1)&&0!==t.length||s.splice(0,1),"/"==t.slice(-1)&&s.splice(s.length-1,1),s}(0,a.path),a.queryKey=function(e,t){const s={};return t.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,(function(e,t,n){t&&(s[t]=n)})),s}(0,a.query),a}},726:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.yeast=t.decode=t.encode=void 0;const s="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),n={};let r,o=0,i=0;function a(e){let t="";do{t=s[e%64]+t,e=Math.floor(e/64)}while(e>0);return t}for(t.encode=a,t.decode=function(e){let t=0;for(i=0;i{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.globalThisShim=void 0,t.globalThisShim="undefined"!=typeof self?self:"undefined"!=typeof window?window:Function("return this")()},679:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.nextTick=t.parse=t.installTimerFunctions=t.transports=t.Transport=t.protocol=t.Socket=void 0;const n=s(481);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return n.Socket}}),t.protocol=n.Socket.protocol;var r=s(870);Object.defineProperty(t,"Transport",{enumerable:!0,get:function(){return r.Transport}});var o=s(385);Object.defineProperty(t,"transports",{enumerable:!0,get:function(){return o.transports}});var i=s(622);Object.defineProperty(t,"installTimerFunctions",{enumerable:!0,get:function(){return i.installTimerFunctions}});var a=s(222);Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return a.parse}});var c=s(552);Object.defineProperty(t,"nextTick",{enumerable:!0,get:function(){return c.nextTick}})},481:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const r=s(385),o=s(622),i=s(754),a=s(222),c=n(s(802)),u=s(260),h=s(373),l=(0,c.default)("engine.io-client:socket");class d extends u.Emitter{constructor(e,t={}){super(),this.writeBuffer=[],e&&"object"==typeof e&&(t=e,e=null),e?(e=(0,a.parse)(e),t.hostname=e.host,t.secure="https"===e.protocol||"wss"===e.protocol,t.port=e.port,e.query&&(t.query=e.query)):t.host&&(t.hostname=(0,a.parse)(t.host).host),(0,o.installTimerFunctions)(this,t),this.secure=null!=t.secure?t.secure:"undefined"!=typeof location&&"https:"===location.protocol,t.hostname&&!t.port&&(t.port=this.secure?"443":"80"),this.hostname=t.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=t.port||("undefined"!=typeof location&&location.port?location.port:this.secure?"443":"80"),this.transports=t.transports||["polling","websocket"],this.writeBuffer=[],this.prevBufferLen=0,this.opts=Object.assign({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,addTrailingSlash:!0,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!0},t),this.opts.path=this.opts.path.replace(/\/$/,"")+(this.opts.addTrailingSlash?"/":""),"string"==typeof this.opts.query&&(this.opts.query=(0,i.decode)(this.opts.query)),this.id=null,this.upgrades=null,this.pingInterval=null,this.pingTimeout=null,this.pingTimeoutTimer=null,"function"==typeof addEventListener&&(this.opts.closeOnBeforeunload&&(this.beforeunloadEventListener=()=>{this.transport&&(this.transport.removeAllListeners(),this.transport.close())},addEventListener("beforeunload",this.beforeunloadEventListener,!1)),"localhost"!==this.hostname&&(this.offlineEventListener=()=>{this.onClose("transport close",{description:"network connection lost"})},addEventListener("offline",this.offlineEventListener,!1))),this.open()}createTransport(e){l('creating transport "%s"',e);const t=Object.assign({},this.opts.query);t.EIO=h.protocol,t.transport=e,this.id&&(t.sid=this.id);const s=Object.assign({},this.opts.transportOptions[e],this.opts,{query:t,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return l("options: %j",s),new r.transports[e](s)}open(){let e;if(this.opts.rememberUpgrade&&d.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))e="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((()=>{this.emitReserved("error","No transports available")}),0);e=this.transports[0]}this.readyState="opening";try{e=this.createTransport(e)}catch(e){return l("error while creating transport: %s",e),this.transports.shift(),void this.open()}e.open(),this.setTransport(e)}setTransport(e){l("setting transport %s",e.name),this.transport&&(l("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=e,e.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(e=>this.onClose("transport close",e)))}probe(e){l('probing transport "%s"',e);let t=this.createTransport(e),s=!1;d.priorWebsocketSuccess=!1;const n=()=>{s||(l('probe transport "%s" opened',e),t.send([{type:"ping",data:"probe"}]),t.once("packet",(n=>{if(!s)if("pong"===n.type&&"probe"===n.data){if(l('probe transport "%s" pong',e),this.upgrading=!0,this.emitReserved("upgrading",t),!t)return;d.priorWebsocketSuccess="websocket"===t.name,l('pausing current transport "%s"',this.transport.name),this.transport.pause((()=>{s||"closed"!==this.readyState&&(l("changing transport and sending upgrade packet"),u(),this.setTransport(t),t.send([{type:"upgrade"}]),this.emitReserved("upgrade",t),t=null,this.upgrading=!1,this.flush())}))}else{l('probe transport "%s" failed',e);const s=new Error("probe error");s.transport=t.name,this.emitReserved("upgradeError",s)}})))};function r(){s||(s=!0,u(),t.close(),t=null)}const o=s=>{const n=new Error("probe error: "+s);n.transport=t.name,r(),l('probe transport "%s" failed because of error: %s',e,s),this.emitReserved("upgradeError",n)};function i(){o("transport closed")}function a(){o("socket closed")}function c(e){t&&e.name!==t.name&&(l('"%s" works - aborting "%s"',e.name,t.name),r())}const u=()=>{t.removeListener("open",n),t.removeListener("error",o),t.removeListener("close",i),this.off("close",a),this.off("upgrading",c)};t.once("open",n),t.once("error",o),t.once("close",i),this.once("close",a),this.once("upgrading",c),t.open()}onOpen(){if(l("socket open"),this.readyState="open",d.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade){l("starting upgrade probes");let e=0;const t=this.upgrades.length;for(;e{this.onClose("ping timeout")}),this.pingInterval+this.pingTimeout),this.opts.autoUnref&&this.pingTimeoutTimer.unref()}onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBufferLen=0,0===this.writeBuffer.length?this.emitReserved("drain"):this.flush()}flush(){if("closed"!==this.readyState&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){const e=this.getWritablePackets();l("flushing %d packets in socket",e.length),this.transport.send(e),this.prevBufferLen=e.length,this.emitReserved("flush")}}getWritablePackets(){if(!(this.maxPayload&&"polling"===this.transport.name&&this.writeBuffer.length>1))return this.writeBuffer;let e=1;for(let t=0;t0&&e>this.maxPayload)return l("only send %d out of %d packets",t,this.writeBuffer.length),this.writeBuffer.slice(0,t);e+=2}return l("payload size is %d (max: %d)",e,this.maxPayload),this.writeBuffer}write(e,t,s){return this.sendPacket("message",e,t,s),this}send(e,t,s){return this.sendPacket("message",e,t,s),this}sendPacket(e,t,s,n){if("function"==typeof t&&(n=t,t=void 0),"function"==typeof s&&(n=s,s=null),"closing"===this.readyState||"closed"===this.readyState)return;(s=s||{}).compress=!1!==s.compress;const r={type:e,data:t,options:s};this.emitReserved("packetCreate",r),this.writeBuffer.push(r),n&&this.once("flush",n),this.flush()}close(){const e=()=>{this.onClose("forced close"),l("socket closing - telling transport to close"),this.transport.close()},t=()=>{this.off("upgrade",t),this.off("upgradeError",t),e()},s=()=>{this.once("upgrade",t),this.once("upgradeError",t)};return"opening"!==this.readyState&&"open"!==this.readyState||(this.readyState="closing",this.writeBuffer.length?this.once("drain",(()=>{this.upgrading?s():e()})):this.upgrading?s():e()),this}onError(e){l("socket error %j",e),d.priorWebsocketSuccess=!1,this.emitReserved("error",e),this.onClose("transport error",e)}onClose(e,t){"opening"!==this.readyState&&"open"!==this.readyState&&"closing"!==this.readyState||(l('socket close with reason: "%s"',e),this.clearTimeoutFn(this.pingTimeoutTimer),this.transport.removeAllListeners("close"),this.transport.close(),this.transport.removeAllListeners(),"function"==typeof removeEventListener&&(removeEventListener("beforeunload",this.beforeunloadEventListener,!1),removeEventListener("offline",this.offlineEventListener,!1)),this.readyState="closed",this.id=null,this.emitReserved("close",e,t),this.writeBuffer=[],this.prevBufferLen=0)}filterUpgrades(e){const t=[];let s=0;const n=e.length;for(;s{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transports=void 0;const n=s(484),r=s(308);t.transports={websocket:r.WS,polling:n.Polling}},484:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Request=t.Polling=void 0;const r=s(870),o=n(s(802)),i=s(726),a=s(754),c=s(373),u=s(666),h=s(260),l=s(622),d=s(242),p=(0,o.default)("engine.io-client:polling");function f(){}const g=null!=new u.XHR({xdomain:!1}).responseType;class m extends r.Transport{constructor(e){if(super(e),this.polling=!1,"undefined"!=typeof location){const t="https:"===location.protocol;let s=location.port;s||(s=t?"443":"80"),this.xd="undefined"!=typeof location&&e.hostname!==location.hostname||s!==e.port,this.xs=e.secure!==t}const t=e&&e.forceBase64;this.supportsBinary=g&&!t}get name(){return"polling"}doOpen(){this.poll()}pause(e){this.readyState="pausing";const t=()=>{p("paused"),this.readyState="paused",e()};if(this.polling||!this.writable){let e=0;this.polling&&(p("we are currently polling - waiting to pause"),e++,this.once("pollComplete",(function(){p("pre-pause polling complete"),--e||t()}))),this.writable||(p("we are currently writing - waiting to pause"),e++,this.once("drain",(function(){p("pre-pause writing complete"),--e||t()})))}else t()}poll(){p("polling"),this.polling=!0,this.doPoll(),this.emitReserved("poll")}onData(e){p("polling got data %s",e),(0,c.decodePayload)(e,this.socket.binaryType).forEach((e=>{if("opening"===this.readyState&&"open"===e.type&&this.onOpen(),"close"===e.type)return this.onClose({description:"transport closed by the server"}),!1;this.onPacket(e)})),"closed"!==this.readyState&&(this.polling=!1,this.emitReserved("pollComplete"),"open"===this.readyState?this.poll():p('ignoring poll - transport state "%s"',this.readyState))}doClose(){const e=()=>{p("writing close packet"),this.write([{type:"close"}])};"open"===this.readyState?(p("transport open - closing"),e()):(p("transport not open - deferring close"),this.once("open",e))}write(e){this.writable=!1,(0,c.encodePayload)(e,(e=>{this.doWrite(e,(()=>{this.writable=!0,this.emitReserved("drain")}))}))}uri(){let e=this.query||{};const t=this.opts.secure?"https":"http";let s="";!1!==this.opts.timestampRequests&&(e[this.opts.timestampParam]=(0,i.yeast)()),this.supportsBinary||e.sid||(e.b64=1),this.opts.port&&("https"===t&&443!==Number(this.opts.port)||"http"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port);const n=(0,a.encode)(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(n.length?"?"+n:"")}request(e={}){return Object.assign(e,{xd:this.xd,xs:this.xs},this.opts),new y(this.uri(),e)}doWrite(e,t){const s=this.request({method:"POST",data:e});s.on("success",t),s.on("error",((e,t)=>{this.onError("xhr post error",e,t)}))}doPoll(){p("xhr poll");const e=this.request();e.on("data",this.onData.bind(this)),e.on("error",((e,t)=>{this.onError("xhr poll error",e,t)})),this.pollXhr=e}}t.Polling=m;class y extends h.Emitter{constructor(e,t){super(),(0,l.installTimerFunctions)(this,t),this.opts=t,this.method=t.method||"GET",this.uri=e,this.async=!1!==t.async,this.data=void 0!==t.data?t.data:null,this.create()}create(){const e=(0,l.pick)(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");e.xdomain=!!this.opts.xd,e.xscheme=!!this.opts.xs;const t=this.xhr=new u.XHR(e);try{p("xhr open %s: %s",this.method,this.uri),t.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders){t.setDisableHeaderCheck&&t.setDisableHeaderCheck(!0);for(let e in this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(e)&&t.setRequestHeader(e,this.opts.extraHeaders[e])}}catch(e){}if("POST"===this.method)try{t.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(e){}try{t.setRequestHeader("Accept","*/*")}catch(e){}"withCredentials"in t&&(t.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(t.timeout=this.opts.requestTimeout),t.onreadystatechange=()=>{4===t.readyState&&(200===t.status||1223===t.status?this.onLoad():this.setTimeoutFn((()=>{this.onError("number"==typeof t.status?t.status:0)}),0))},p("xhr data %s",this.data),t.send(this.data)}catch(e){return void this.setTimeoutFn((()=>{this.onError(e)}),0)}"undefined"!=typeof document&&(this.index=y.requestsCount++,y.requests[this.index]=this)}onError(e){this.emitReserved("error",e,this.xhr),this.cleanup(!0)}cleanup(e){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=f,e)try{this.xhr.abort()}catch(e){}"undefined"!=typeof document&&delete y.requests[this.index],this.xhr=null}}onLoad(){const e=this.xhr.responseText;null!==e&&(this.emitReserved("data",e),this.emitReserved("success"),this.cleanup())}abort(){this.cleanup()}}if(t.Request=y,y.requestsCount=0,y.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",C);else if("function"==typeof addEventListener){const e="onpagehide"in d.globalThisShim?"pagehide":"unload";addEventListener(e,C,!1)}function C(){for(let e in y.requests)y.requests.hasOwnProperty(e)&&y.requests[e].abort()}},552:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.defaultBinaryType=t.usingBrowserWebSocket=t.WebSocket=t.nextTick=void 0;const n=s(242);t.nextTick="function"==typeof Promise&&"function"==typeof Promise.resolve?e=>Promise.resolve().then(e):(e,t)=>t(e,0),t.WebSocket=n.globalThisShim.WebSocket||n.globalThisShim.MozWebSocket,t.usingBrowserWebSocket=!0,t.defaultBinaryType="arraybuffer"},308:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.WS=void 0;const r=s(870),o=s(754),i=s(726),a=s(622),c=s(552),u=n(s(802)),h=s(373),l=(0,u.default)("engine.io-client:websocket"),d="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase();class p extends r.Transport{constructor(e){super(e),this.supportsBinary=!e.forceBase64}get name(){return"websocket"}doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protocols,s=d?{}:(0,a.pick)(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(s.headers=this.opts.extraHeaders);try{this.ws=c.usingBrowserWebSocket&&!d?t?new c.WebSocket(e,t):new c.WebSocket(e):new c.WebSocket(e,t,s)}catch(e){return this.emitReserved("error",e)}this.ws.binaryType=this.socket.binaryType||c.defaultBinaryType,this.addEventListeners()}addEventListeners(){this.ws.onopen=()=>{this.opts.autoUnref&&this.ws._socket.unref(),this.onOpen()},this.ws.onclose=e=>this.onClose({description:"websocket connection closed",context:e}),this.ws.onmessage=e=>this.onData(e.data),this.ws.onerror=e=>this.onError("websocket error",e)}write(e){this.writable=!1;for(let t=0;t{const t={};!c.usingBrowserWebSocket&&(s.options&&(t.compress=s.options.compress),this.opts.perMessageDeflate)&&("string"==typeof e?Buffer.byteLength(e):e.length){this.writable=!0,this.emitReserved("drain")}),this.setTimeoutFn)}))}}doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}uri(){let e=this.query||{};const t=this.opts.secure?"wss":"ws";let s="";this.opts.port&&("wss"===t&&443!==Number(this.opts.port)||"ws"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port),this.opts.timestampRequests&&(e[this.opts.timestampParam]=(0,i.yeast)()),this.supportsBinary||(e.b64=1);const n=(0,o.encode)(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(n.length?"?"+n:"")}check(){return!!c.WebSocket}}t.WS=p},666:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.XHR=void 0;const n=s(419),r=s(242);t.XHR=function(e){const t=e.xdomain;try{if("undefined"!=typeof XMLHttpRequest&&(!t||n.hasCORS))return new XMLHttpRequest}catch(e){}if(!t)try{return new(r.globalThisShim[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(e){}}},622:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.byteLength=t.installTimerFunctions=t.pick=void 0;const n=s(242);t.pick=function(e,...t){return t.reduce(((t,s)=>(e.hasOwnProperty(s)&&(t[s]=e[s]),t)),{})};const r=n.globalThisShim.setTimeout,o=n.globalThisShim.clearTimeout;t.installTimerFunctions=function(e,t){t.useNativeTimers?(e.setTimeoutFn=r.bind(n.globalThisShim),e.clearTimeoutFn=o.bind(n.globalThisShim)):(e.setTimeoutFn=n.globalThisShim.setTimeout.bind(n.globalThisShim),e.clearTimeoutFn=n.globalThisShim.clearTimeout.bind(n.globalThisShim))},t.byteLength=function(e){return"string"==typeof e?function(e){let t=0,s=0;for(let n=0,r=e.length;n=57344?s+=3:(n++,s+=4);return s}(e):Math.ceil(1.33*(e.byteLength||e.size))}},87:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ERROR_PACKET=t.PACKET_TYPES_REVERSE=t.PACKET_TYPES=void 0;const s=Object.create(null);t.PACKET_TYPES=s,s.open="0",s.close="1",s.ping="2",s.pong="3",s.message="4",s.upgrade="5",s.noop="6";const n=Object.create(null);t.PACKET_TYPES_REVERSE=n,Object.keys(s).forEach((e=>{n[s[e]]=e})),t.ERROR_PACKET={type:"error",data:"parser error"}},469:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0;const s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n="undefined"==typeof Uint8Array?[]:new Uint8Array(256);for(let e=0;e<64;e++)n[s.charCodeAt(e)]=e;t.encode=e=>{let t,n=new Uint8Array(e),r=n.length,o="";for(t=0;t>2],o+=s[(3&n[t])<<4|n[t+1]>>4],o+=s[(15&n[t+1])<<2|n[t+2]>>6],o+=s[63&n[t+2]];return r%3==2?o=o.substring(0,o.length-1)+"=":r%3==1&&(o=o.substring(0,o.length-2)+"=="),o},t.decode=e=>{let t,s,r,o,i,a=.75*e.length,c=e.length,u=0;"="===e[e.length-1]&&(a--,"="===e[e.length-2]&&a--);const h=new ArrayBuffer(a),l=new Uint8Array(h);for(t=0;t>4,l[u++]=(15&r)<<4|o>>2,l[u++]=(3&o)<<6|63&i;return h}},572:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=s(87),r=s(469),o="function"==typeof ArrayBuffer,i=(e,t)=>{if(o){const s=(0,r.decode)(e);return a(s,t)}return{base64:!0,data:e}},a=(e,t)=>"blob"===t&&e instanceof ArrayBuffer?new Blob([e]):e;t.default=(e,t)=>{if("string"!=typeof e)return{type:"message",data:a(e,t)};const s=e.charAt(0);return"b"===s?{type:"message",data:i(e.substring(1),t)}:n.PACKET_TYPES_REVERSE[s]?e.length>1?{type:n.PACKET_TYPES_REVERSE[s],data:e.substring(1)}:{type:n.PACKET_TYPES_REVERSE[s]}:n.ERROR_PACKET}},908:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=s(87),r="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===Object.prototype.toString.call(Blob),o="function"==typeof ArrayBuffer,i=(e,t)=>{const s=new FileReader;return s.onload=function(){const e=s.result.split(",")[1];t("b"+(e||""))},s.readAsDataURL(e)};t.default=({type:e,data:t},s,a)=>{return r&&t instanceof Blob?s?a(t):i(t,a):o&&(t instanceof ArrayBuffer||(c=t,"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(c):c&&c.buffer instanceof ArrayBuffer))?s?a(t):i(new Blob([t]),a):a(n.PACKET_TYPES[e]+(t||""));var c}},373:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decodePayload=t.decodePacket=t.encodePayload=t.encodePacket=t.protocol=void 0;const n=s(908);t.encodePacket=n.default;const r=s(572);t.decodePacket=r.default;const o=String.fromCharCode(30);t.encodePayload=(e,t)=>{const s=e.length,r=new Array(s);let i=0;e.forEach(((e,a)=>{(0,n.default)(e,!1,(e=>{r[a]=e,++i===s&&t(r.join(o))}))}))},t.decodePayload=(e,t)=>{const s=e.split(o),n=[];for(let e=0;e{"use strict";function s(e){e=e||{},this.ms=e.min||100,this.max=e.max||1e4,this.factor=e.factor||2,this.jitter=e.jitter>0&&e.jitter<=1?e.jitter:0,this.attempts=0}Object.defineProperty(t,"__esModule",{value:!0}),t.Backoff=void 0,t.Backoff=s,s.prototype.duration=function(){var e=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var t=Math.random(),s=Math.floor(t*this.jitter*e);e=0==(1&Math.floor(10*t))?e-s:e+s}return 0|Math.min(e,this.max)},s.prototype.reset=function(){this.attempts=0},s.prototype.setMin=function(e){this.ms=e},s.prototype.setMax=function(e){this.max=e},s.prototype.setJitter=function(e){this.jitter=e}},46:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.connect=t.io=t.Socket=t.Manager=t.protocol=void 0;const r=s(84),o=s(168);Object.defineProperty(t,"Manager",{enumerable:!0,get:function(){return o.Manager}});const i=s(312);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return i.Socket}});const a=n(s(669)).default("socket.io-client"),c={};function u(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};const s=r.url(e,t.path||"/socket.io"),n=s.source,i=s.id,u=s.path,h=c[i]&&u in c[i].nsps;let l;return t.forceNew||t["force new connection"]||!1===t.multiplex||h?(a("ignoring socket cache for %s",n),l=new o.Manager(n,t)):(c[i]||(a("new io instance for %s",n),c[i]=new o.Manager(n,t)),l=c[i]),s.query&&!t.query&&(t.query=s.queryKey),l.socket(s.path,t)}t.io=u,t.connect=u,t.default=u,Object.assign(u,{Manager:o.Manager,Socket:i.Socket,io:u,connect:u});var h=s(514);Object.defineProperty(t,"protocol",{enumerable:!0,get:function(){return h.protocol}}),e.exports=u},168:function(e,t,s){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[s]}})}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var s in e)"default"!==s&&Object.prototype.hasOwnProperty.call(e,s)&&n(t,e,s);return r(t,e),t},i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Manager=void 0;const a=s(679),c=s(312),u=o(s(514)),h=s(149),l=s(159),d=s(260),p=i(s(669)).default("socket.io-client:manager");class f extends d.Emitter{constructor(e,t){var s;super(),this.nsps={},this.subs=[],e&&"object"==typeof e&&(t=e,e=void 0),(t=t||{}).path=t.path||"/socket.io",this.opts=t,a.installTimerFunctions(this,t),this.reconnection(!1!==t.reconnection),this.reconnectionAttempts(t.reconnectionAttempts||1/0),this.reconnectionDelay(t.reconnectionDelay||1e3),this.reconnectionDelayMax(t.reconnectionDelayMax||5e3),this.randomizationFactor(null!==(s=t.randomizationFactor)&&void 0!==s?s:.5),this.backoff=new l.Backoff({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(null==t.timeout?2e4:t.timeout),this._readyState="closed",this.uri=e;const n=t.parser||u;this.encoder=new n.Encoder,this.decoder=new n.Decoder,this._autoConnect=!1!==t.autoConnect,this._autoConnect&&this.open()}reconnection(e){return arguments.length?(this._reconnection=!!e,this):this._reconnection}reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(this._reconnectionAttempts=e,this)}reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(this._reconnectionDelay=e,null===(t=this.backoff)||void 0===t||t.setMin(e),this)}randomizationFactor(e){var t;return void 0===e?this._randomizationFactor:(this._randomizationFactor=e,null===(t=this.backoff)||void 0===t||t.setJitter(e),this)}reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDelayMax:(this._reconnectionDelayMax=e,null===(t=this.backoff)||void 0===t||t.setMax(e),this)}timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}open(e){if(p("readyState %s",this._readyState),~this._readyState.indexOf("open"))return this;p("opening %s",this.uri),this.engine=new a.Socket(this.uri,this.opts);const t=this.engine,s=this;this._readyState="opening",this.skipReconnect=!1;const n=h.on(t,"open",(function(){s.onopen(),e&&e()})),r=h.on(t,"error",(t=>{p("error"),s.cleanup(),s._readyState="closed",this.emitReserved("error",t),e?e(t):s.maybeReconnectOnOpen()}));if(!1!==this._timeout){const e=this._timeout;p("connect attempt will timeout after %d",e),0===e&&n();const s=this.setTimeoutFn((()=>{p("connect attempt timed out after %d",e),n(),t.close(),t.emit("error",new Error("timeout"))}),e);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}return this.subs.push(n),this.subs.push(r),this}connect(e){return this.open(e)}onopen(){p("open"),this.cleanup(),this._readyState="open",this.emitReserved("open");const e=this.engine;this.subs.push(h.on(e,"ping",this.onping.bind(this)),h.on(e,"data",this.ondata.bind(this)),h.on(e,"error",this.onerror.bind(this)),h.on(e,"close",this.onclose.bind(this)),h.on(this.decoder,"decoded",this.ondecoded.bind(this)))}onping(){this.emitReserved("ping")}ondata(e){try{this.decoder.add(e)}catch(e){this.onclose("parse error",e)}}ondecoded(e){a.nextTick((()=>{this.emitReserved("packet",e)}),this.setTimeoutFn)}onerror(e){p("error",e),this.emitReserved("error",e)}socket(e,t){let s=this.nsps[e];return s?this._autoConnect&&!s.active&&s.connect():(s=new c.Socket(this,e,t),this.nsps[e]=s),s}_destroy(e){const t=Object.keys(this.nsps);for(const e of t)if(this.nsps[e].active)return void p("socket %s is still active, skipping close",e);this._close()}_packet(e){p("writing packet %j",e);const t=this.encoder.encode(e);for(let s=0;se())),this.subs.length=0,this.decoder.destroy()}_close(){p("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,this.onclose("forced close"),this.engine&&this.engine.close()}disconnect(){return this._close()}onclose(e,t){p("closed due to %s",e),this.cleanup(),this.backoff.reset(),this._readyState="closed",this.emitReserved("close",e,t),this._reconnection&&!this.skipReconnect&&this.reconnect()}reconnect(){if(this._reconnecting||this.skipReconnect)return this;const e=this;if(this.backoff.attempts>=this._reconnectionAttempts)p("reconnect failed"),this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{const t=this.backoff.duration();p("will wait %dms before reconnect attempt",t),this._reconnecting=!0;const s=this.setTimeoutFn((()=>{e.skipReconnect||(p("attempting reconnect"),this.emitReserved("reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((t=>{t?(p("reconnect attempt error"),e._reconnecting=!1,e.reconnect(),this.emitReserved("reconnect_error",t)):(p("reconnect success"),e.onreconnect())})))}),t);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}}onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",e)}}t.Manager=f},149:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.on=void 0,t.on=function(e,t,s){return e.on(t,s),function(){e.off(t,s)}}},312:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const r=s(514),o=s(149),i=s(260),a=n(s(669)).default("socket.io-client:socket"),c=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1});class u extends i.Emitter{constructor(e,t,s){super(),this.connected=!1,this.recovered=!1,this.receiveBuffer=[],this.sendBuffer=[],this._queue=[],this._queueSeq=0,this.ids=0,this.acks={},this.flags={},this.io=e,this.nsp=t,s&&s.auth&&(this.auth=s.auth),this._opts=Object.assign({},s),this.io._autoConnect&&this.open()}get disconnected(){return!this.connected}subEvents(){if(this.subs)return;const e=this.io;this.subs=[o.on(e,"open",this.onopen.bind(this)),o.on(e,"packet",this.onpacket.bind(this)),o.on(e,"error",this.onerror.bind(this)),o.on(e,"close",this.onclose.bind(this))]}get active(){return!!this.subs}connect(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}open(){return this.connect()}send(...e){return e.unshift("message"),this.emit.apply(this,e),this}emit(e,...t){if(c.hasOwnProperty(e))throw new Error('"'+e.toString()+'" is a reserved event name');if(t.unshift(e),this._opts.retries&&!this.flags.fromQueue&&!this.flags.volatile)return this._addToQueue(t),this;const s={type:r.PacketType.EVENT,data:t,options:{}};if(s.options.compress=!1!==this.flags.compress,"function"==typeof t[t.length-1]){const e=this.ids++;a("emitting packet with ack id %d",e);const n=t.pop();this._registerAckCallback(e,n),s.id=e}const n=this.io.engine&&this.io.engine.transport&&this.io.engine.transport.writable;return!this.flags.volatile||n&&this.connected?this.connected?(this.notifyOutgoingListeners(s),this.packet(s)):this.sendBuffer.push(s):a("discard packet as the transport is not currently writable"),this.flags={},this}_registerAckCallback(e,t){var s;const n=null!==(s=this.flags.timeout)&&void 0!==s?s:this._opts.ackTimeout;if(void 0===n)return void(this.acks[e]=t);const r=this.io.setTimeoutFn((()=>{delete this.acks[e];for(let t=0;t{this.io.clearTimeoutFn(r),t.apply(this,[null,...e])}}emitWithAck(e,...t){const s=void 0!==this.flags.timeout||void 0!==this._opts.ackTimeout;return new Promise(((n,r)=>{t.push(((e,t)=>s?e?r(e):n(t):n(e))),this.emit(e,...t)}))}_addToQueue(e){let t;"function"==typeof e[e.length-1]&&(t=e.pop());const s={id:this._queueSeq++,tryCount:0,pending:!1,args:e,flags:Object.assign({fromQueue:!0},this.flags)};e.push(((e,...n)=>{if(s===this._queue[0])return null!==e?s.tryCount>this._opts.retries&&(a("packet [%d] is discarded after %d tries",s.id,s.tryCount),this._queue.shift(),t&&t(e)):(a("packet [%d] was successfully sent",s.id),this._queue.shift(),t&&t(null,...n)),s.pending=!1,this._drainQueue()})),this._queue.push(s),this._drainQueue()}_drainQueue(e=!1){if(a("draining queue"),!this.connected||0===this._queue.length)return;const t=this._queue[0];!t.pending||e?(t.pending=!0,t.tryCount++,a("sending packet [%d] (try n°%d)",t.id,t.tryCount),this.flags=t.flags,this.emit.apply(this,t.args)):a("packet [%d] has already been sent and is waiting for an ack",t.id)}packet(e){e.nsp=this.nsp,this.io._packet(e)}onopen(){a("transport is open - connecting"),"function"==typeof this.auth?this.auth((e=>{this._sendConnectPacket(e)})):this._sendConnectPacket(this.auth)}_sendConnectPacket(e){this.packet({type:r.PacketType.CONNECT,data:this._pid?Object.assign({pid:this._pid,offset:this._lastOffset},e):e})}onerror(e){this.connected||this.emitReserved("connect_error",e)}onclose(e,t){a("close (%s)",e),this.connected=!1,delete this.id,this.emitReserved("disconnect",e,t)}onpacket(e){if(e.nsp===this.nsp)switch(e.type){case r.PacketType.CONNECT:e.data&&e.data.sid?this.onconnect(e.data.sid,e.data.pid):this.emitReserved("connect_error",new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));break;case r.PacketType.EVENT:case r.PacketType.BINARY_EVENT:this.onevent(e);break;case r.PacketType.ACK:case r.PacketType.BINARY_ACK:this.onack(e);break;case r.PacketType.DISCONNECT:this.ondisconnect();break;case r.PacketType.CONNECT_ERROR:this.destroy();const t=new Error(e.data.message);t.data=e.data.data,this.emitReserved("connect_error",t)}}onevent(e){const t=e.data||[];a("emitting event %j",t),null!=e.id&&(a("attaching ack callback to event"),t.push(this.ack(e.id))),this.connected?this.emitEvent(t):this.receiveBuffer.push(Object.freeze(t))}emitEvent(e){if(this._anyListeners&&this._anyListeners.length){const t=this._anyListeners.slice();for(const s of t)s.apply(this,e)}super.emit.apply(this,e),this._pid&&e.length&&"string"==typeof e[e.length-1]&&(this._lastOffset=e[e.length-1])}ack(e){const t=this;let s=!1;return function(...n){s||(s=!0,a("sending ack %j",n),t.packet({type:r.PacketType.ACK,id:e,data:n}))}}onack(e){const t=this.acks[e.id];"function"==typeof t?(a("calling ack %s with %j",e.id,e.data),t.apply(this,e.data),delete this.acks[e.id]):a("bad ack %s",e.id)}onconnect(e,t){a("socket connected with id %s",e),this.id=e,this.recovered=t&&this._pid===t,this._pid=t,this.connected=!0,this.emitBuffered(),this.emitReserved("connect"),this._drainQueue(!0)}emitBuffered(){this.receiveBuffer.forEach((e=>this.emitEvent(e))),this.receiveBuffer=[],this.sendBuffer.forEach((e=>{this.notifyOutgoingListeners(e),this.packet(e)})),this.sendBuffer=[]}ondisconnect(){a("server disconnect (%s)",this.nsp),this.destroy(),this.onclose("io server disconnect")}destroy(){this.subs&&(this.subs.forEach((e=>e())),this.subs=void 0),this.io._destroy(this)}disconnect(){return this.connected&&(a("performing disconnect (%s)",this.nsp),this.packet({type:r.PacketType.DISCONNECT})),this.destroy(),this.connected&&this.onclose("io client disconnect"),this}close(){return this.disconnect()}compress(e){return this.flags.compress=e,this}get volatile(){return this.flags.volatile=!0,this}timeout(e){return this.flags.timeout=e,this}onAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.push(e),this}prependAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.unshift(e),this}offAny(e){if(!this._anyListeners)return this;if(e){const t=this._anyListeners;for(let s=0;s{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.reconstructPacket=t.deconstructPacket=void 0;const n=s(665);function r(e,t){if(!e)return e;if((0,n.isBinary)(e)){const s={_placeholder:!0,num:t.length};return t.push(e),s}if(Array.isArray(e)){const s=new Array(e.length);for(let n=0;n=0&&e.num{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Decoder=t.Encoder=t.PacketType=t.protocol=void 0;const n=s(260),r=s(880),o=s(665),i=(0,s(618).default)("socket.io-parser");var a;t.protocol=5,function(e){e[e.CONNECT=0]="CONNECT",e[e.DISCONNECT=1]="DISCONNECT",e[e.EVENT=2]="EVENT",e[e.ACK=3]="ACK",e[e.CONNECT_ERROR=4]="CONNECT_ERROR",e[e.BINARY_EVENT=5]="BINARY_EVENT",e[e.BINARY_ACK=6]="BINARY_ACK"}(a=t.PacketType||(t.PacketType={})),t.Encoder=class{constructor(e){this.replacer=e}encode(e){return i("encoding packet %j",e),e.type!==a.EVENT&&e.type!==a.ACK||!(0,o.hasBinary)(e)?[this.encodeAsString(e)]:this.encodeAsBinary({type:e.type===a.EVENT?a.BINARY_EVENT:a.BINARY_ACK,nsp:e.nsp,data:e.data,id:e.id})}encodeAsString(e){let t=""+e.type;return e.type!==a.BINARY_EVENT&&e.type!==a.BINARY_ACK||(t+=e.attachments+"-"),e.nsp&&"/"!==e.nsp&&(t+=e.nsp+","),null!=e.id&&(t+=e.id),null!=e.data&&(t+=JSON.stringify(e.data,this.replacer)),i("encoded %j as %s",e,t),t}encodeAsBinary(e){const t=(0,r.deconstructPacket)(e),s=this.encodeAsString(t.packet),n=t.buffers;return n.unshift(s),n}};class c extends n.Emitter{constructor(e){super(),this.reviver=e}add(e){let t;if("string"==typeof e){if(this.reconstructor)throw new Error("got plaintext data when reconstructing a packet");t=this.decodeString(e);const s=t.type===a.BINARY_EVENT;s||t.type===a.BINARY_ACK?(t.type=s?a.EVENT:a.ACK,this.reconstructor=new u(t),0===t.attachments&&super.emitReserved("decoded",t)):super.emitReserved("decoded",t)}else{if(!(0,o.isBinary)(e)&&!e.base64)throw new Error("Unknown type: "+e);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");t=this.reconstructor.takeBinaryData(e),t&&(this.reconstructor=null,super.emitReserved("decoded",t))}}decodeString(e){let t=0;const s={type:Number(e.charAt(0))};if(void 0===a[s.type])throw new Error("unknown packet type "+s.type);if(s.type===a.BINARY_EVENT||s.type===a.BINARY_ACK){const n=t+1;for(;"-"!==e.charAt(++t)&&t!=e.length;);const r=e.substring(n,t);if(r!=Number(r)||"-"!==e.charAt(t))throw new Error("Illegal attachments");s.attachments=Number(r)}if("/"===e.charAt(t+1)){const n=t+1;for(;++t&&","!==e.charAt(t)&&t!==e.length;);s.nsp=e.substring(n,t)}else s.nsp="/";const n=e.charAt(t+1);if(""!==n&&Number(n)==n){const n=t+1;for(;++t;){const s=e.charAt(t);if(null==s||Number(s)!=s){--t;break}if(t===e.length)break}s.id=Number(e.substring(n,t+1))}if(e.charAt(++t)){const n=this.tryParse(e.substr(t));if(!c.isPayloadValid(s.type,n))throw new Error("invalid payload");s.data=n}return i("decoded %s as %j",e,s),s}tryParse(e){try{return JSON.parse(e,this.reviver)}catch(e){return!1}}static isPayloadValid(e,t){switch(e){case a.CONNECT:return"object"==typeof t;case a.DISCONNECT:return void 0===t;case a.CONNECT_ERROR:return"string"==typeof t||"object"==typeof t;case a.EVENT:case a.BINARY_EVENT:return Array.isArray(t)&&("string"==typeof t[0]||"number"==typeof t[0]);case a.ACK:case a.BINARY_ACK:return Array.isArray(t)}}destroy(){this.reconstructor&&(this.reconstructor.finishedReconstruction(),this.reconstructor=null)}}t.Decoder=c;class u{constructor(e){this.packet=e,this.buffers=[],this.reconPack=e}takeBinaryData(e){if(this.buffers.push(e),this.buffers.length===this.reconPack.attachments){const e=(0,r.reconstructPacket)(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null}finishedReconstruction(){this.reconPack=null,this.buffers=[]}}},665:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasBinary=t.isBinary=void 0;const s="function"==typeof ArrayBuffer,n=Object.prototype.toString,r="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===n.call(Blob),o="function"==typeof File||"undefined"!=typeof File&&"[object FileConstructor]"===n.call(File);function i(e){return s&&(e instanceof ArrayBuffer||(e=>"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(e):e.buffer instanceof ArrayBuffer)(e))||r&&e instanceof Blob||o&&e instanceof File}t.isBinary=i,t.hasBinary=function e(t,s){if(!t||"object"!=typeof t)return!1;if(Array.isArray(t)){for(let s=0,n=t.length;s{"use strict";function n(e){if(e)return function(e){for(var t in n.prototype)e[t]=n.prototype[t];return e}(e)}s.r(t),s.d(t,{Emitter:()=>n}),n.prototype.on=n.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+e]=this._callbacks["$"+e]||[]).push(t),this},n.prototype.once=function(e,t){function s(){this.off(e,s),t.apply(this,arguments)}return s.fn=t,this.on(e,s),this},n.prototype.off=n.prototype.removeListener=n.prototype.removeAllListeners=n.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var s,n=this._callbacks["$"+e];if(!n)return this;if(1==arguments.length)return delete this._callbacks["$"+e],this;for(var r=0;r{for(var n in t)s.o(t,n)&&!s.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),s.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s(628)})(); \ No newline at end of file +(()=>{var e={802:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(804)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},804:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},669:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(231)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},231:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},618:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(224)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},224:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},628:function(e,t,s){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s);var r=Object.getOwnPropertyDescriptor(t,s);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[s]}}),Object.defineProperty(e,n,r)}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var s in e)"default"!==s&&Object.prototype.hasOwnProperty.call(e,s)&&n(t,e,s);return r(t,e),t};Object.defineProperty(t,"__esModule",{value:!0}),t.authToken=void 0;const i=s(46),a=s(182),c=o(s(454));function u(e,t=document){return t.querySelector(e)}function h(e,t=document){return Array.from(t.querySelectorAll(e))}function l(){return localStorage.getItem("authToken")||""}function d(){const e=p.gradientName(),t=u("body");let s;t.classList.value=e,t.classList.add(p.getTimePeriod()),s=p.get24Hour()>=5&&p.get24Hour()<9?"morning":p.get24Hour()>=9&&p.get24Hour()<17?"afternoon":p.get24Hour()>=17&&p.get24Hour()<20?"evening":"night",u("#time-of-day").innerHTML=` ${p.getHour()}${p.getAmPm()}`}t.authToken=l;const p=new a.TimeManager,f=(0,i.io)({extraHeaders:{"x-authtoken":l()}});d(),setInterval(d,6e4),f.on("connect",(()=>{console.log(`Connected: ${f.id}`)})),f.on("authToken",(e=>{console.log(`recv auth token ${e}`),localStorage.getItem("authToken")!==e&&(localStorage.setItem("authToken",e),window.location.reload())})),f.on("status",(e=>u("#server-stats").innerHTML=e)),f.on("chat",(function(e){u("#chat-messages").insertAdjacentHTML("beforeend",e),u("#chat-messages").scrollTop=u("#chat-messages").scrollHeight})),f.on("ready",(function(){console.log("Server connection verified"),h("nav a")[3].click()})),h("nav a").forEach((e=>{e.addEventListener("click",(e=>{const t=e.target;h("a",t.closest("nav")).forEach((e=>{e.classList.remove("active")})),t.classList.add("active");const s=u(t.getAttribute("hx-target").toString());Array.from(s.parentElement.children).forEach((e=>{e.classList.remove("active")})),s.classList.add("active")}))})),u("body").addEventListener("click",(e=>{var t;const s=e.target;if(s.parentElement.classList.contains("filter")){Array.from(s.parentElement.children).forEach((e=>e.classList.remove("active"))),s.classList.add("active");const e=s.getAttribute("data-filter"),t=u(`.filter-result[data-filter="${e}"]`,s.closest(".filter-container"));t&&Array.from(t.parentElement.children).forEach((t=>{t.getAttribute("data-filter")===e?(t.classList.remove("hidden"),t.classList.add("active")):(t.classList.add("hidden"),t.classList.remove("active"))}))}if("dialog"===s.getAttribute("formmethod")&&"cancel"===s.getAttribute("value")){null===(t=s.closest("dialog"))||void 0===t||t.close();const e=s.getAttribute("nav-trigger");if(e){const[t,s]=e.split("|");h(t)[s].click()}}}));const g=new MutationObserver(((e,t)=>{const s={modal:!1,alert:!1};e.forEach((e=>{switch(e.target.id){case"modal-wrapper":s.modal=!0;break;case"alerts":s.alert=!0}})),s.modal&&u("#modal-wrapper").children.length&&h("#modal-wrapper dialog").forEach((e=>{e.open||e.showModal()})),s.alert&&u("#alerts").children.length&&h("#alerts .alert").forEach((e=>{if(!e.getAttribute("data-dismiss-at")){const t=Date.now()+c.ALERT_DISPLAY_LENGTH;e.setAttribute("data-dismiss-at",t.toString()),setTimeout((()=>{e.remove()}),c.ALERT_DISPLAY_LENGTH)}}))}));g.observe(u("#modal-wrapper"),{childList:!0}),g.observe(u("#alerts"),{childList:!0}),document.body.addEventListener("htmx:configRequest",(function(e){e.detail.headers["x-authtoken"]=l()})),document.body.addEventListener("htmx:load",(function(e){h(".disabled[data-block]").forEach((e=>{const t=parseInt(e.getAttribute("data-block")||"0");if(t>Date.now()){const s=t-Date.now();setTimeout((()=>{e.removeAttribute("disabled")}),s)}else e.removeAttribute("disabled")}))})),document.body.addEventListener("htmx:beforeSwap",(function(e){"chat-form"===e.target.id?u("#message").value="":"logout"===e.detail.serverResponse&&(localStorage.removeItem("authToken"),window.location.reload())}))},454:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.DUNGEON_TRAVEL_BLOCK=t.CHANCE_TO_FIGHT_SPECIAL=t.ALERT_DISPLAY_LENGTH=t.STEP_DELAY=t.FIGHT_ATTACK_DELAY=void 0,t.FIGHT_ATTACK_DELAY=1500,t.STEP_DELAY=2e3,t.ALERT_DISPLAY_LENGTH=3e3,t.CHANCE_TO_FIGHT_SPECIAL=10,t.DUNGEON_TRAVEL_BLOCK=3e3},182:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TimeManager=void 0,t.TimeManager=class{constructor(e=120){this.dayLength=e,this.scaleFactor=30,this.dayLengthAsMS=60*e*1e3}dayScaleFactor(){return this.dayLength/30}getTimePeriod(){return this.isMorning()?"morning":this.isAfternoon()?"afternoon":this.isEvening()?"evening":this.isNight()?"night":void 0}getAmPm(){return this.get24Hour()<12?"am":"pm"}get24Hour(){const e=new Date,t=(e.getMinutes()+e.getHours()%2*(this.dayLength/2))/this.dayLength;return Math.floor(24*t)}getHour(){const e=this.get24Hour(),t=e>12?e-12:e;return 0===t?12:t}gradientName(){const e=Math.floor(this.get24Hour()/24*this.scaleFactor);return`sky-gradient-${e<10?"0":""}${e}`}isNight(){const e=this.get24Hour();return e>=0&&e<5||e>=21&&e<24}isMorning(){const e=this.get24Hour();return e>=5&&e<12}isAfternoon(){const e=this.get24Hour();return e>=12&&e<18}isEvening(){const e=this.get24Hour();return e>=18&&e<21}}},419:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasCORS=void 0;let s=!1;try{s="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(e){}t.hasCORS=s},754:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0,t.encode=function(e){let t="";for(let s in e)e.hasOwnProperty(s)&&(t.length&&(t+="&"),t+=encodeURIComponent(s)+"="+encodeURIComponent(e[s]));return t},t.decode=function(e){let t={},s=e.split("&");for(let e=0,n=s.length;e{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parse=void 0;const s=/^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,n=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];t.parse=function(e){const t=e,r=e.indexOf("["),o=e.indexOf("]");-1!=r&&-1!=o&&(e=e.substring(0,r)+e.substring(r,o).replace(/:/g,";")+e.substring(o,e.length));let i=s.exec(e||""),a={},c=14;for(;c--;)a[n[c]]=i[c]||"";return-1!=r&&-1!=o&&(a.source=t,a.host=a.host.substring(1,a.host.length-1).replace(/;/g,":"),a.authority=a.authority.replace("[","").replace("]","").replace(/;/g,":"),a.ipv6uri=!0),a.pathNames=function(e,t){const s=t.replace(/\/{2,9}/g,"/").split("/");return"/"!=t.slice(0,1)&&0!==t.length||s.splice(0,1),"/"==t.slice(-1)&&s.splice(s.length-1,1),s}(0,a.path),a.queryKey=function(e,t){const s={};return t.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,(function(e,t,n){t&&(s[t]=n)})),s}(0,a.query),a}},726:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.yeast=t.decode=t.encode=void 0;const s="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),n={};let r,o=0,i=0;function a(e){let t="";do{t=s[e%64]+t,e=Math.floor(e/64)}while(e>0);return t}for(t.encode=a,t.decode=function(e){let t=0;for(i=0;i{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.globalThisShim=void 0,t.globalThisShim="undefined"!=typeof self?self:"undefined"!=typeof window?window:Function("return this")()},679:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.nextTick=t.parse=t.installTimerFunctions=t.transports=t.Transport=t.protocol=t.Socket=void 0;const n=s(481);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return n.Socket}}),t.protocol=n.Socket.protocol;var r=s(870);Object.defineProperty(t,"Transport",{enumerable:!0,get:function(){return r.Transport}});var o=s(385);Object.defineProperty(t,"transports",{enumerable:!0,get:function(){return o.transports}});var i=s(622);Object.defineProperty(t,"installTimerFunctions",{enumerable:!0,get:function(){return i.installTimerFunctions}});var a=s(222);Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return a.parse}});var c=s(552);Object.defineProperty(t,"nextTick",{enumerable:!0,get:function(){return c.nextTick}})},481:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const r=s(385),o=s(622),i=s(754),a=s(222),c=n(s(802)),u=s(260),h=s(373),l=(0,c.default)("engine.io-client:socket");class d extends u.Emitter{constructor(e,t={}){super(),this.writeBuffer=[],e&&"object"==typeof e&&(t=e,e=null),e?(e=(0,a.parse)(e),t.hostname=e.host,t.secure="https"===e.protocol||"wss"===e.protocol,t.port=e.port,e.query&&(t.query=e.query)):t.host&&(t.hostname=(0,a.parse)(t.host).host),(0,o.installTimerFunctions)(this,t),this.secure=null!=t.secure?t.secure:"undefined"!=typeof location&&"https:"===location.protocol,t.hostname&&!t.port&&(t.port=this.secure?"443":"80"),this.hostname=t.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=t.port||("undefined"!=typeof location&&location.port?location.port:this.secure?"443":"80"),this.transports=t.transports||["polling","websocket"],this.writeBuffer=[],this.prevBufferLen=0,this.opts=Object.assign({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,addTrailingSlash:!0,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!0},t),this.opts.path=this.opts.path.replace(/\/$/,"")+(this.opts.addTrailingSlash?"/":""),"string"==typeof this.opts.query&&(this.opts.query=(0,i.decode)(this.opts.query)),this.id=null,this.upgrades=null,this.pingInterval=null,this.pingTimeout=null,this.pingTimeoutTimer=null,"function"==typeof addEventListener&&(this.opts.closeOnBeforeunload&&(this.beforeunloadEventListener=()=>{this.transport&&(this.transport.removeAllListeners(),this.transport.close())},addEventListener("beforeunload",this.beforeunloadEventListener,!1)),"localhost"!==this.hostname&&(this.offlineEventListener=()=>{this.onClose("transport close",{description:"network connection lost"})},addEventListener("offline",this.offlineEventListener,!1))),this.open()}createTransport(e){l('creating transport "%s"',e);const t=Object.assign({},this.opts.query);t.EIO=h.protocol,t.transport=e,this.id&&(t.sid=this.id);const s=Object.assign({},this.opts.transportOptions[e],this.opts,{query:t,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return l("options: %j",s),new r.transports[e](s)}open(){let e;if(this.opts.rememberUpgrade&&d.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))e="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((()=>{this.emitReserved("error","No transports available")}),0);e=this.transports[0]}this.readyState="opening";try{e=this.createTransport(e)}catch(e){return l("error while creating transport: %s",e),this.transports.shift(),void this.open()}e.open(),this.setTransport(e)}setTransport(e){l("setting transport %s",e.name),this.transport&&(l("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=e,e.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(e=>this.onClose("transport close",e)))}probe(e){l('probing transport "%s"',e);let t=this.createTransport(e),s=!1;d.priorWebsocketSuccess=!1;const n=()=>{s||(l('probe transport "%s" opened',e),t.send([{type:"ping",data:"probe"}]),t.once("packet",(n=>{if(!s)if("pong"===n.type&&"probe"===n.data){if(l('probe transport "%s" pong',e),this.upgrading=!0,this.emitReserved("upgrading",t),!t)return;d.priorWebsocketSuccess="websocket"===t.name,l('pausing current transport "%s"',this.transport.name),this.transport.pause((()=>{s||"closed"!==this.readyState&&(l("changing transport and sending upgrade packet"),u(),this.setTransport(t),t.send([{type:"upgrade"}]),this.emitReserved("upgrade",t),t=null,this.upgrading=!1,this.flush())}))}else{l('probe transport "%s" failed',e);const s=new Error("probe error");s.transport=t.name,this.emitReserved("upgradeError",s)}})))};function r(){s||(s=!0,u(),t.close(),t=null)}const o=s=>{const n=new Error("probe error: "+s);n.transport=t.name,r(),l('probe transport "%s" failed because of error: %s',e,s),this.emitReserved("upgradeError",n)};function i(){o("transport closed")}function a(){o("socket closed")}function c(e){t&&e.name!==t.name&&(l('"%s" works - aborting "%s"',e.name,t.name),r())}const u=()=>{t.removeListener("open",n),t.removeListener("error",o),t.removeListener("close",i),this.off("close",a),this.off("upgrading",c)};t.once("open",n),t.once("error",o),t.once("close",i),this.once("close",a),this.once("upgrading",c),t.open()}onOpen(){if(l("socket open"),this.readyState="open",d.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade){l("starting upgrade probes");let e=0;const t=this.upgrades.length;for(;e{this.onClose("ping timeout")}),this.pingInterval+this.pingTimeout),this.opts.autoUnref&&this.pingTimeoutTimer.unref()}onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBufferLen=0,0===this.writeBuffer.length?this.emitReserved("drain"):this.flush()}flush(){if("closed"!==this.readyState&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){const e=this.getWritablePackets();l("flushing %d packets in socket",e.length),this.transport.send(e),this.prevBufferLen=e.length,this.emitReserved("flush")}}getWritablePackets(){if(!(this.maxPayload&&"polling"===this.transport.name&&this.writeBuffer.length>1))return this.writeBuffer;let e=1;for(let t=0;t0&&e>this.maxPayload)return l("only send %d out of %d packets",t,this.writeBuffer.length),this.writeBuffer.slice(0,t);e+=2}return l("payload size is %d (max: %d)",e,this.maxPayload),this.writeBuffer}write(e,t,s){return this.sendPacket("message",e,t,s),this}send(e,t,s){return this.sendPacket("message",e,t,s),this}sendPacket(e,t,s,n){if("function"==typeof t&&(n=t,t=void 0),"function"==typeof s&&(n=s,s=null),"closing"===this.readyState||"closed"===this.readyState)return;(s=s||{}).compress=!1!==s.compress;const r={type:e,data:t,options:s};this.emitReserved("packetCreate",r),this.writeBuffer.push(r),n&&this.once("flush",n),this.flush()}close(){const e=()=>{this.onClose("forced close"),l("socket closing - telling transport to close"),this.transport.close()},t=()=>{this.off("upgrade",t),this.off("upgradeError",t),e()},s=()=>{this.once("upgrade",t),this.once("upgradeError",t)};return"opening"!==this.readyState&&"open"!==this.readyState||(this.readyState="closing",this.writeBuffer.length?this.once("drain",(()=>{this.upgrading?s():e()})):this.upgrading?s():e()),this}onError(e){l("socket error %j",e),d.priorWebsocketSuccess=!1,this.emitReserved("error",e),this.onClose("transport error",e)}onClose(e,t){"opening"!==this.readyState&&"open"!==this.readyState&&"closing"!==this.readyState||(l('socket close with reason: "%s"',e),this.clearTimeoutFn(this.pingTimeoutTimer),this.transport.removeAllListeners("close"),this.transport.close(),this.transport.removeAllListeners(),"function"==typeof removeEventListener&&(removeEventListener("beforeunload",this.beforeunloadEventListener,!1),removeEventListener("offline",this.offlineEventListener,!1)),this.readyState="closed",this.id=null,this.emitReserved("close",e,t),this.writeBuffer=[],this.prevBufferLen=0)}filterUpgrades(e){const t=[];let s=0;const n=e.length;for(;s{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transports=void 0;const n=s(484),r=s(308);t.transports={websocket:r.WS,polling:n.Polling}},484:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Request=t.Polling=void 0;const r=s(870),o=n(s(802)),i=s(726),a=s(754),c=s(373),u=s(666),h=s(260),l=s(622),d=s(242),p=(0,o.default)("engine.io-client:polling");function f(){}const g=null!=new u.XHR({xdomain:!1}).responseType;class m extends r.Transport{constructor(e){if(super(e),this.polling=!1,"undefined"!=typeof location){const t="https:"===location.protocol;let s=location.port;s||(s=t?"443":"80"),this.xd="undefined"!=typeof location&&e.hostname!==location.hostname||s!==e.port,this.xs=e.secure!==t}const t=e&&e.forceBase64;this.supportsBinary=g&&!t}get name(){return"polling"}doOpen(){this.poll()}pause(e){this.readyState="pausing";const t=()=>{p("paused"),this.readyState="paused",e()};if(this.polling||!this.writable){let e=0;this.polling&&(p("we are currently polling - waiting to pause"),e++,this.once("pollComplete",(function(){p("pre-pause polling complete"),--e||t()}))),this.writable||(p("we are currently writing - waiting to pause"),e++,this.once("drain",(function(){p("pre-pause writing complete"),--e||t()})))}else t()}poll(){p("polling"),this.polling=!0,this.doPoll(),this.emitReserved("poll")}onData(e){p("polling got data %s",e),(0,c.decodePayload)(e,this.socket.binaryType).forEach((e=>{if("opening"===this.readyState&&"open"===e.type&&this.onOpen(),"close"===e.type)return this.onClose({description:"transport closed by the server"}),!1;this.onPacket(e)})),"closed"!==this.readyState&&(this.polling=!1,this.emitReserved("pollComplete"),"open"===this.readyState?this.poll():p('ignoring poll - transport state "%s"',this.readyState))}doClose(){const e=()=>{p("writing close packet"),this.write([{type:"close"}])};"open"===this.readyState?(p("transport open - closing"),e()):(p("transport not open - deferring close"),this.once("open",e))}write(e){this.writable=!1,(0,c.encodePayload)(e,(e=>{this.doWrite(e,(()=>{this.writable=!0,this.emitReserved("drain")}))}))}uri(){let e=this.query||{};const t=this.opts.secure?"https":"http";let s="";!1!==this.opts.timestampRequests&&(e[this.opts.timestampParam]=(0,i.yeast)()),this.supportsBinary||e.sid||(e.b64=1),this.opts.port&&("https"===t&&443!==Number(this.opts.port)||"http"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port);const n=(0,a.encode)(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(n.length?"?"+n:"")}request(e={}){return Object.assign(e,{xd:this.xd,xs:this.xs},this.opts),new y(this.uri(),e)}doWrite(e,t){const s=this.request({method:"POST",data:e});s.on("success",t),s.on("error",((e,t)=>{this.onError("xhr post error",e,t)}))}doPoll(){p("xhr poll");const e=this.request();e.on("data",this.onData.bind(this)),e.on("error",((e,t)=>{this.onError("xhr poll error",e,t)})),this.pollXhr=e}}t.Polling=m;class y extends h.Emitter{constructor(e,t){super(),(0,l.installTimerFunctions)(this,t),this.opts=t,this.method=t.method||"GET",this.uri=e,this.async=!1!==t.async,this.data=void 0!==t.data?t.data:null,this.create()}create(){const e=(0,l.pick)(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");e.xdomain=!!this.opts.xd,e.xscheme=!!this.opts.xs;const t=this.xhr=new u.XHR(e);try{p("xhr open %s: %s",this.method,this.uri),t.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders){t.setDisableHeaderCheck&&t.setDisableHeaderCheck(!0);for(let e in this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(e)&&t.setRequestHeader(e,this.opts.extraHeaders[e])}}catch(e){}if("POST"===this.method)try{t.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(e){}try{t.setRequestHeader("Accept","*/*")}catch(e){}"withCredentials"in t&&(t.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(t.timeout=this.opts.requestTimeout),t.onreadystatechange=()=>{4===t.readyState&&(200===t.status||1223===t.status?this.onLoad():this.setTimeoutFn((()=>{this.onError("number"==typeof t.status?t.status:0)}),0))},p("xhr data %s",this.data),t.send(this.data)}catch(e){return void this.setTimeoutFn((()=>{this.onError(e)}),0)}"undefined"!=typeof document&&(this.index=y.requestsCount++,y.requests[this.index]=this)}onError(e){this.emitReserved("error",e,this.xhr),this.cleanup(!0)}cleanup(e){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=f,e)try{this.xhr.abort()}catch(e){}"undefined"!=typeof document&&delete y.requests[this.index],this.xhr=null}}onLoad(){const e=this.xhr.responseText;null!==e&&(this.emitReserved("data",e),this.emitReserved("success"),this.cleanup())}abort(){this.cleanup()}}if(t.Request=y,y.requestsCount=0,y.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",C);else if("function"==typeof addEventListener){const e="onpagehide"in d.globalThisShim?"pagehide":"unload";addEventListener(e,C,!1)}function C(){for(let e in y.requests)y.requests.hasOwnProperty(e)&&y.requests[e].abort()}},552:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.defaultBinaryType=t.usingBrowserWebSocket=t.WebSocket=t.nextTick=void 0;const n=s(242);t.nextTick="function"==typeof Promise&&"function"==typeof Promise.resolve?e=>Promise.resolve().then(e):(e,t)=>t(e,0),t.WebSocket=n.globalThisShim.WebSocket||n.globalThisShim.MozWebSocket,t.usingBrowserWebSocket=!0,t.defaultBinaryType="arraybuffer"},308:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.WS=void 0;const r=s(870),o=s(754),i=s(726),a=s(622),c=s(552),u=n(s(802)),h=s(373),l=(0,u.default)("engine.io-client:websocket"),d="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase();class p extends r.Transport{constructor(e){super(e),this.supportsBinary=!e.forceBase64}get name(){return"websocket"}doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protocols,s=d?{}:(0,a.pick)(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(s.headers=this.opts.extraHeaders);try{this.ws=c.usingBrowserWebSocket&&!d?t?new c.WebSocket(e,t):new c.WebSocket(e):new c.WebSocket(e,t,s)}catch(e){return this.emitReserved("error",e)}this.ws.binaryType=this.socket.binaryType||c.defaultBinaryType,this.addEventListeners()}addEventListeners(){this.ws.onopen=()=>{this.opts.autoUnref&&this.ws._socket.unref(),this.onOpen()},this.ws.onclose=e=>this.onClose({description:"websocket connection closed",context:e}),this.ws.onmessage=e=>this.onData(e.data),this.ws.onerror=e=>this.onError("websocket error",e)}write(e){this.writable=!1;for(let t=0;t{const t={};!c.usingBrowserWebSocket&&(s.options&&(t.compress=s.options.compress),this.opts.perMessageDeflate)&&("string"==typeof e?Buffer.byteLength(e):e.length){this.writable=!0,this.emitReserved("drain")}),this.setTimeoutFn)}))}}doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}uri(){let e=this.query||{};const t=this.opts.secure?"wss":"ws";let s="";this.opts.port&&("wss"===t&&443!==Number(this.opts.port)||"ws"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port),this.opts.timestampRequests&&(e[this.opts.timestampParam]=(0,i.yeast)()),this.supportsBinary||(e.b64=1);const n=(0,o.encode)(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(n.length?"?"+n:"")}check(){return!!c.WebSocket}}t.WS=p},666:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.XHR=void 0;const n=s(419),r=s(242);t.XHR=function(e){const t=e.xdomain;try{if("undefined"!=typeof XMLHttpRequest&&(!t||n.hasCORS))return new XMLHttpRequest}catch(e){}if(!t)try{return new(r.globalThisShim[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(e){}}},622:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.byteLength=t.installTimerFunctions=t.pick=void 0;const n=s(242);t.pick=function(e,...t){return t.reduce(((t,s)=>(e.hasOwnProperty(s)&&(t[s]=e[s]),t)),{})};const r=n.globalThisShim.setTimeout,o=n.globalThisShim.clearTimeout;t.installTimerFunctions=function(e,t){t.useNativeTimers?(e.setTimeoutFn=r.bind(n.globalThisShim),e.clearTimeoutFn=o.bind(n.globalThisShim)):(e.setTimeoutFn=n.globalThisShim.setTimeout.bind(n.globalThisShim),e.clearTimeoutFn=n.globalThisShim.clearTimeout.bind(n.globalThisShim))},t.byteLength=function(e){return"string"==typeof e?function(e){let t=0,s=0;for(let n=0,r=e.length;n=57344?s+=3:(n++,s+=4);return s}(e):Math.ceil(1.33*(e.byteLength||e.size))}},87:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ERROR_PACKET=t.PACKET_TYPES_REVERSE=t.PACKET_TYPES=void 0;const s=Object.create(null);t.PACKET_TYPES=s,s.open="0",s.close="1",s.ping="2",s.pong="3",s.message="4",s.upgrade="5",s.noop="6";const n=Object.create(null);t.PACKET_TYPES_REVERSE=n,Object.keys(s).forEach((e=>{n[s[e]]=e})),t.ERROR_PACKET={type:"error",data:"parser error"}},469:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0;const s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n="undefined"==typeof Uint8Array?[]:new Uint8Array(256);for(let e=0;e<64;e++)n[s.charCodeAt(e)]=e;t.encode=e=>{let t,n=new Uint8Array(e),r=n.length,o="";for(t=0;t>2],o+=s[(3&n[t])<<4|n[t+1]>>4],o+=s[(15&n[t+1])<<2|n[t+2]>>6],o+=s[63&n[t+2]];return r%3==2?o=o.substring(0,o.length-1)+"=":r%3==1&&(o=o.substring(0,o.length-2)+"=="),o},t.decode=e=>{let t,s,r,o,i,a=.75*e.length,c=e.length,u=0;"="===e[e.length-1]&&(a--,"="===e[e.length-2]&&a--);const h=new ArrayBuffer(a),l=new Uint8Array(h);for(t=0;t>4,l[u++]=(15&r)<<4|o>>2,l[u++]=(3&o)<<6|63&i;return h}},572:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=s(87),r=s(469),o="function"==typeof ArrayBuffer,i=(e,t)=>{if(o){const s=(0,r.decode)(e);return a(s,t)}return{base64:!0,data:e}},a=(e,t)=>"blob"===t&&e instanceof ArrayBuffer?new Blob([e]):e;t.default=(e,t)=>{if("string"!=typeof e)return{type:"message",data:a(e,t)};const s=e.charAt(0);return"b"===s?{type:"message",data:i(e.substring(1),t)}:n.PACKET_TYPES_REVERSE[s]?e.length>1?{type:n.PACKET_TYPES_REVERSE[s],data:e.substring(1)}:{type:n.PACKET_TYPES_REVERSE[s]}:n.ERROR_PACKET}},908:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=s(87),r="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===Object.prototype.toString.call(Blob),o="function"==typeof ArrayBuffer,i=(e,t)=>{const s=new FileReader;return s.onload=function(){const e=s.result.split(",")[1];t("b"+(e||""))},s.readAsDataURL(e)};t.default=({type:e,data:t},s,a)=>{return r&&t instanceof Blob?s?a(t):i(t,a):o&&(t instanceof ArrayBuffer||(c=t,"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(c):c&&c.buffer instanceof ArrayBuffer))?s?a(t):i(new Blob([t]),a):a(n.PACKET_TYPES[e]+(t||""));var c}},373:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decodePayload=t.decodePacket=t.encodePayload=t.encodePacket=t.protocol=void 0;const n=s(908);t.encodePacket=n.default;const r=s(572);t.decodePacket=r.default;const o=String.fromCharCode(30);t.encodePayload=(e,t)=>{const s=e.length,r=new Array(s);let i=0;e.forEach(((e,a)=>{(0,n.default)(e,!1,(e=>{r[a]=e,++i===s&&t(r.join(o))}))}))},t.decodePayload=(e,t)=>{const s=e.split(o),n=[];for(let e=0;e{"use strict";function s(e){e=e||{},this.ms=e.min||100,this.max=e.max||1e4,this.factor=e.factor||2,this.jitter=e.jitter>0&&e.jitter<=1?e.jitter:0,this.attempts=0}Object.defineProperty(t,"__esModule",{value:!0}),t.Backoff=void 0,t.Backoff=s,s.prototype.duration=function(){var e=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var t=Math.random(),s=Math.floor(t*this.jitter*e);e=0==(1&Math.floor(10*t))?e-s:e+s}return 0|Math.min(e,this.max)},s.prototype.reset=function(){this.attempts=0},s.prototype.setMin=function(e){this.ms=e},s.prototype.setMax=function(e){this.max=e},s.prototype.setJitter=function(e){this.jitter=e}},46:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.connect=t.io=t.Socket=t.Manager=t.protocol=void 0;const r=s(84),o=s(168);Object.defineProperty(t,"Manager",{enumerable:!0,get:function(){return o.Manager}});const i=s(312);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return i.Socket}});const a=n(s(669)).default("socket.io-client"),c={};function u(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};const s=r.url(e,t.path||"/socket.io"),n=s.source,i=s.id,u=s.path,h=c[i]&&u in c[i].nsps;let l;return t.forceNew||t["force new connection"]||!1===t.multiplex||h?(a("ignoring socket cache for %s",n),l=new o.Manager(n,t)):(c[i]||(a("new io instance for %s",n),c[i]=new o.Manager(n,t)),l=c[i]),s.query&&!t.query&&(t.query=s.queryKey),l.socket(s.path,t)}t.io=u,t.connect=u,t.default=u,Object.assign(u,{Manager:o.Manager,Socket:i.Socket,io:u,connect:u});var h=s(514);Object.defineProperty(t,"protocol",{enumerable:!0,get:function(){return h.protocol}}),e.exports=u},168:function(e,t,s){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[s]}})}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var s in e)"default"!==s&&Object.prototype.hasOwnProperty.call(e,s)&&n(t,e,s);return r(t,e),t},i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Manager=void 0;const a=s(679),c=s(312),u=o(s(514)),h=s(149),l=s(159),d=s(260),p=i(s(669)).default("socket.io-client:manager");class f extends d.Emitter{constructor(e,t){var s;super(),this.nsps={},this.subs=[],e&&"object"==typeof e&&(t=e,e=void 0),(t=t||{}).path=t.path||"/socket.io",this.opts=t,a.installTimerFunctions(this,t),this.reconnection(!1!==t.reconnection),this.reconnectionAttempts(t.reconnectionAttempts||1/0),this.reconnectionDelay(t.reconnectionDelay||1e3),this.reconnectionDelayMax(t.reconnectionDelayMax||5e3),this.randomizationFactor(null!==(s=t.randomizationFactor)&&void 0!==s?s:.5),this.backoff=new l.Backoff({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(null==t.timeout?2e4:t.timeout),this._readyState="closed",this.uri=e;const n=t.parser||u;this.encoder=new n.Encoder,this.decoder=new n.Decoder,this._autoConnect=!1!==t.autoConnect,this._autoConnect&&this.open()}reconnection(e){return arguments.length?(this._reconnection=!!e,this):this._reconnection}reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(this._reconnectionAttempts=e,this)}reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(this._reconnectionDelay=e,null===(t=this.backoff)||void 0===t||t.setMin(e),this)}randomizationFactor(e){var t;return void 0===e?this._randomizationFactor:(this._randomizationFactor=e,null===(t=this.backoff)||void 0===t||t.setJitter(e),this)}reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDelayMax:(this._reconnectionDelayMax=e,null===(t=this.backoff)||void 0===t||t.setMax(e),this)}timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}open(e){if(p("readyState %s",this._readyState),~this._readyState.indexOf("open"))return this;p("opening %s",this.uri),this.engine=new a.Socket(this.uri,this.opts);const t=this.engine,s=this;this._readyState="opening",this.skipReconnect=!1;const n=h.on(t,"open",(function(){s.onopen(),e&&e()})),r=h.on(t,"error",(t=>{p("error"),s.cleanup(),s._readyState="closed",this.emitReserved("error",t),e?e(t):s.maybeReconnectOnOpen()}));if(!1!==this._timeout){const e=this._timeout;p("connect attempt will timeout after %d",e),0===e&&n();const s=this.setTimeoutFn((()=>{p("connect attempt timed out after %d",e),n(),t.close(),t.emit("error",new Error("timeout"))}),e);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}return this.subs.push(n),this.subs.push(r),this}connect(e){return this.open(e)}onopen(){p("open"),this.cleanup(),this._readyState="open",this.emitReserved("open");const e=this.engine;this.subs.push(h.on(e,"ping",this.onping.bind(this)),h.on(e,"data",this.ondata.bind(this)),h.on(e,"error",this.onerror.bind(this)),h.on(e,"close",this.onclose.bind(this)),h.on(this.decoder,"decoded",this.ondecoded.bind(this)))}onping(){this.emitReserved("ping")}ondata(e){try{this.decoder.add(e)}catch(e){this.onclose("parse error",e)}}ondecoded(e){a.nextTick((()=>{this.emitReserved("packet",e)}),this.setTimeoutFn)}onerror(e){p("error",e),this.emitReserved("error",e)}socket(e,t){let s=this.nsps[e];return s?this._autoConnect&&!s.active&&s.connect():(s=new c.Socket(this,e,t),this.nsps[e]=s),s}_destroy(e){const t=Object.keys(this.nsps);for(const e of t)if(this.nsps[e].active)return void p("socket %s is still active, skipping close",e);this._close()}_packet(e){p("writing packet %j",e);const t=this.encoder.encode(e);for(let s=0;se())),this.subs.length=0,this.decoder.destroy()}_close(){p("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,this.onclose("forced close"),this.engine&&this.engine.close()}disconnect(){return this._close()}onclose(e,t){p("closed due to %s",e),this.cleanup(),this.backoff.reset(),this._readyState="closed",this.emitReserved("close",e,t),this._reconnection&&!this.skipReconnect&&this.reconnect()}reconnect(){if(this._reconnecting||this.skipReconnect)return this;const e=this;if(this.backoff.attempts>=this._reconnectionAttempts)p("reconnect failed"),this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{const t=this.backoff.duration();p("will wait %dms before reconnect attempt",t),this._reconnecting=!0;const s=this.setTimeoutFn((()=>{e.skipReconnect||(p("attempting reconnect"),this.emitReserved("reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((t=>{t?(p("reconnect attempt error"),e._reconnecting=!1,e.reconnect(),this.emitReserved("reconnect_error",t)):(p("reconnect success"),e.onreconnect())})))}),t);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}}onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",e)}}t.Manager=f},149:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.on=void 0,t.on=function(e,t,s){return e.on(t,s),function(){e.off(t,s)}}},312:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const r=s(514),o=s(149),i=s(260),a=n(s(669)).default("socket.io-client:socket"),c=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1});class u extends i.Emitter{constructor(e,t,s){super(),this.connected=!1,this.recovered=!1,this.receiveBuffer=[],this.sendBuffer=[],this._queue=[],this._queueSeq=0,this.ids=0,this.acks={},this.flags={},this.io=e,this.nsp=t,s&&s.auth&&(this.auth=s.auth),this._opts=Object.assign({},s),this.io._autoConnect&&this.open()}get disconnected(){return!this.connected}subEvents(){if(this.subs)return;const e=this.io;this.subs=[o.on(e,"open",this.onopen.bind(this)),o.on(e,"packet",this.onpacket.bind(this)),o.on(e,"error",this.onerror.bind(this)),o.on(e,"close",this.onclose.bind(this))]}get active(){return!!this.subs}connect(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}open(){return this.connect()}send(...e){return e.unshift("message"),this.emit.apply(this,e),this}emit(e,...t){if(c.hasOwnProperty(e))throw new Error('"'+e.toString()+'" is a reserved event name');if(t.unshift(e),this._opts.retries&&!this.flags.fromQueue&&!this.flags.volatile)return this._addToQueue(t),this;const s={type:r.PacketType.EVENT,data:t,options:{}};if(s.options.compress=!1!==this.flags.compress,"function"==typeof t[t.length-1]){const e=this.ids++;a("emitting packet with ack id %d",e);const n=t.pop();this._registerAckCallback(e,n),s.id=e}const n=this.io.engine&&this.io.engine.transport&&this.io.engine.transport.writable;return!this.flags.volatile||n&&this.connected?this.connected?(this.notifyOutgoingListeners(s),this.packet(s)):this.sendBuffer.push(s):a("discard packet as the transport is not currently writable"),this.flags={},this}_registerAckCallback(e,t){var s;const n=null!==(s=this.flags.timeout)&&void 0!==s?s:this._opts.ackTimeout;if(void 0===n)return void(this.acks[e]=t);const r=this.io.setTimeoutFn((()=>{delete this.acks[e];for(let t=0;t{this.io.clearTimeoutFn(r),t.apply(this,[null,...e])}}emitWithAck(e,...t){const s=void 0!==this.flags.timeout||void 0!==this._opts.ackTimeout;return new Promise(((n,r)=>{t.push(((e,t)=>s?e?r(e):n(t):n(e))),this.emit(e,...t)}))}_addToQueue(e){let t;"function"==typeof e[e.length-1]&&(t=e.pop());const s={id:this._queueSeq++,tryCount:0,pending:!1,args:e,flags:Object.assign({fromQueue:!0},this.flags)};e.push(((e,...n)=>{if(s===this._queue[0])return null!==e?s.tryCount>this._opts.retries&&(a("packet [%d] is discarded after %d tries",s.id,s.tryCount),this._queue.shift(),t&&t(e)):(a("packet [%d] was successfully sent",s.id),this._queue.shift(),t&&t(null,...n)),s.pending=!1,this._drainQueue()})),this._queue.push(s),this._drainQueue()}_drainQueue(e=!1){if(a("draining queue"),!this.connected||0===this._queue.length)return;const t=this._queue[0];!t.pending||e?(t.pending=!0,t.tryCount++,a("sending packet [%d] (try n°%d)",t.id,t.tryCount),this.flags=t.flags,this.emit.apply(this,t.args)):a("packet [%d] has already been sent and is waiting for an ack",t.id)}packet(e){e.nsp=this.nsp,this.io._packet(e)}onopen(){a("transport is open - connecting"),"function"==typeof this.auth?this.auth((e=>{this._sendConnectPacket(e)})):this._sendConnectPacket(this.auth)}_sendConnectPacket(e){this.packet({type:r.PacketType.CONNECT,data:this._pid?Object.assign({pid:this._pid,offset:this._lastOffset},e):e})}onerror(e){this.connected||this.emitReserved("connect_error",e)}onclose(e,t){a("close (%s)",e),this.connected=!1,delete this.id,this.emitReserved("disconnect",e,t)}onpacket(e){if(e.nsp===this.nsp)switch(e.type){case r.PacketType.CONNECT:e.data&&e.data.sid?this.onconnect(e.data.sid,e.data.pid):this.emitReserved("connect_error",new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));break;case r.PacketType.EVENT:case r.PacketType.BINARY_EVENT:this.onevent(e);break;case r.PacketType.ACK:case r.PacketType.BINARY_ACK:this.onack(e);break;case r.PacketType.DISCONNECT:this.ondisconnect();break;case r.PacketType.CONNECT_ERROR:this.destroy();const t=new Error(e.data.message);t.data=e.data.data,this.emitReserved("connect_error",t)}}onevent(e){const t=e.data||[];a("emitting event %j",t),null!=e.id&&(a("attaching ack callback to event"),t.push(this.ack(e.id))),this.connected?this.emitEvent(t):this.receiveBuffer.push(Object.freeze(t))}emitEvent(e){if(this._anyListeners&&this._anyListeners.length){const t=this._anyListeners.slice();for(const s of t)s.apply(this,e)}super.emit.apply(this,e),this._pid&&e.length&&"string"==typeof e[e.length-1]&&(this._lastOffset=e[e.length-1])}ack(e){const t=this;let s=!1;return function(...n){s||(s=!0,a("sending ack %j",n),t.packet({type:r.PacketType.ACK,id:e,data:n}))}}onack(e){const t=this.acks[e.id];"function"==typeof t?(a("calling ack %s with %j",e.id,e.data),t.apply(this,e.data),delete this.acks[e.id]):a("bad ack %s",e.id)}onconnect(e,t){a("socket connected with id %s",e),this.id=e,this.recovered=t&&this._pid===t,this._pid=t,this.connected=!0,this.emitBuffered(),this.emitReserved("connect"),this._drainQueue(!0)}emitBuffered(){this.receiveBuffer.forEach((e=>this.emitEvent(e))),this.receiveBuffer=[],this.sendBuffer.forEach((e=>{this.notifyOutgoingListeners(e),this.packet(e)})),this.sendBuffer=[]}ondisconnect(){a("server disconnect (%s)",this.nsp),this.destroy(),this.onclose("io server disconnect")}destroy(){this.subs&&(this.subs.forEach((e=>e())),this.subs=void 0),this.io._destroy(this)}disconnect(){return this.connected&&(a("performing disconnect (%s)",this.nsp),this.packet({type:r.PacketType.DISCONNECT})),this.destroy(),this.connected&&this.onclose("io client disconnect"),this}close(){return this.disconnect()}compress(e){return this.flags.compress=e,this}get volatile(){return this.flags.volatile=!0,this}timeout(e){return this.flags.timeout=e,this}onAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.push(e),this}prependAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.unshift(e),this}offAny(e){if(!this._anyListeners)return this;if(e){const t=this._anyListeners;for(let s=0;s{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.reconstructPacket=t.deconstructPacket=void 0;const n=s(665);function r(e,t){if(!e)return e;if((0,n.isBinary)(e)){const s={_placeholder:!0,num:t.length};return t.push(e),s}if(Array.isArray(e)){const s=new Array(e.length);for(let n=0;n=0&&e.num{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Decoder=t.Encoder=t.PacketType=t.protocol=void 0;const n=s(260),r=s(880),o=s(665),i=(0,s(618).default)("socket.io-parser");var a;t.protocol=5,function(e){e[e.CONNECT=0]="CONNECT",e[e.DISCONNECT=1]="DISCONNECT",e[e.EVENT=2]="EVENT",e[e.ACK=3]="ACK",e[e.CONNECT_ERROR=4]="CONNECT_ERROR",e[e.BINARY_EVENT=5]="BINARY_EVENT",e[e.BINARY_ACK=6]="BINARY_ACK"}(a=t.PacketType||(t.PacketType={})),t.Encoder=class{constructor(e){this.replacer=e}encode(e){return i("encoding packet %j",e),e.type!==a.EVENT&&e.type!==a.ACK||!(0,o.hasBinary)(e)?[this.encodeAsString(e)]:this.encodeAsBinary({type:e.type===a.EVENT?a.BINARY_EVENT:a.BINARY_ACK,nsp:e.nsp,data:e.data,id:e.id})}encodeAsString(e){let t=""+e.type;return e.type!==a.BINARY_EVENT&&e.type!==a.BINARY_ACK||(t+=e.attachments+"-"),e.nsp&&"/"!==e.nsp&&(t+=e.nsp+","),null!=e.id&&(t+=e.id),null!=e.data&&(t+=JSON.stringify(e.data,this.replacer)),i("encoded %j as %s",e,t),t}encodeAsBinary(e){const t=(0,r.deconstructPacket)(e),s=this.encodeAsString(t.packet),n=t.buffers;return n.unshift(s),n}};class c extends n.Emitter{constructor(e){super(),this.reviver=e}add(e){let t;if("string"==typeof e){if(this.reconstructor)throw new Error("got plaintext data when reconstructing a packet");t=this.decodeString(e);const s=t.type===a.BINARY_EVENT;s||t.type===a.BINARY_ACK?(t.type=s?a.EVENT:a.ACK,this.reconstructor=new u(t),0===t.attachments&&super.emitReserved("decoded",t)):super.emitReserved("decoded",t)}else{if(!(0,o.isBinary)(e)&&!e.base64)throw new Error("Unknown type: "+e);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");t=this.reconstructor.takeBinaryData(e),t&&(this.reconstructor=null,super.emitReserved("decoded",t))}}decodeString(e){let t=0;const s={type:Number(e.charAt(0))};if(void 0===a[s.type])throw new Error("unknown packet type "+s.type);if(s.type===a.BINARY_EVENT||s.type===a.BINARY_ACK){const n=t+1;for(;"-"!==e.charAt(++t)&&t!=e.length;);const r=e.substring(n,t);if(r!=Number(r)||"-"!==e.charAt(t))throw new Error("Illegal attachments");s.attachments=Number(r)}if("/"===e.charAt(t+1)){const n=t+1;for(;++t&&","!==e.charAt(t)&&t!==e.length;);s.nsp=e.substring(n,t)}else s.nsp="/";const n=e.charAt(t+1);if(""!==n&&Number(n)==n){const n=t+1;for(;++t;){const s=e.charAt(t);if(null==s||Number(s)!=s){--t;break}if(t===e.length)break}s.id=Number(e.substring(n,t+1))}if(e.charAt(++t)){const n=this.tryParse(e.substr(t));if(!c.isPayloadValid(s.type,n))throw new Error("invalid payload");s.data=n}return i("decoded %s as %j",e,s),s}tryParse(e){try{return JSON.parse(e,this.reviver)}catch(e){return!1}}static isPayloadValid(e,t){switch(e){case a.CONNECT:return"object"==typeof t;case a.DISCONNECT:return void 0===t;case a.CONNECT_ERROR:return"string"==typeof t||"object"==typeof t;case a.EVENT:case a.BINARY_EVENT:return Array.isArray(t)&&("string"==typeof t[0]||"number"==typeof t[0]);case a.ACK:case a.BINARY_ACK:return Array.isArray(t)}}destroy(){this.reconstructor&&(this.reconstructor.finishedReconstruction(),this.reconstructor=null)}}t.Decoder=c;class u{constructor(e){this.packet=e,this.buffers=[],this.reconPack=e}takeBinaryData(e){if(this.buffers.push(e),this.buffers.length===this.reconPack.attachments){const e=(0,r.reconstructPacket)(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null}finishedReconstruction(){this.reconPack=null,this.buffers=[]}}},665:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasBinary=t.isBinary=void 0;const s="function"==typeof ArrayBuffer,n=Object.prototype.toString,r="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===n.call(Blob),o="function"==typeof File||"undefined"!=typeof File&&"[object FileConstructor]"===n.call(File);function i(e){return s&&(e instanceof ArrayBuffer||(e=>"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(e):e.buffer instanceof ArrayBuffer)(e))||r&&e instanceof Blob||o&&e instanceof File}t.isBinary=i,t.hasBinary=function e(t,s){if(!t||"object"!=typeof t)return!1;if(Array.isArray(t)){for(let s=0,n=t.length;s{"use strict";function n(e){if(e)return function(e){for(var t in n.prototype)e[t]=n.prototype[t];return e}(e)}s.r(t),s.d(t,{Emitter:()=>n}),n.prototype.on=n.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+e]=this._callbacks["$"+e]||[]).push(t),this},n.prototype.once=function(e,t){function s(){this.off(e,s),t.apply(this,arguments)}return s.fn=t,this.on(e,s),this},n.prototype.off=n.prototype.removeListener=n.prototype.removeAllListeners=n.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var s,n=this._callbacks["$"+e];if(!n)return this;if(1==arguments.length)return delete this._callbacks["$"+e],this;for(var r=0;r{for(var n in t)s.o(t,n)&&!s.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),s.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s(628)})(); \ No newline at end of file diff --git a/public/assets/css/game.css b/public/assets/css/game.css index 898b78a..f910410 100644 --- a/public/assets/css/game.css +++ b/public/assets/css/game.css @@ -785,3 +785,7 @@ footer { overflow: auto; } } + +.dungeon-room-description { + padding: 1rem; +} diff --git a/seeds/cities.ts b/seeds/cities.ts index 2e1bfba..866907f 100644 --- a/seeds/cities.ts +++ b/seeds/cities.ts @@ -73,7 +73,8 @@ export async function createLocations(): Promise { type: r.fields.Type, city_id: r.fields.city_id[0], display_order: r.fields["Display Order"], - event_name: r.fields['event_name'] + event_name: r.fields['event_name'], + min_level: Math.max(parseInt(r.fields['Min Level'].toString()), 1) } })).onConflict('id').merge(); diff --git a/seeds/dungeons.ts b/seeds/dungeons.ts new file mode 100644 index 0000000..eb210d1 --- /dev/null +++ b/seeds/dungeons.ts @@ -0,0 +1,176 @@ +import { config as dotenv } from 'dotenv'; +import { db } from "../src/server/lib/db"; +import { join } from 'path'; +import { Dungeon, DungeonRoom, RoomExit } from '../src/shared/dungeon'; +import * as fs from 'fs'; +import * as marked from 'marked'; +import { map, max } from 'lodash'; + +dotenv(); + +type TwisonLink = { + name: string; + ink: string; + pid: string; +} + +type TwisonPassage = { + text: string; + name: string; + pid: string; + props?: { + fight?: { + monster_id: string; + one_time: string; + }, + visit?: Record, + end?: string, + rewards?: { + base: { + exp?: string, + gold?: string + }, + per_kill_bonus?: { + exp?: string, + gold?: string + } + } + }, + position: { + x: string; + y: string; + }; + links:TwisonLink[] +} + +type TwisonDungeon = { + passages: TwisonPassage[]; + name: string; + startnode: string; + creator: string; + 'creator-version': string; + ifid: string; +} + +async function getFileData(filename: string): Promise { + const data = fs.readFileSync(join(__dirname, '..', 'data', 'dungeons', filename), 'utf8'); + + console.log(data); + + return JSON.parse(data) as TwisonDungeon; +} + +export async function main(filename: string, done?: any) { + await db('dungeon_players').delete(); + + const raw = await getFileData(filename); + + // attempt to create base dungeon! + const dungeon: Dungeon = (await db('dungeons').insert({ + id: raw.ifid.toLowerCase(), + name: raw.name + }).onConflict('id').merge().returning('*')).pop(); + + // clear the rooms for the created dungeon + await db('dungeon_rooms').where({dungeon_id: dungeon.id}).delete(); + + // create the rooms first! + const roomsToCreate = raw.passages.map(passage => { + let data: Omit = { + dungeon_id: dungeon.id, + description: marked.parse(passage.text.split('')[0]), + exits: [], + settings: {} + }; + + if(passage.props) { + if(passage.props.fight) { + data.settings.fight = { + monster_id: parseInt(passage.props.fight.monster_id), + one_time: passage.props.fight.one_time.toLowerCase() === 'true' + } + } + if(passage.props.visit) { + data.settings.visit = map(passage.props.visit, (str: string, index: string) => { + return { + visit_number: parseInt(index), + description: marked.parse(str) + } + }); + } + if(passage.props.end) { + data.settings.end = true; + } + if(passage.props.rewards) { + data.settings.rewards = { + base: { + exp: max([parseInt(passage.props.rewards.base.exp || '0'), 0]), + gold: max([parseInt(passage.props.rewards.base.gold || '0'), 0]), + } + }; + + if(passage.props.rewards.per_kill_bonus) { + data.settings.rewards.per_kill_bonus = { + exp: max([parseInt(passage.props.rewards.per_kill_bonus.exp || '0'), 0]), + gold: max([parseInt(passage.props.rewards.per_kill_bonus.gold || '0'), 0]), + } + } + } + } + + return data; + }); + + const createdRooms: DungeonRoom[] = await db('dungeon_rooms').insert(roomsToCreate,).returning('*'); + + console.log(createdRooms); + + // set the starting room! + await db('dungeons').update({starting_room: createdRooms[pidToIndex(raw.startnode)].id.toLowerCase()}).where({ + id: dungeon.id + }); + + const exits = raw.passages.map(passage => { + const roomIndex = pidToIndex(passage.pid); + let exits: RoomExit[] = []; + + // ending nodes don't have any links + if(passage.links) { + exits = passage.links.map(link => { + const pid = pidToIndex(link.pid); + return { + name: link.name, + target_room_id: createdRooms[pid].id + } + }); + } + + return { + id: createdRooms[roomIndex].id, + exits + }; + }); + + let i = 0; + exits.map(async exit => { + await db('dungeon_rooms').update({exits: JSON.stringify(exit.exits)}).where({ + id: exit.id + }); + console.log(`${++i}/${raw.passages.length} rooms created`); + + if(i === raw.passages.length) { + done(); + } + }); + + console.log(JSON.stringify(exits, null, 2)); +} + +function pidToIndex(str: string): number { + return parseInt(str)-1; +} + +main('storage_cellar.json', () => { + console.log('Dungeons created!'); + process.exit(0); +}); diff --git a/src/client/htmx.ts b/src/client/htmx.ts index 2dc5608..5b14ef3 100644 --- a/src/client/htmx.ts +++ b/src/client/htmx.ts @@ -119,6 +119,12 @@ $('body').addEventListener('click', e => { if(target.getAttribute('formmethod') === 'dialog' && target.getAttribute('value') === 'cancel') { target.closest('dialog')?.close(); + // sometimes dialog buttons have a "nav direct" + const attr = target.getAttribute('nav-trigger'); + if(attr) { + const [selector, click_num] = attr.split('|'); + $$(selector)[click_num].click(); + } } }); diff --git a/src/server/admin.ts b/src/server/admin.ts new file mode 100644 index 0000000..e45466d --- /dev/null +++ b/src/server/admin.ts @@ -0,0 +1,6 @@ +import { Permission } from "../shared/player"; +import { db } from './lib/db'; + +export async function givePlayerPermission(player_id: string, permission: Permission) { + return db('player_permissions').insert({player_id, permission}); +} diff --git a/src/server/api.ts b/src/server/api.ts index 0aa2689..c476f77 100644 --- a/src/server/api.ts +++ b/src/server/api.ts @@ -18,10 +18,10 @@ import {maxHp, maxVigor, Player} from '../shared/player'; import {createFight, getMonsterList, getMonsterLocation, getRandomMonster, loadMonster, loadMonsterFromFight, loadMonsterWithFaction} from './monster'; import {addInventoryItem, getEquippedItems, getInventory, getInventoryItem} from './inventory'; import { getItemFromPlayer, getItemFromShop, getPlayersItems, getShopItems, givePlayerItem, updateItemCount } from './items'; -import {FightTrigger, Monster, MonsterForFight} from '../shared/monsters'; +import {FightTrigger, Monster} from '../shared/monsters'; import {getShopEquipment, listShopItems } from './shopEquipment'; import {EquipmentSlot} from '../shared/inventory'; -import { clearTravelPlan, completeTravel, getAllPaths, getAllServices, getCityDetails, getService, getTravelPlan, stepForward, travel } from './map'; +import { clearTravelPlan, completeTravel, getAllPaths, getAllServices, getCityDetails, getService, getTravelPlan, stepForward, travel, getDungeon } from './map'; import { signup, login, authEndpoint } from './auth'; import {db} from './lib/db'; import { getPlayerSkills} from './skills'; @@ -32,8 +32,10 @@ import { fightRound, blockPlayerInFight } from './fight'; import { router as healerRouter } from './locations/healer'; import { router as professionRouter } from './locations/recruiter'; import { router as repairRouter } from './locations/repair'; +import { router as dungeonRouter } from './locations/dungeon'; import * as Alert from './views/alert'; +import { ExplorePane } from './views/components/explore-pane'; import { renderPlayerBar } from './views/player-bar' import { renderEquipmentDetails, renderStore } from './views/stores'; import { renderMap } from './views/map'; @@ -49,11 +51,15 @@ import { renderChatMessage } from './views/chat'; import { Item, PlayerItem, ShopItem } from 'shared/items'; import { equip, unequip } from './equipment'; import { HealthPotionSmall } from '../shared/items/health_potion'; +import { completeDungeonFight, getActiveDungeon, getRoomVists, loadRoom, blockPlayerInDungeon } from './dungeon'; +import { renderDungeon, renderDungeonRoom } from './views/dungeons/room'; +import { flushBuffer, addEvent } from './events'; dotenv(); otel.s(); +flushBuffer(); const app = express(); const server = http.createServer(app); @@ -140,12 +146,15 @@ io.on('connection', async socket => { // this is a special event to let the client know it can start // requesting data socket.emit('ready'); + + addEvent('LOGIN', player.id); }); app.use(healerRouter); app.use(professionRouter); app.use(repairRouter); +app.use(dungeonRouter); app.get('/chat/history', authEndpoint, async (req: Request, res: Response) => { @@ -163,14 +172,12 @@ app.post('/chat', authEndpoint, async (req: Request, res: Response) => { } if(msg.startsWith('/server') && req.player.permissions.includes('admin')) { + const sender = io.sockets.sockets.get(cache.get(`socket:${req.player.id}`)); try { - const output = await handleChatCommands(msg, req.player, io); - if(output) { - io.to(cache.get(`socket:${req.player.id}`)).emit('chat', renderChatMessage(output)); - } + await handleChatCommands(msg, req.player, io, sender); } catch(e) { - io.to(cache.get(`socket:${req.player.id}`)).emit('chat', renderChatMessage(broadcastMessage('server', e.message))); + sender.emit('chat', renderChatMessage(broadcastMessage('server', e.message))); } } else if(msg === '/online') { @@ -235,7 +242,7 @@ app.get('/player/inventory', authEndpoint, async (req: Request, res: Response) = res.send(renderInventoryPage(inventory, items)); }); -app.post('/player/equip/:item_id/:slot', authEndpoint, blockPlayerInFight, async (req: Request, res: Response) => { +app.post('/player/equip/:item_id/:slot', authEndpoint, blockPlayerInFight, blockPlayerInDungeon, async (req: Request, res: Response) => { const inventoryItem = await getInventoryItem(req.player.id, req.params.item_id); const equippedItems = await getEquippedItems(req.player.id); const requestedSlot = req.params.slot; @@ -287,7 +294,7 @@ app.post('/player/equip/:item_id/:slot', authEndpoint, blockPlayerInFight, async res.send(renderInventoryPage(inventory, items, inventoryItem.type) + renderPlayerBar(req.player)); }); -app.post('/player/unequip/:item_id', authEndpoint, blockPlayerInFight, async (req: Request, res: Response) => { +app.post('/player/unequip/:item_id', authEndpoint, blockPlayerInFight, blockPlayerInDungeon, async (req: Request, res: Response) => { const [item, ] = await Promise.all([ getInventoryItem(req.player.id, req.params.item_id), unequip(req.player.id, req.params.item_id) @@ -310,44 +317,53 @@ app.get('/player/explore', authEndpoint, async (req: Request, res: Response) => closestTown = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id; } - if(fight) { + if(fight && req.player.hp > 0) { const location = await getMonsterLocation(fight.ref_id); res.send(renderPlayerBar(req.player) + renderFightPreRound(fight, true, location, closestTown)); + return; } - else { - if(travelPlan) { - // traveling! - const chanceToSeeMonster = random(0, 100); - const things: any[] = []; - if(chanceToSeeMonster <= 30) { - const monster = await getRandomMonster([closestTown]); - things.push(monster); - } - // STEP_DELAY - const nextAction = cache[`step:${req.player.id}`] || 0; + const dungeon = await getActiveDungeon(req.player.id); + if(dungeon && req.player.hp > 0) { + const service = await getDungeon(dungeon.dungeon_id); + const room = await loadRoom(dungeon.current_room_id); + const visits = await getRoomVists(req.player.id, service.event_name); - res.send(renderPlayerBar(req.player) + renderTravel({ - things, - nextAction, - closestTown: closestTown, - walkingText: '', - travelPlan - })); - } - else { - // display the city info! - const [city, locations, paths] = await Promise.all([ - getCityDetails(req.player.city_id), - getAllServices(req.player.city_id), - getAllPaths(req.player.city_id) - ]); - - res.send(renderPlayerBar(req.player) + await renderMap({city, locations, paths}, closestTown)); + res.send(ExplorePane(service.city_id, renderDungeon(service.city_name, service.name, room, visits))); + return; + } + + if(travelPlan && req.player.hp > 0) { + // traveling! + const chanceToSeeMonster = random(0, 100); + const things: any[] = []; + if(chanceToSeeMonster <= 30) { + const monster = await getRandomMonster([closestTown]); + things.push(monster); } + // STEP_DELAY + const nextAction = cache[`step:${req.player.id}`] || 0; + + res.send(renderPlayerBar(req.player) + renderTravel({ + things, + nextAction, + closestTown: closestTown, + walkingText: '', + travelPlan + })); + return; } + + // display the default explore view + const [city, locations, paths] = await Promise.all([ + getCityDetails(req.player.city_id), + getAllServices(req.player.city_id, req.player.level), + getAllPaths(req.player.city_id) + ]); + + res.send(renderPlayerBar(req.player) + await renderMap({city, locations, paths}, closestTown)); }); // used to purchase equipment from a particular shop @@ -593,6 +609,40 @@ app.post('/fight/turn', authEndpoint, async (req: Request, res: Response) => { }); + if(fightData.roundData.winner !== 'in-progress') { + delete cache[fightBlockKey]; + } + + if(fightData.roundData.winner === 'player') { + //@TODO: Add equipped weapons + addEvent('MONSTER_KILLED', req.player.id, { + monster_id: monster.ref_id, + monster_name: monster.name, + monster_level: monster.level, + fight_trigger: monster.fight_trigger, + }); + } + else if(fightData.roundData.winner === 'monster') { + addEvent('PLAYER_KILLED', req.player.id, { + monster_id: monster.ref_id, + monster_name: monster.name, + monster_level: monster.level, + fight_trigger: monster.fight_trigger + }); + } + + + if(monster.fight_trigger === 'dungeon-forced' && fightData.roundData.winner === 'player') { + // ok the player was in a dungeon, lets make sure + // that they complete whatever dungeon room they are in + const dungeonState = await completeDungeonFight(req.player.id, monster); + const room = await loadRoom(dungeonState.current_room_id); + const visits = await getRoomVists(req.player.id, room.dungeon_id); + + res.send(renderDungeonRoom(room, visits)); + return; + } + let html = renderFight( monster, renderRoundDetails(fightData.roundData), @@ -600,10 +650,6 @@ app.post('/fight/turn', authEndpoint, async (req: Request, res: Response) => { cache[fightBlockKey] ); - if(fightData.roundData.winner !== 'in-progress') { - delete cache[fightBlockKey]; - } - if(fightData.monsters.length && monster.fight_trigger === 'explore') { html += renderMonsterSelector(fightData.monsters, monster.ref_id); } @@ -679,7 +725,7 @@ app.post('/travel/step', authEndpoint, async (req: Request, res: Response) => { const [city, locations, paths] = await Promise.all([ getCityDetails(travel.destination_id), - getAllServices(travel.destination_id), + getAllServices(travel.destination_id, req.player.level), getAllPaths(travel.destination_id) ]); @@ -736,7 +782,7 @@ app.post('/travel/return-to-source', authEndpoint, async (req: Request, res: Res else { const [city, locations, paths] = await Promise.all([ getCityDetails(req.player.city_id), - getAllServices(req.player.city_id), + getAllServices(req.player.city_id, req.player.level), getAllPaths(req.player.city_id) ]); diff --git a/src/server/chat-commands.ts b/src/server/chat-commands.ts index 5e43627..527e77e 100644 --- a/src/server/chat-commands.ts +++ b/src/server/chat-commands.ts @@ -1,52 +1,24 @@ -import { Server } from 'socket.io'; -import { maxHp, maxVigor, Player } from '../shared/player'; -import { createMonsters } from '../../seeds/monsters'; -import { createAllCitiesAndLocations } from '../../seeds/cities'; -import { createShopItems, createShopEquipment } from '../../seeds/shop_items'; -import { broadcastMessage, Message } from '../shared/message'; -import { updatePlayer } from './player'; +import { Server, Socket } from 'socket.io'; +import { Player } from '../shared/player'; +import { broadcastMessage } from '../shared/message'; +import { renderChatMessage } from './views/chat'; +import { Commands } from './chat-commands/'; -export async function handleChatCommands(msg: string, player: Player, io: Server): Promise { - let message: Message; - if(msg === '/server refresh-monsters') { - await createMonsters(); - message = broadcastMessage('server', 'Monster refresh!'); - } - else if(msg === '/server refresh-cities') { - await createAllCitiesAndLocations(); - message = broadcastMessage('server', 'Cities, Locations, and Paths refreshed!'); - } - else if(msg === '/server refresh-shops') { - await createShopItems(); - await createShopEquipment(); - message = broadcastMessage('server', 'Refresh shop items'); - } - else if(msg.startsWith('/server set-level')) { - const level = parseInt(msg.split(' ').pop()); - if(level < 1) { - message = broadcastMessage('server', 'Needs to be at least level 1'); - } - else { - message = broadcastMessage('server', `Set player level: ${level}`); - player.level = level; - player.strength = 4; - player.constitution = 4; - player.dexterity = 4; - player.intelligence = 4; - player.hp = maxHp(player.constitution, player.level); - player.vigor = maxVigor(player.constitution, player.level); - player.stat_points = level-1; +export async function handleChatCommands(msg: string, player: Player, io: Server, sender: Socket): Promise { + const rawCommand = msg.split('/server ')[1]; - await updatePlayer(player); + let matched = false; + Commands.forEach(async command => { + if(command.regex.test(rawCommand)) { + matched = true; + console.log(`${player.username} running command: [${rawCommand}]`); + await command.handler(rawCommand, sender, player, io); } - } - else { - const str = msg.split('/server ')[1]; - if(str) { - message = broadcastMessage('server', str); - } - } + }); - return message; + if(!matched) { + const message = broadcastMessage('server', `Invalid command: [${rawCommand}]`); + sender.emit('chat', renderChatMessage(message)); + } } diff --git a/src/server/chat-commands/base.ts b/src/server/chat-commands/base.ts new file mode 100644 index 0000000..8241067 --- /dev/null +++ b/src/server/chat-commands/base.ts @@ -0,0 +1,14 @@ +import type { Player } from '../../shared/player'; +import type { Server, Socket } from 'socket.io'; + +type ChatCommandHandler = (command: string, sender: Socket, player: Player, io: Server) => Promise; + +export class ChatCommand { + constructor( + public name: string, + public regex: RegExp, + public handler: ChatCommandHandler + ) { + + } +} diff --git a/src/server/chat-commands/give-permission.ts b/src/server/chat-commands/give-permission.ts new file mode 100644 index 0000000..2586f8c --- /dev/null +++ b/src/server/chat-commands/give-permission.ts @@ -0,0 +1,31 @@ +import { Socket } from 'socket.io'; +import { Permission, PermissionGuard, Player } from '../../shared/player'; +import { ChatCommand } from './base'; +import { givePlayerPermission } from '../admin'; +import { findPlayerByUsername } from '../player'; +import { broadcastMessage, Message } from '../../shared/message'; +import { renderChatMessage } from './../views/chat'; + +async function handler(rawCommand: string, sender: Socket, player: Player) { + if(player.permissions.includes('admin')) { + const pieces = rawCommand.split(' '); + const username = pieces[1]; + const permission = pieces[2]; + + if(PermissionGuard(permission)) { + const recipient = await findPlayerByUsername(username); + if(player) { + await givePlayerPermission(recipient.id, permission as Permission); + + const message: Message = broadcastMessage('server', `Granted ${permission} to ${recipient.username}`); + sender.emit('chat', renderChatMessage(message)); + } + else { + const message: Message = broadcastMessage('server', `Cant find user [${username}]`); + sender.emit('chat', renderChatMessage(message)); + } + } + } +} + +export const setPermission = new ChatCommand('give-permission', new RegExp(/^give-permission (.*)+/), handler); diff --git a/src/server/chat-commands/index.ts b/src/server/chat-commands/index.ts new file mode 100644 index 0000000..2ea13bc --- /dev/null +++ b/src/server/chat-commands/index.ts @@ -0,0 +1,16 @@ +import { ChatCommand } from "./base"; +import { refreshMonsters } from "./refresh-monsters"; +import { refreshCities } from './refresh-cities'; +import { refreshShops } from './refresh-shops'; +import { setLevel } from './set-level'; +import { say } from './say'; +import { setPermission } from './give-permission'; + +export const Commands = new Set(); + +Commands.add(refreshMonsters); +Commands.add(refreshCities); +Commands.add(refreshShops); +Commands.add(setLevel); +Commands.add(say); +Commands.add(setPermission); diff --git a/src/server/chat-commands/refresh-cities.ts b/src/server/chat-commands/refresh-cities.ts new file mode 100644 index 0000000..25c94cb --- /dev/null +++ b/src/server/chat-commands/refresh-cities.ts @@ -0,0 +1,16 @@ +import { ChatCommand } from './base'; +import { Socket } from 'socket.io'; +import { createAllCitiesAndLocations } from '../../../seeds/cities'; +import { broadcastMessage } from '../../shared/message'; +import { renderChatMessage } from './../views/chat'; +import { Player } from '../../shared/player'; + +async function handler(rawCommand: string, sender: Socket, player: Player) { + if(player.permissions.includes('admin')) { + await createAllCitiesAndLocations(); + const message = broadcastMessage('server', 'Cities, Locations, and Paths refreshed!'); + sender.emit('chat', renderChatMessage(message)); + } +} + +export const refreshCities = new ChatCommand('refresh-cities', new RegExp(/^refresh-cities/), handler); diff --git a/src/server/chat-commands/refresh-monsters.ts b/src/server/chat-commands/refresh-monsters.ts new file mode 100644 index 0000000..e0c0624 --- /dev/null +++ b/src/server/chat-commands/refresh-monsters.ts @@ -0,0 +1,16 @@ +import { ChatCommand } from './base'; +import { Socket } from 'socket.io'; +import { createMonsters } from '../../../seeds/monsters'; +import { broadcastMessage } from '../../shared/message'; +import { renderChatMessage } from './../views/chat'; +import { Player } from '../../shared/player'; + +async function handler(rawCommand: string, sender: Socket, player: Player) { + if(player.permissions.includes('admin')) { + await createMonsters(); + const message = broadcastMessage('server', 'Monsters refreshed!'); + sender.emit('chat', renderChatMessage(message)); + } +} + +export const refreshMonsters = new ChatCommand('refresh-monsters', new RegExp(/^refresh-monsters$/), handler); diff --git a/src/server/chat-commands/refresh-shops.ts b/src/server/chat-commands/refresh-shops.ts new file mode 100644 index 0000000..2f90c3b --- /dev/null +++ b/src/server/chat-commands/refresh-shops.ts @@ -0,0 +1,18 @@ +import { ChatCommand } from './base'; +import { Socket } from 'socket.io'; +import { createShopItems, createShopEquipment } from '../../../seeds/shop_items'; +import { broadcastMessage } from '../../shared/message'; +import { renderChatMessage } from './../views/chat'; +import { Player } from '../../shared/player'; + +async function handler(rawCommand: string, sender: Socket, player: Player) { + if(player.permissions.includes('admin')) { + await createShopItems(); + await createShopEquipment(); + const message = broadcastMessage('server', 'Shop items refreshed!'); + sender.emit('chat', renderChatMessage(message)); + + } +} + +export const refreshShops = new ChatCommand('refresh-shops', new RegExp(/^refresh-shops/), handler); diff --git a/src/server/chat-commands/say.ts b/src/server/chat-commands/say.ts new file mode 100644 index 0000000..1c1104e --- /dev/null +++ b/src/server/chat-commands/say.ts @@ -0,0 +1,14 @@ +import { ChatCommand } from './base'; +import { Socket } from 'socket.io'; +import { broadcastMessage, Message } from '../../shared/message'; +import { renderChatMessage } from './../views/chat'; +import { Player } from '../../shared/player'; + +async function handler(rawCommand: string, sender: Socket, player: Player) { + if(player.permissions.includes('moderator') || player.permissions.includes('admin')) { + let message: Message = broadcastMessage('server', rawCommand.split('say ')[1].trim()); + sender.emit('chat', renderChatMessage(message)); + } +} + +export const say = new ChatCommand('say', new RegExp(/^say (.*)+/), handler); diff --git a/src/server/chat-commands/set-level.ts b/src/server/chat-commands/set-level.ts new file mode 100644 index 0000000..640a194 --- /dev/null +++ b/src/server/chat-commands/set-level.ts @@ -0,0 +1,42 @@ +import { ChatCommand } from './base'; +import { Socket } from 'socket.io'; +import { broadcastMessage, Message } from '../../shared/message'; +import { renderChatMessage } from './../views/chat'; +import { updatePlayer } from '../player'; +import { maxHp, maxVigor, Player } from '../../shared/player'; + +async function handler(rawCommand: string, sender: Socket, player: Player) { + if(player.permissions.includes('admin') || player.permissions.includes('tester')) { + let message: Message; + // command in set-level username level + const pieces = rawCommand.split(' '); + if(pieces.length !== 2) { + message = broadcastMessage('server', 'format: /set-level level'); + } + else { + const level = parseInt(pieces.pop() || '0'); + if(level < 1) { + message = broadcastMessage('server', 'format: /set-level [level >= 1]'); + } + else { + message = broadcastMessage('server', `Set to level ${level}. Please reload.`); + + player.level = level; + player.strength = 4; + player.constitution = 4; + player.dexterity = 4; + player.intelligence = 4; + player.hp = maxHp(player.constitution, player.level); + player.vigor = maxVigor(player.constitution, player.level); + player.stat_points = level-1; + + await updatePlayer(player); + } + } + + sender.emit('chat', renderChatMessage(message)); + + } +} + +export const setLevel = new ChatCommand('set-level', new RegExp(/^set-level \d+$/), handler); diff --git a/src/server/dungeon.ts b/src/server/dungeon.ts new file mode 100644 index 0000000..33558a9 --- /dev/null +++ b/src/server/dungeon.ts @@ -0,0 +1,178 @@ +import { Fight } from "shared/monsters"; +import { Dungeon, DungeonRoom, DungeonPlayer, DungeonState, DungeonStateSummaryVists, DungeonStateSummaryFights } from "../shared/dungeon"; +import { db } from './lib/db'; +import { Request, Response } from 'express'; +import { ErrorAlert } from "./views/alert"; +import { addEvent } from './events'; + +export async function blockPlayerInDungeon(req: Request, res: Response, next: any) { + const state = await getActiveDungeon(req.player.id); + if(!state) { + next(); + } + else { + res.send(ErrorAlert('You are currently exploring a dungeon')); + } +} + +export async function getActiveDungeon(player_id: string): Promise { + return db.select('*').from('dungeon_players').where({ + player_id + }).first(); +} + +export async function loadDungeon(dungeon_id: string): Promise { + return db.select('*').from('dungeons').where({id: dungeon_id}).first(); +} + +export async function getDungeonState(player_id: string, dungeon_id: string) { + return db.select('*').from('dungeon_state').where({ + player_id, + dungeon_id + }); +} + +export async function addNewState(player_id: string, dungeon_id: string, event_name: string, props: Record = {}) { + return db('dungeon_state').insert({ + player_id, + dungeon_id, + event_name, + event_props: props + }); +} +// in a dungeon fight, we dont care what room the player is in, +// but we care what room they are going to +export async function completeDungeonFight(player_id: string, monster: Fight): Promise { + const activeDungeon = await getActiveDungeon(player_id); + + await addNewState(player_id, activeDungeon.dungeon_id, 'FIGHT_COMPLETE', { + monster_id: monster.ref_id, + target_room: activeDungeon.target_room_id, + source_room: activeDungeon.current_room_id + }); + + await movePlayerToRoomInDungeon(player_id, activeDungeon.dungeon_id, activeDungeon.target_room_id); + + return getActiveDungeon(player_id); +} + +export async function movePlayerToRoomInDungeon(player_id: string, dungeon_id: string, room_id: string) { + await updatePlayerDungeonState(player_id, dungeon_id, { + current_room_id: room_id, + target_room_id: room_id + }); + + await addNewState(player_id, dungeon_id, 'ROOM_VISIT', { + room_id + }); +} + +export async function getRoomVists(player_id: string, dungeon_id: string): Promise { + + const res = await db.raw(`select +count(id) as visits, +event_props->>'room_id' as room_id +from dungeon_state +group by event_props->>'room_id',player_id,dungeon_id,event_name +having player_id = ? and dungeon_id = ? and event_name = ? +`, [ + player_id, + dungeon_id, + 'ROOM_VISIT' + ]); + + let data = {}; + res.rows.forEach((row: {room_id: string, visits: string}) => { + data[row.room_id] = parseInt(row.visits); + }); + + return data; +} + +export async function getUniqueFights(player_id: string, dungeon_id: string): Promise { + // fights always happen between movement source->target. So when we record + // the state of a fight, we record the source/target room props. + // however, when we are checking if a fight occurrent in a room.. we really + // only care about the TARGET room. + const res = await db.raw(`select +count(id) as fights, +event_props->>'monster_id' as monster_id, +event_props->>'target_room' as room_id +from dungeon_state +group by event_props->>'monster_id',event_props->>'target_room', +player_id,dungeon_id,event_name +having player_id = ? and dungeon_id = ? and event_name = ? +`, [ + player_id, + dungeon_id, + 'FIGHT_COMPLETE' + ]); + + let data = {}; + res.rows.forEach((row: {fights: string, monster_id: string, room_id: string}) => { + if(!data[row.room_id]) { + data[row.room_id] = {}; + } + + if(!data[row.room_id][row.monster_id]) { + data[row.room_id][row.monster_id] = row.fights; + } + }); + + return data; +} + +export async function putPlayerInDungeon(player_id: string, dungeon_id: string): Promise { + const res: {rows: DungeonPlayer[] }= await db.raw(` + insert into dungeon_players +(player_id, dungeon_id, current_room_id) +values +(?, ?, (select starting_room from dungeons where id = ?)) returning *`, [player_id, dungeon_id, dungeon_id]) + + const data = res.rows.pop(); + + await addNewState(player_id, dungeon_id, 'ROOM_VISIT', { + room_id: data.current_room_id + }); + + return data; +} + + +export async function updatePlayerDungeonState(player_id: string, dungeon_id: string, fields: any) { + const res = await db('dungeon_players').where({ + player_id, + dungeon_id + }).update(fields).returning('*'); + + return res.pop(); +} + +export async function loadRoom(room_id: string): Promise { + return db.select('*') + .from('dungeon_rooms') + .where({id: room_id}) + .first(); +} + +export async function completeDungeon(player_id: string) { + const dungeonPlayer = await getActiveDungeon(player_id); + const dungeonState = await getDungeonState(player_id, dungeonPlayer.dungeon_id); + + await db('dungeon_players').where({player_id}).delete(); + await db('dungeon_state').where({player_id, dungeon_id: dungeonPlayer.dungeon_id}).delete(); + + let startTime = Number.MAX_VALUE; + let endTime = 0; + dungeonState.forEach(s => { + startTime = Math.min(startTime, s.create_date); + endTime = Math.max(endTime, s.create_date); + }); + + addEvent('DUNGEON_COMPLETE', player_id, { + dungeon_id: dungeonPlayer.dungeon_id, + start: startTime, + end: endTime, + duration: endTime - startTime + }); +} diff --git a/src/server/events.ts b/src/server/events.ts new file mode 100644 index 0000000..df0b819 --- /dev/null +++ b/src/server/events.ts @@ -0,0 +1,78 @@ +import { db } from './lib/db'; +import { version } from '../../package.json'; +import { CreatedEvent, Event, EventName } from '../shared/event'; +import { isEqual } from 'lodash'; +import { logger } from './lib/logger'; +import { EVENT_FLUSH_INTERVAL, EVENT_SECOND_BUCKET } from '../shared/constants'; +import { clickhouse } from './lib/clickhouse'; + +const eventBuffer: CreatedEvent[] = []; +const maxToAdd = 10; + +export async function flushBuffer() { + const events = eventBuffer.splice(0, maxToAdd); + if(events.length) { + await addEvents(events); + logger.log(`Flushed ${events.length} events`); + } + setTimeout(flushBuffer, EVENT_FLUSH_INTERVAL); +} + +function bucketTime(date: Date): Date { + const d = new Date(); + d.setFullYear(date.getFullYear()); + d.setMonth(date.getMonth()); + d.setDate(date.getDate()); + d.setHours(date.getHours()); + d.setMinutes(date.getMinutes()); + d.setMilliseconds(0); + + const s = date.getSeconds(); + + // round down to closest 5 second interval + d.setSeconds(s - (s%EVENT_SECOND_BUCKET)); + return d; +} + + +export async function addEvent(event_name: EventName, player_id: string, props?: any, created?: Date) { + eventBuffer.push({ + event_name, + player_id, + app_version: version, + props: props, + created + }); +} + +export async function addEvents(events: CreatedEvent[]) { + return db('events').insert(events); +} + +export async function getEventHistory(player_id: string, event_name: EventName) { + return db.select('*').from>('events').where({ + player_id, + event_name + }); +} + +export async function getEventHistoryToday(player_id: string, event_name: EventName) { + return db.select('*').from>('events').where({ + player_id, + event_name + }).andWhere('created', '>=', db.raw('current_date::timestamp')); + +} + +export async function hasNeverHappenedBefeore(name: EventName, player_id: string, props?: any): Promise { + return hasHappendXTimes(0, name, player_id, props); +} + +export async function hasHappendXTimes(times: number, event_name: EventName, player_id: string, props?: any): Promise { + const res: Event[] = await getEventHistory(player_id, event_name); + + if(props) { + return res.filter(row => isEqual(row.props, props)).length === times; + } + return res.length === times; +} diff --git a/src/server/fight.ts b/src/server/fight.ts index 011cc5c..4515c30 100644 --- a/src/server/fight.ts +++ b/src/server/fight.ts @@ -11,6 +11,7 @@ import { getPlayerSkillsAsObject, updatePlayerSkills } from './skills'; import { SkillID, Skills } from '../shared/skills'; import { Request, Response } from 'express'; import * as Alert from './views/alert'; +import { addEvent } from './events'; export async function blockPlayerInFight(req: Request, res: Response, next: any) { const fight = await loadMonsterFromFight(req.player.id); @@ -162,6 +163,13 @@ export async function fightRound(player: Player, monster: Fight, data: {action: roundData.monster.hp = 0; roundData.winner = 'player'; + addEvent('MONSTER_KILLED', player.id, { + monster_id: roundData.monster.ref_id, + monster_name: roundData.monster.name, + level: roundData.monster.level, + fightTrigger: roundData.monster.fight_trigger + }); + const expGained = exponentialExp(monster.exp, monster.level, player.level); roundData.rewards.exp = expGained; @@ -173,6 +181,10 @@ export async function fightRound(player: Player, monster: Fight, data: {action: if(player.exp >= expToLevel(player.level + 1)) { player.exp -= expToLevel(player.level + 1) player.level++; + addEvent('LEVEL_UP', player.id, { + from_level: player.level-1, + to_level: player.level + }); roundData.rewards.levelIncrease = true; let statPointsGained = 1; diff --git a/src/server/lib/clickhouse.ts b/src/server/lib/clickhouse.ts new file mode 100644 index 0000000..831f46d --- /dev/null +++ b/src/server/lib/clickhouse.ts @@ -0,0 +1,3 @@ +import { createClient } from '@clickhouse/client'; + +export const clickhouse = createClient(); diff --git a/src/server/locations/dungeon.ts b/src/server/locations/dungeon.ts new file mode 100644 index 0000000..26f7460 --- /dev/null +++ b/src/server/locations/dungeon.ts @@ -0,0 +1,186 @@ +import { Router } from "express"; +import { authEndpoint } from '../auth'; +import { logger } from "../lib/logger"; +import { getDungeon, getService } from '../map'; +import { completeDungeon, getActiveDungeon, getRoomVists, getUniqueFights, loadDungeon, loadRoom, movePlayerToRoomInDungeon, putPlayerInDungeon, updatePlayerDungeonState } from '../dungeon'; +import { Dungeon, DungeonRewards } from "../../shared/dungeon"; +import { dungeonRewards, renderDungeon } from '../views/dungeons/room'; +import * as Alert from '../views/alert'; +import { createFight, loadMonster } from "../monster"; +import { renderFightPreRoundDungeon } from "../views/fight"; +import { has, max, each } from 'lodash'; +import { expToLevel, maxHp, maxVigor } from "../../shared/player"; +import { updatePlayer } from "../player"; +import { getEventHistoryToday } from "../events"; + +export const router = Router(); + +router.get('/city/dungeon/:dungeon_id/:location_id', authEndpoint, async (req, res) => { + let dungeon: Dungeon; + let activeDungeon = await getActiveDungeon(req.player.id); + // because of how we treat locations + dungeons, the "event_name" of a location + // is actually the uuid of the dungeon. How fancy + // in this case service.event_name === dungeon.id + const service = await getService(parseInt(req.params.location_id)); + + if(service.type !== 'DUNGEON') { + logger.log(`Attempting to enter a non-dungeon`); + res.sendStatus(400); + return; + } + + if(service.city_id !== req.player.city_id) { + logger.log(`Player is not in the same place as the dungeon: [${req.params.location_id}]`); + res.sendStatus(400); + return; + } + + if(!activeDungeon) { + // for a dungeon the "event_name" serves as a mapping between the + // airtable integer id that is used for the location and the ifid (interactive fiction id) + // that is generated by twine + activeDungeon = await putPlayerInDungeon(req.player.id, service.event_name); + } + + const room = await loadRoom(activeDungeon.current_room_id); + const visits = await getRoomVists(req.player.id, service.event_name); + + res.send(renderDungeon(service.city_name, service.name, room, visits)); +}); + +router.post('/city/dungeon/step/:target_room_id', authEndpoint, async (req, res) => { + const activeDungeon = await getActiveDungeon(req.player.id); + if(!activeDungeon) { + logger.log(`Not in a dungeon`); + res.sendStatus(400); + return; + } + + const dungeon = await loadDungeon(activeDungeon.dungeon_id); + const service = await getDungeon(dungeon.id); + + const targetRoomId = req.params.target_room_id.toLowerCase().trim(); + const currentRoom = await loadRoom(activeDungeon.current_room_id); + + const targetExit = currentRoom.exits.filter(exit => { + return exit.target_room_id === targetRoomId + }); + + if(!targetExit.length) { + logger.log(`Invalid exit: [${targetRoomId}]`); + res.sendStatus(400); + return; + } + + const nextRoom = await loadRoom(targetRoomId); + + if(!nextRoom) { + logger.error(`Dang.. no valid room`, targetRoomId, currentRoom); + res.send(Alert.ErrorAlert(`${req.params.direction} is not a valid direction`)).status(400); + return; + } + + + // if the room contiains a fight and + // its a one time fight the user hasn't finished + // OR + // its not a one time fight + // render the fight screen + if(nextRoom.settings.fight) { + const fights = await getUniqueFights(req.player.id, nextRoom.dungeon_id); + if( + ( + nextRoom.settings.fight.one_time && + ( + has(fights, [nextRoom.id, nextRoom.settings.fight.monster_id]) + ? + fights[nextRoom.id][nextRoom.settings.fight.monster_id] + : + 0 + ) === 0 + ) + || + !nextRoom.settings.fight.one_time + ){ + const monster = await loadMonster(nextRoom.settings.fight.monster_id); + const fight = await createFight(req.player.id, monster, 'dungeon-forced'); + + // ensure that we know what room the player was attempting to go + // to + await updatePlayerDungeonState(req.player.id, currentRoom.dungeon_id, { + current_room_id: currentRoom.id, + target_room_id: nextRoom.id + }); + + // ok render the fight view instead! + res.send(renderFightPreRoundDungeon(service.city_name, service.name, fight)); + return; + } + } + + await movePlayerToRoomInDungeon(req.player.id, nextRoom.dungeon_id, nextRoom.id); + const visits = await getRoomVists(req.player.id, service.event_name); + + res.send(renderDungeon(service.city_name, service.name, nextRoom, visits)); +}); + +router.post('/city/dungeon/:dungeon_id/complete', authEndpoint, async (req, res) => { + const activeDungeon = await getActiveDungeon(req.player.id); + if(!activeDungeon) { + logger.log(`Not in a dungeon`); + res.sendStatus(400); + return; + } + + const dungeon = await loadDungeon(activeDungeon.dungeon_id); + const currentRoom = await loadRoom(activeDungeon.current_room_id); + + if(!currentRoom.settings.end) { + logger.log(`Not the end of the dungeon: [${currentRoom.id}]`); + res.sendStatus(400); + return; + } + + const stats = await getUniqueFights(req.player.id, dungeon.id); + + const rewards: DungeonRewards = { + exp: max([currentRoom.settings.rewards?.base.exp, 0]), + gold: max([currentRoom.settings.rewards?.base.gold, 0]) + }; + + if(currentRoom.settings.rewards.per_kill_bonus) { + each(stats, (room) => { + each(room, (count) => { + if(currentRoom.settings.rewards.per_kill_bonus.exp) { + rewards.exp += (count * currentRoom.settings.rewards.per_kill_bonus.exp) + } + if(currentRoom.settings.rewards.per_kill_bonus.gold) { + rewards.gold += (count * currentRoom.settings.rewards.per_kill_bonus.gold) + } + }); + }); + } + + + // if this is not the first completion, lets give them diminishing returns + const completionsToday = await getEventHistoryToday(req.player.id, 'DUNGEON_COMPLETE'); + let factor = completionsToday.length <= 5 ? 1 : 0.2; + + // give the user these rewards! + req.player.gold += Math.ceil(rewards.gold * factor); + req.player.exp += Math.ceil(rewards.exp * factor); + + while(req.player.exp >= expToLevel(req.player.level + 1)) { + req.player.exp -= expToLevel(req.player.level + 1); + req.player.level++; + req.player.stat_points += req.player.profession === 'Wanderer' ? 1 : 2; + req.player.hp = maxHp(req.player.constitution, req.player.level); + req.player.vigor = maxVigor(req.player.constitution, req.player.level); + } + + // delete the tracking for this dungeon-run + await completeDungeon(req.player.id); + await updatePlayer(req.player); + + res.send(dungeonRewards(dungeon, rewards, completionsToday.length)); +}); diff --git a/src/server/map.ts b/src/server/map.ts index df70a38..45b0084 100644 --- a/src/server/map.ts +++ b/src/server/map.ts @@ -4,10 +4,11 @@ import type { Travel, TravelWithNames } from '../shared/travel'; import { db } from './lib/db'; import { random } from 'lodash'; -export async function getAllServices(city_id: number): Promise { +export async function getAllServices(city_id: number, min_level: number): Promise { return db.select('*') .from('locations') .where({city_id}) + .andWhere('min_level', '<=', min_level) .orderBy('type') .orderBy('display_order'); } @@ -19,6 +20,13 @@ export async function getService(location_id: number): Promise }).first(); } +export async function getDungeon(dungeon_id: string): Promise { + return db.select(['locations.*', 'cities.name as city_name']). + from('locations').join('cities', 'locations.city_id', '=', 'cities.id').where({ + 'locations.event_name': dungeon_id + }).first(); +} + export async function getAllPaths(city_id: number): Promise { const res = await db.raw(` select @@ -82,7 +90,6 @@ export async function clearTravelPlan(player_id: string): Promise { export async function completeTravel(player_id: string): Promise { const rows = await db('travel').where({player_id}).delete().returning('*'); if(rows.length !== 1) { - console.log(rows); throw new Error('Unexpected response when moving'); } diff --git a/src/server/player.ts b/src/server/player.ts index a9d077c..b957969 100644 --- a/src/server/player.ts +++ b/src/server/player.ts @@ -31,6 +31,32 @@ export async function loadPlayer(authToken: string): Promise { return res; } +export async function findPlayerByUsername(username: string): Promise { + const res = await db.first() + .select( + 'players.*', + 'profession_levels.level', + 'profession_levels.exp', + db.raw(`coalesce(pp.permissions, '[]'::json) as permissions`) + ) + .from('players') + .join('profession_levels', function() { + this.on(function() { + this.on('profession_levels.player_id', '=', 'players.id') + this.andOn('profession_levels.profession', '=', 'players.profession') + }) + }) + .leftJoin( + db.raw(`(select json_agg(pp.permission) as permissions, pp.player_id from player_permissions pp group by pp.player_id) pp`), + 'pp.player_id','=', 'players.id' + ) + .where({ + 'players.username': username + }); + + return res; +} + export async function createPlayer(): Promise { const raw: Partial = { username: `Player${Date.now().toString().substr(-7)}`, diff --git a/src/server/views/components/explore-pane.ts b/src/server/views/components/explore-pane.ts new file mode 100644 index 0000000..581677b --- /dev/null +++ b/src/server/views/components/explore-pane.ts @@ -0,0 +1,5 @@ +export function ExplorePane(townId: number, contents: string): string { + return `
+ ${contents} +
`; +} diff --git a/src/server/views/dungeons/room.ts b/src/server/views/dungeons/room.ts new file mode 100644 index 0000000..a4e3552 --- /dev/null +++ b/src/server/views/dungeons/room.ts @@ -0,0 +1,71 @@ +import { DUNGEON_TRAVEL_BLOCK } from '../../../shared/constants'; +import { Dungeon, DungeonPlayer, DungeonRewards, DungeonRoom, DungeonState, DungeonStateSummaryVists } from '../../../shared/dungeon'; +import { Button, ButtonWithBlock } from '../components/button'; +import { Details, Title } from '../components/city'; + +function renderMovementButtons(room: DungeonRoom): string { + let html: string[] = []; + const now = Date.now(); + + room.exits.forEach(exit => { + html.push(ButtonWithBlock({ + id: `target-${exit.target_room_id}`, + 'hx-post': `/city/dungeon/step/${exit.target_room_id}`, + 'hx-target': '#explore' + }, exit.name, now + DUNGEON_TRAVEL_BLOCK)); + }); + + if(room.settings?.end) { + html.push(Button({ + id: `target-exit`, + 'hx-post': `/city/dungeon/${room.dungeon_id}/complete`, + 'hx-target': '#modal-wrapper' + }, 'Complete Dungeon')); + } + + return html.join("\n"); +} + +export function renderDungeonRoom(room: DungeonRoom, state: DungeonStateSummaryVists): string { + // first visit for this room? + let desc = room.description; + room.settings?.visit?.forEach(visit => { + // This ssets the stage for repeat events. + // eventually the description might change if you visit + // a spot MROE than 5 or 6 times + if(state[room.id]) { + if(visit?.visit_number === state[room.id]) { + desc = visit.description; + } + } + }); + + let html = `
${desc}
${renderMovementButtons(room)}
`; + + return html; + +} + +export function renderDungeon(city: string, dungeon_name: string, room: DungeonRoom, state: DungeonStateSummaryVists): string { + return` + ${Title(city)} + ${Details(dungeon_name, renderDungeonRoom(room, state))} +`; +} + +export function dungeonRewards(dungeon: Dungeon, rewards: DungeonRewards, completions: number): string { + return ` + +
+

Congratulations on completing the ${dungeon.name} Dungeon!

+

${completions <= 5 ? `${completions}/5 Runs` : `You've exhausted your runs!`}

+ Rewards:
+ Exp: ${rewards.exp.toLocaleString()}
+ Gold: ${rewards.gold.toLocaleString()}
+
+
+ +
+
+ `; +} diff --git a/src/server/views/fight.ts b/src/server/views/fight.ts index c66cdbd..46d962b 100644 --- a/src/server/views/fight.ts +++ b/src/server/views/fight.ts @@ -1,7 +1,9 @@ +import { Dungeon } from "shared/dungeon"; import { FightRound } from "shared/fight"; import { LocationWithCity } from "shared/map"; import { Fight, MonsterForFight } from "../../shared/monsters"; import { Button, ButtonWithBlock } from "./components/button"; +import { Details, Title } from "./components/city"; export function renderRoundDetails(roundData: FightRound): string { let html: string[] = roundData.roundDetails.map(d => `
${d}
`); @@ -91,14 +93,21 @@ export function renderFight(monster: Fight, results: string = '', displayFightAc `: ''} - +
${results}
-`; +`; return html; } +export function renderFightPreRoundDungeon(city: string, dungeon_name: string, monster: Fight): string { + return` + ${Title(city)} + ${Details(dungeon_name, renderFight(monster, '', true))} +`; +} + export function renderFightPreRound(monster: Fight, displayFightActions: boolean = true, location: LocationWithCity, closestTown: number) { let html = `
diff --git a/src/server/views/map.ts b/src/server/views/map.ts index e432ebd..0b6f2c2 100644 --- a/src/server/views/map.ts +++ b/src/server/views/map.ts @@ -9,7 +9,8 @@ export async function renderMap(data: { city: City, locations: Location[], paths const servicesParsed: Record = { 'SERVICES': [], 'STORES': [], - 'EXPLORE': [] + 'EXPLORE': [], + 'DUNGEON': [] }; data.locations.forEach(l => { @@ -28,7 +29,10 @@ export async function renderMap(data: { city: City, locations: Location[], paths html += `

Stores

${servicesParsed.STORES.join("
")}
` } if(servicesParsed.EXPLORE.length) { - html += `

Explore

${servicesParsed.EXPLORE.join("
")}
` + html += ` +

Explore

${servicesParsed.EXPLORE.join("
")} + ${servicesParsed.DUNGEON.length ? `
${servicesParsed.DUNGEON.join("
")}` : ''} +
`; } html += `
diff --git a/src/shared/constants.ts b/src/shared/constants.ts index 4cda940..7804b56 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -3,3 +3,8 @@ export const STEP_DELAY = 2000; export const ALERT_DISPLAY_LENGTH = 3000; // this is displayed as a percentage out of 100 export const CHANCE_TO_FIGHT_SPECIAL = 10; + +export const DUNGEON_TRAVEL_BLOCK = 3000; + +export const EVENT_FLUSH_INTERVAL = 10000; +export const EVENT_SECOND_BUCKET = 3; diff --git a/src/shared/dungeon.ts b/src/shared/dungeon.ts new file mode 100644 index 0000000..e345523 --- /dev/null +++ b/src/shared/dungeon.ts @@ -0,0 +1,73 @@ +export type Dungeon = { + id: string; + name: string; + starting_room: string; +} + +export type RoomExit = { + name: string; + target_room_id: string +} + +export type RoomSettings = { + visit?: { + visit_number: number; + description?: string; + }[], + fight?: { + monster_id: number; + one_time: boolean; + }, + end?: boolean; + rewards?: { + base: { + exp?: number, + gold?: number + }, + per_kill_bonus?: { + exp?: number, + gold?: number + } + } +} + +export type DungeonRoom = { + id: string; + dungeon_id: string; + description: string; + exits: RoomExit[]; + settings: RoomSettings; +} + +export type DungeonThing = { + room_id: string; + id: number; + name: string; + type: string; + properties: Record; +} + +export type DungeonState = { + player_id: string; + dungeon_id: string; + event_name: 'ROOM_VISIT' | 'FIGHT_COMPLETE'; + event_props: any; + create_date: number; +} + +export type DungeonPlayer = { + player_id: string; + dungeon_id: string; + current_room_id: string; + target_room_id: string; +} + +// +export type DungeonStateSummaryVists = Record; +// > +export type DungeonStateSummaryFights = Record>; + +export type DungeonRewards = { + exp: number; + gold: number; +} diff --git a/src/shared/event.ts b/src/shared/event.ts new file mode 100644 index 0000000..bb2bec2 --- /dev/null +++ b/src/shared/event.ts @@ -0,0 +1,23 @@ +type UUID = string; + +export type EventName = 'DUNGEON_COMPLETE' +| 'MONSTER_KILLED' +| 'PLAYER_KILLED' +| 'LEVEL_UP' +| 'LOGIN' +; + +export type Event = { + id: UUID; + event_name: EventName; + player_id: UUID; + app_version: string; + value: number; + props: T + created: Date; +} + +export type CreatedEvent = Omit, 'id'|'created'|'value'> & { + created?: Date; + value?: number; +} diff --git a/src/shared/map.ts b/src/shared/map.ts index c05ae8f..b4267db 100644 --- a/src/shared/map.ts +++ b/src/shared/map.ts @@ -5,7 +5,7 @@ export type City = { name: string; } -export type LocationType = 'SERVICES' | 'STORES' | 'EXPLORE'; +export type LocationType = 'SERVICES' | 'STORES' | 'EXPLORE' | 'DUNGEON'; export type Location = { id: number; diff --git a/src/shared/monsters.ts b/src/shared/monsters.ts index c7f8700..854eee5 100644 --- a/src/shared/monsters.ts +++ b/src/shared/monsters.ts @@ -25,7 +25,7 @@ export type MonsterForList = { level: number; } -export type FightTrigger = 'explore' | 'travel'; +export type FightTrigger = 'explore' | 'travel' | 'dungeon-forced'; export type Fight = Omit & { id: string; diff --git a/src/shared/player.ts b/src/shared/player.ts index 93d75f3..339396d 100644 --- a/src/shared/player.ts +++ b/src/shared/player.ts @@ -3,7 +3,13 @@ import { Stat } from './stats'; import { SkillDefinition, Skill } from './skills'; import { EquippedItemDetails } from './equipped'; -export type Permission = 'admin' | 'moderator'; +export function PermissionGuard(request: any): boolean { + const perms: Permission[] = ['admin', 'moderator', 'tester', 'archaeologist']; + + return perms.includes(request); +} + +export type Permission = 'admin' | 'moderator' | 'tester' | 'archaeologist'; export type Player = { id: string,