aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.ci/ci.cjs5147
-rw-r--r--.ci/ci.json3
-rw-r--r--.ci/ci.ts76
-rw-r--r--.ci/package-lock.json544
-rw-r--r--.ci/package.json17
-rw-r--r--.ci/tsconfig.json28
-rw-r--r--.dockerignore8
-rw-r--r--.eslintrc.cjs12
-rw-r--r--.gitignore5
-rw-r--r--.prettierrc7
-rw-r--r--Dockerfile17
-rw-r--r--README.md345
-rwxr-xr-xexamples.sh162
-rw-r--r--package-lock.json1861
-rw-r--r--package.json36
-rw-r--r--src/activity/index.ts438
-rw-r--r--src/index.ts64
-rw-r--r--src/integrations/hcaptcha.ts32
-rw-r--r--src/integrations/ntfy.ts40
-rw-r--r--src/server/index.ts84
-rw-r--r--src/storage/index.ts114
-rw-r--r--src/token/index.ts76
-rw-r--r--src/types/index.ts78
-rw-r--r--tsconfig.json24
24 files changed, 9218 insertions, 0 deletions
diff --git a/.ci/ci.cjs b/.ci/ci.cjs
new file mode 100755
index 0000000..1a44166
--- /dev/null
+++ b/.ci/ci.cjs
@@ -0,0 +1,5147 @@
+#!/usr/bin/env node
+"use strict";
+var __create = Object.create;
+var __defProp = Object.defineProperty;
+var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
+var __getOwnPropNames = Object.getOwnPropertyNames;
+var __getProtoOf = Object.getPrototypeOf;
+var __hasOwnProp = Object.prototype.hasOwnProperty;
+var __commonJS = (cb, mod) => function __require() {
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
+};
+var __copyProps = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames(from))
+ if (!__hasOwnProp.call(to, key) && key !== except)
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
+ }
+ return to;
+};
+var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
+ // If the importer is in node compatibility mode or this is not an ESM
+ // file that has been converted to a CommonJS file using a Babel-
+ // compatible transform (i.e. "__esModule" has not been set), then set
+ // "default" to the CommonJS "module.exports" for node compatibility.
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
+ mod
+));
+
+// node_modules/@emprespresso/pengueno/dist/leftpadesque/prepend.js
+var require_prepend = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/leftpadesque/prepend.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.prependWith = void 0;
+ var prependWith = (arr, prep) => Array(arr.length * 2).fill(0).map((_, i) => i % 2 === 0).map((isPrep, i) => isPrep ? prep : arr[Math.floor(i / 2)]);
+ exports2.prependWith = prependWith;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/leftpadesque/debug.js
+var require_debug = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/leftpadesque/debug.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.isDebug = exports2.isProd = void 0;
+ var _hasEnv = true;
+ var _env = _hasEnv && (process.env.ENVIRONMENT ?? "").toLowerCase().includes("prod") ? "production" : "development";
+ var isProd = () => _env === "production";
+ exports2.isProd = isProd;
+ var _debug = !(0, exports2.isProd)() || _hasEnv && ["y", "t"].some((process.env.DEBUG ?? "").toLowerCase().startsWith);
+ var isDebug = () => _debug;
+ exports2.isDebug = isDebug;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/leftpadesque/memoize.js
+var require_memoize = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/leftpadesque/memoize.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.memoize = void 0;
+ var memoize = (fn) => {
+ const cache = /* @__PURE__ */ new Map();
+ return (...args) => {
+ const key = JSON.stringify(args);
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ const res = fn(...args);
+ cache.set(key, res);
+ return res;
+ };
+ };
+ exports2.memoize = memoize;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/leftpadesque/index.js
+var require_leftpadesque = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/leftpadesque/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_prepend(), exports2);
+ __exportStar(require_debug(), exports2);
+ __exportStar(require_memoize(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/misc.js
+var require_misc = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/misc.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/object.js
+var require_object = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/object.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.isObject = void 0;
+ var isObject3 = (o) => typeof o === "object" && !Array.isArray(o) && !!o;
+ exports2.isObject = isObject3;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/tagged.js
+var require_tagged = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/tagged.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.isTagged = void 0;
+ var index_1 = require_types();
+ var isTagged = (o, tag) => !!((0, index_1.isObject)(o) && "_tag" in o && o._tag === tag);
+ exports2.isTagged = isTagged;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/fn/callable.js
+var require_callable = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/fn/callable.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/fn/optional.js
+var require_optional = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/fn/optional.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.Optional = exports2.IOptionalEmptyError = exports2.isOptional = exports2.IOptionalTag = void 0;
+ var pengueno_1 = require_dist2();
+ exports2.IOptionalTag = "IOptional";
+ var isOptional = (o) => (0, pengueno_1.isTagged)(o, exports2.IOptionalTag);
+ exports2.isOptional = isOptional;
+ var IOptionalEmptyError = class extends Error {
+ };
+ exports2.IOptionalEmptyError = IOptionalEmptyError;
+ var OSomeTag = "O.Some";
+ var ONoneTag = "O.None";
+ var isNone = (o) => (0, pengueno_1.isTagged)(o, ONoneTag);
+ var isSome = (o) => (0, pengueno_1.isTagged)(o, OSomeTag);
+ var _Tagged = class {
+ _tag;
+ constructor(_tag = exports2.IOptionalTag) {
+ this._tag = _tag;
+ }
+ };
+ var Optional = class _Optional extends _Tagged {
+ self;
+ constructor(self) {
+ super();
+ this.self = self;
+ }
+ move(t) {
+ return this.map(() => t);
+ }
+ orSome(supplier) {
+ if (isNone(this.self))
+ return _Optional.from(supplier());
+ return this;
+ }
+ get() {
+ if (isNone(this.self))
+ throw new IOptionalEmptyError("called get() on None optional");
+ return this.self.value;
+ }
+ filter(mapper) {
+ if (isNone(this.self) || !mapper(this.self.value))
+ return _Optional.none();
+ return _Optional.some(this.self.value);
+ }
+ map(mapper) {
+ if (isNone(this.self))
+ return _Optional.none();
+ return _Optional.from(mapper(this.self.value));
+ }
+ flatMap(mapper) {
+ if (isNone(this.self))
+ return _Optional.none();
+ return _Optional.from(mapper(this.self.value)).orSome(() => _Optional.none()).get();
+ }
+ present() {
+ return isSome(this.self);
+ }
+ *[Symbol.iterator]() {
+ if (isSome(this.self))
+ yield this.self.value;
+ }
+ static some(value) {
+ return new _Optional({ value, _tag: OSomeTag });
+ }
+ static _none = new _Optional({ _tag: ONoneTag });
+ static none() {
+ return this._none;
+ }
+ static from(value) {
+ if (value === null || value === void 0)
+ return _Optional.none();
+ return _Optional.some(value);
+ }
+ };
+ exports2.Optional = Optional;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/fn/either.js
+var require_either = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/fn/either.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.Either = exports2.isRight = exports2.isLeft = exports2.isEither = exports2.IEitherTag = void 0;
+ var pengueno_1 = require_dist2();
+ exports2.IEitherTag = "IEither";
+ var isEither = (o) => (0, pengueno_1.isTagged)(o, exports2.IEitherTag);
+ exports2.isEither = isEither;
+ var ELeftTag = "E.Left";
+ var isLeft = (o) => (0, pengueno_1.isTagged)(o, ELeftTag);
+ exports2.isLeft = isLeft;
+ var ERightTag = "E.Right";
+ var isRight = (o) => (0, pengueno_1.isTagged)(o, ERightTag);
+ exports2.isRight = isRight;
+ var _Tagged = class {
+ _tag;
+ constructor(_tag = exports2.IEitherTag) {
+ this._tag = _tag;
+ }
+ };
+ var Either2 = class _Either extends _Tagged {
+ self;
+ constructor(self) {
+ super();
+ this.self = self;
+ }
+ moveRight(t) {
+ return this.mapRight(() => t);
+ }
+ mapBoth(errBranch, okBranch) {
+ if ((0, exports2.isLeft)(this.self))
+ return _Either.left(errBranch(this.self.err));
+ return _Either.right(okBranch(this.self.ok));
+ }
+ mapRight(mapper) {
+ if ((0, exports2.isRight)(this.self))
+ return _Either.right(mapper(this.self.ok));
+ return _Either.left(this.self.err);
+ }
+ mapLeft(mapper) {
+ if ((0, exports2.isLeft)(this.self))
+ return _Either.left(mapper(this.self.err));
+ return _Either.right(this.self.ok);
+ }
+ flatMap(mapper) {
+ if ((0, exports2.isRight)(this.self))
+ return mapper(this.self.ok);
+ return _Either.left(this.self.err);
+ }
+ filter(mapper) {
+ if ((0, exports2.isLeft)(this.self))
+ return _Either.left(this.self.err);
+ return _Either.fromFailable(() => this.right().filter(mapper).get());
+ }
+ async flatMapAsync(mapper) {
+ if ((0, exports2.isLeft)(this.self))
+ return Promise.resolve(_Either.left(this.self.err));
+ return await mapper(this.self.ok).catch((err) => _Either.left(err));
+ }
+ fold(leftFolder, rightFolder) {
+ if ((0, exports2.isLeft)(this.self))
+ return leftFolder(this.self.err);
+ return rightFolder(this.self.ok);
+ }
+ left() {
+ if ((0, exports2.isLeft)(this.self))
+ return pengueno_1.Optional.from(this.self.err);
+ return pengueno_1.Optional.none();
+ }
+ right() {
+ if ((0, exports2.isRight)(this.self))
+ return pengueno_1.Optional.from(this.self.ok);
+ return pengueno_1.Optional.none();
+ }
+ joinRight(other, mapper) {
+ return this.flatMap((t) => other.mapRight((o) => mapper(o, t)));
+ }
+ joinRightAsync(other, mapper) {
+ return this.flatMapAsync(async (t) => {
+ const o = typeof other === "function" ? other() : other;
+ return await o.then((other2) => other2.mapRight((o2) => mapper(o2, t)));
+ });
+ }
+ swap() {
+ if ((0, exports2.isRight)(this.self))
+ return _Either.left(this.self.ok);
+ return _Either.right(this.self.err);
+ }
+ static left(e) {
+ return new _Either({ err: e, _tag: ELeftTag });
+ }
+ static right(t) {
+ return new _Either({ ok: t, _tag: ERightTag });
+ }
+ static fromFailable(s) {
+ try {
+ return _Either.right(s());
+ } catch (e) {
+ return _Either.left(e);
+ }
+ }
+ static async fromFailableAsync(s) {
+ return await (typeof s === "function" ? s() : s).then((t) => _Either.right(t)).catch((e) => _Either.left(e));
+ }
+ static async retrying(s, attempts = 3, interval = (attempt) => _Either.attemptWait(attempt)) {
+ let result = _Either.right(new Error("No attempts made"));
+ for (let attempt = 0; attempt < attempts && result.right().present(); attempt++) {
+ await interval(attempt);
+ const currentAttempt = await s().then((s2) => s2.swap());
+ result = await result.joinRightAsync(() => Promise.resolve(currentAttempt), (res, _prevError) => res);
+ }
+ return result.swap();
+ }
+ static attemptWait(attempt, backoffFactor = 500, jitter = 300, exponent = 1.3) {
+ if (attempt === 0) {
+ return Promise.resolve();
+ }
+ const wait = Math.pow(exponent, attempt) * backoffFactor + jitter * Math.random() * Math.pow(exponent, attempt);
+ return new Promise((res) => setTimeout(res, wait));
+ }
+ };
+ exports2.Either = Either2;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/fn/index.js
+var require_fn = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/fn/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_callable(), exports2);
+ __exportStar(require_optional(), exports2);
+ __exportStar(require_either(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/collections/cons.js
+var require_cons = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/collections/cons.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.ListZipper = exports2.Cons = void 0;
+ var pengueno_1 = require_dist2();
+ var Cons = class _Cons {
+ value;
+ next;
+ constructor(value, next = pengueno_1.Optional.none()) {
+ this.value = value;
+ this.next = next;
+ }
+ before(head) {
+ return new _Cons(this.value, head);
+ }
+ replace(_value) {
+ return new _Cons(_value, this.next);
+ }
+ *[Symbol.iterator]() {
+ for (let cur = pengueno_1.Optional.some(this); cur.present(); cur = cur.flatMap((cur2) => cur2.next)) {
+ yield cur.get().value;
+ }
+ }
+ static addOnto(items, tail) {
+ return Array.from(items).reverse().reduce((cons, value) => pengueno_1.Optional.from(new _Cons(value, cons)), tail);
+ }
+ static from(items) {
+ return _Cons.addOnto(items, pengueno_1.Optional.none());
+ }
+ };
+ exports2.Cons = Cons;
+ var ListZipper = class _ListZipper {
+ reversedPathToHead;
+ currentHead;
+ constructor(reversedPathToHead, currentHead) {
+ this.reversedPathToHead = reversedPathToHead;
+ this.currentHead = currentHead;
+ }
+ read() {
+ return this.currentHead.map(({ value }) => value);
+ }
+ next() {
+ return this.currentHead.map((head) => new _ListZipper(pengueno_1.Optional.some(head.before(this.reversedPathToHead)), head.next));
+ }
+ previous() {
+ return this.reversedPathToHead.map((lastVisited) => new _ListZipper(lastVisited.next, pengueno_1.Optional.some(lastVisited.before(this.currentHead))));
+ }
+ prependChunk(values) {
+ return new _ListZipper(Cons.addOnto(Array.from(values).reverse(), this.reversedPathToHead), this.currentHead);
+ }
+ prepend(value) {
+ return this.prependChunk([value]);
+ }
+ remove() {
+ const newHead = this.currentHead.flatMap((right) => right.next);
+ return new _ListZipper(this.reversedPathToHead, newHead);
+ }
+ replace(value) {
+ const newHead = this.currentHead.map((right) => right.replace(value));
+ return new _ListZipper(this.reversedPathToHead, newHead);
+ }
+ *[Symbol.iterator]() {
+ let head = this;
+ for (let prev = head.previous(); prev.present(); prev = prev.flatMap((p) => p.previous())) {
+ head = prev.get();
+ }
+ if (head.currentHead.present())
+ yield* head.currentHead.get();
+ }
+ collection() {
+ return Array.from(this);
+ }
+ static from(iterable) {
+ return new _ListZipper(pengueno_1.Optional.none(), Cons.from(iterable));
+ }
+ };
+ exports2.ListZipper = ListZipper;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/collections/jsonds.js
+var require_jsonds = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/collections/jsonds.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.JSONHashMap = exports2.JSONSet = void 0;
+ var JSONSet = class {
+ items;
+ constructor(items = /* @__PURE__ */ new Set()) {
+ this.items = items;
+ }
+ add(item) {
+ const itemJson = JSON.stringify(item, Object.keys(item).sort());
+ this.items.add(itemJson);
+ }
+ has(item) {
+ const itemJson = JSON.stringify(item, Object.keys(item).sort());
+ return this.items.has(itemJson);
+ }
+ delete(item) {
+ const itemJson = JSON.stringify(item, Object.keys(item).sort());
+ return this.items.delete(itemJson);
+ }
+ clear() {
+ this.items.clear();
+ }
+ size() {
+ return this.items.size;
+ }
+ };
+ exports2.JSONSet = JSONSet;
+ var JSONHashMap = class {
+ map;
+ constructor(map = /* @__PURE__ */ new Map()) {
+ this.map = map;
+ }
+ set(key, value) {
+ const keyJson = JSON.stringify(key, Object.keys(key).sort());
+ this.map.set(keyJson, value);
+ }
+ get(key) {
+ const keyJson = JSON.stringify(key, Object.keys(key).sort());
+ return this.map.get(keyJson);
+ }
+ has(key) {
+ const keyJson = JSON.stringify(key, Object.keys(key).sort());
+ return this.map.has(keyJson);
+ }
+ keys() {
+ return Array.from(this.map.keys()).map((x) => JSON.parse(x));
+ }
+ delete(key) {
+ const keyJson = JSON.stringify(key, Object.keys(key).sort());
+ return this.map.delete(keyJson);
+ }
+ clear() {
+ this.map.clear();
+ }
+ size() {
+ return this.map.size;
+ }
+ };
+ exports2.JSONHashMap = JSONHashMap;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/collections/index.js
+var require_collections = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/collections/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_cons(), exports2);
+ __exportStar(require_jsonds(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/types/index.js
+var require_types = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/types/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_misc(), exports2);
+ __exportStar(require_object(), exports2);
+ __exportStar(require_tagged(), exports2);
+ __exportStar(require_fn(), exports2);
+ __exportStar(require_collections(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/itrace.js
+var require_itrace = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/itrace.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.TraceableImpl = void 0;
+ var TraceableImpl = class _TraceableImpl {
+ item;
+ trace;
+ constructor(item, trace) {
+ this.item = item;
+ this.trace = trace;
+ }
+ map(mapper) {
+ const result = mapper(this);
+ return new _TraceableImpl(result, this.trace);
+ }
+ coExtend(mapper) {
+ const results = mapper(this);
+ return Array.from(results).map((result) => this.move(result));
+ }
+ flatMap(mapper) {
+ return mapper(this);
+ }
+ flatMapAsync(mapper) {
+ return new _TraceableImpl(mapper(this).then((t) => t.get()), this.trace);
+ }
+ traceScope(mapper) {
+ return new _TraceableImpl(this.get(), this.trace.traceScope(mapper(this)));
+ }
+ peek(peek) {
+ peek(this);
+ return this;
+ }
+ move(t) {
+ return this.map(() => t);
+ }
+ bimap(mapper) {
+ const { item, trace: _trace } = mapper(this);
+ return this.move(item).traceScope(() => _trace);
+ }
+ get() {
+ return this.item;
+ }
+ };
+ exports2.TraceableImpl = TraceableImpl;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/metric/emittable.js
+var require_emittable = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/metric/emittable.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.EmittableMetric = void 0;
+ var index_1 = require_metric2();
+ var EmittableMetric = class {
+ name;
+ unit;
+ constructor(name, unit) {
+ this.name = name;
+ this.unit = unit;
+ }
+ withValue(value) {
+ return {
+ name: this.name,
+ unit: this.unit,
+ emissionTimestamp: Date.now(),
+ value,
+ _tag: index_1.MetricValueTag
+ };
+ }
+ };
+ exports2.EmittableMetric = EmittableMetric;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/metric/metric.js
+var require_metric = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/metric/metric.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.ResultMetric = exports2.Metric = void 0;
+ var index_1 = require_metric2();
+ var _Tagged = class {
+ _tag;
+ constructor(_tag = index_1.IMetricTag) {
+ this._tag = _tag;
+ }
+ };
+ var Metric = class _Metric extends _Tagged {
+ name;
+ parent;
+ count;
+ time;
+ static DELIM = ".";
+ constructor(name, parent = void 0, count = new index_1.EmittableMetric(_Metric.join(name, "count"), index_1.Unit.COUNT), time = new index_1.EmittableMetric(_Metric.join(name, "time"), index_1.Unit.MILLISECONDS)) {
+ super();
+ this.name = name;
+ this.parent = parent;
+ this.count = count;
+ this.time = time;
+ }
+ child(_name) {
+ const childName = _Metric.join(this.name, _name);
+ return new _Metric(childName, this);
+ }
+ asResult() {
+ return ResultMetric.from(this);
+ }
+ static join(...name) {
+ return name.join(_Metric.DELIM);
+ }
+ static fromName(name) {
+ return new _Metric(name);
+ }
+ };
+ exports2.Metric = Metric;
+ var ResultMetric = class _ResultMetric extends Metric {
+ name;
+ parent;
+ failure;
+ success;
+ warn;
+ constructor(name, parent = void 0, failure, success, warn) {
+ super(name, parent);
+ this.name = name;
+ this.parent = parent;
+ this.failure = failure;
+ this.success = success;
+ this.warn = warn;
+ }
+ static from(metric) {
+ const failure = metric.child("failure");
+ const success = metric.child("success");
+ const warn = metric.child("warn");
+ return new _ResultMetric(metric.name, metric.parent, failure, success, warn);
+ }
+ };
+ exports2.ResultMetric = ResultMetric;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/metric/trace.js
+var require_trace = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/metric/trace.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.MetricsTrace = exports2.isMetricsTraceSupplier = void 0;
+ var pengueno_1 = require_dist2();
+ var isMetricsTraceSupplier = (t) => (0, pengueno_1.isMetricValue)(t) || (0, pengueno_1.isIMetric)(t) || Array.isArray(t) && t.every((_m) => (0, pengueno_1.isMetricValue)(_m) || (0, pengueno_1.isIMetric)(_m));
+ exports2.isMetricsTraceSupplier = isMetricsTraceSupplier;
+ var MetricsTrace = class _MetricsTrace {
+ metricConsumer;
+ activeTraces;
+ completedTraces;
+ constructor(metricConsumer, activeTraces = /* @__PURE__ */ new Map(), completedTraces = /* @__PURE__ */ new Set()) {
+ this.metricConsumer = metricConsumer;
+ this.activeTraces = activeTraces;
+ this.completedTraces = completedTraces;
+ }
+ traceScope(trace) {
+ const now = Date.now();
+ const metricsToTrace = (Array.isArray(trace) ? trace : [trace]).filter(pengueno_1.isIMetric);
+ const initialTraces = new Map(metricsToTrace.map((metric) => [metric.name, now]));
+ return new _MetricsTrace(this.metricConsumer, initialTraces, this.completedTraces);
+ }
+ trace(metrics) {
+ if (!metrics || typeof metrics === "string") {
+ return this;
+ }
+ const now = Date.now();
+ const allMetrics = Array.isArray(metrics) ? metrics : [metrics];
+ const valuesToEmit = allMetrics.filter(pengueno_1.isMetricValue);
+ const traceableMetrics = allMetrics.filter(pengueno_1.isIMetric);
+ const metricsToStart = traceableMetrics.filter((m) => !this.activeTraces.has(m.name));
+ const metricsToEnd = traceableMetrics.filter((m) => this.activeTraces.has(m.name) && !this.completedTraces.has(m.name));
+ const endedMetricValues = metricsToEnd.flatMap((metric) => [
+ metric.count.withValue(1),
+ metric.time.withValue(now - this.activeTraces.get(metric.name))
+ ]);
+ const parentBasedMetrics = metricsToStart.filter((metric) => {
+ const parent = metric.parent;
+ return parent && this.activeTraces.has(parent.name);
+ });
+ const parentBasedValues = parentBasedMetrics.flatMap((metric) => {
+ const parentStart = this.activeTraces.get(metric.parent.name);
+ return [metric.count.withValue(1), metric.time.withValue(now - parentStart)];
+ });
+ const allMetricsToEmit = [...valuesToEmit, ...endedMetricValues, ...parentBasedValues];
+ if (allMetricsToEmit.length > 0) {
+ this.metricConsumer(allMetricsToEmit);
+ }
+ const nextActiveTraces = new Map([
+ ...this.activeTraces,
+ ...metricsToStart.map((m) => [m.name, now])
+ ]);
+ const nextCompletedTraces = /* @__PURE__ */ new Set([
+ ...this.completedTraces,
+ ...metricsToEnd.map((m) => m.name),
+ ...parentBasedMetrics.map((m) => m.name)
+ ]);
+ return new _MetricsTrace(this.metricConsumer, nextActiveTraces, nextCompletedTraces);
+ }
+ };
+ exports2.MetricsTrace = MetricsTrace;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/metric/index.js
+var require_metric2 = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/metric/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.isIMetric = exports2.IMetricTag = exports2.isMetricValue = exports2.MetricValueTag = exports2.Unit = void 0;
+ var pengueno_1 = require_dist2();
+ var Unit;
+ (function(Unit2) {
+ Unit2["COUNT"] = "COUNT";
+ Unit2["MILLISECONDS"] = "MILLISECONDS";
+ })(Unit || (exports2.Unit = Unit = {}));
+ exports2.MetricValueTag = "MetricValue";
+ var isMetricValue = (t) => (0, pengueno_1.isTagged)(t, exports2.MetricValueTag);
+ exports2.isMetricValue = isMetricValue;
+ exports2.IMetricTag = "IMetric";
+ var isIMetric = (t) => (0, pengueno_1.isTagged)(t, exports2.IMetricTag);
+ exports2.isIMetric = isIMetric;
+ __exportStar(require_emittable(), exports2);
+ __exportStar(require_metric(), exports2);
+ __exportStar(require_trace(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/log/ansi.js
+var require_ansi = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/log/ansi.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.ANSI = void 0;
+ exports2.ANSI = {
+ RESET: "\x1B[0m",
+ BOLD: "\x1B[1m",
+ DIM: "\x1B[2m",
+ RED: "\x1B[31m",
+ GREEN: "\x1B[32m",
+ YELLOW: "\x1B[33m",
+ BLUE: "\x1B[34m",
+ MAGENTA: "\x1B[35m",
+ CYAN: "\x1B[36m",
+ WHITE: "\x1B[37m",
+ BRIGHT_RED: "\x1B[91m",
+ BRIGHT_YELLOW: "\x1B[93m",
+ GRAY: "\x1B[90m"
+ };
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/log/level.js
+var require_level = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/log/level.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.isLogLevel = exports2.logLevelOrder = exports2.LogLevel = void 0;
+ var LogLevel;
+ (function(LogLevel2) {
+ LogLevel2["UNKNOWN"] = "UNKNOWN";
+ LogLevel2["INFO"] = "INFO";
+ LogLevel2["WARN"] = "WARN";
+ LogLevel2["DEBUG"] = "DEBUG";
+ LogLevel2["ERROR"] = "ERROR";
+ LogLevel2["SYS"] = "SYS";
+ })(LogLevel || (exports2.LogLevel = LogLevel = {}));
+ exports2.logLevelOrder = [
+ LogLevel.DEBUG,
+ LogLevel.INFO,
+ LogLevel.WARN,
+ LogLevel.ERROR,
+ LogLevel.SYS
+ ];
+ var isLogLevel = (l) => typeof l === "string" && exports2.logLevelOrder.some((level) => level === l);
+ exports2.isLogLevel = isLogLevel;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/log/logger.js
+var require_logger = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/log/logger.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/log/pretty_json_console.js
+var require_pretty_json_console = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/log/pretty_json_console.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.PrettyJsonConsoleLogger = void 0;
+ var index_1 = require_log();
+ var PrettyJsonConsoleLogger = class {
+ log(level, ...trace) {
+ const message = JSON.stringify({
+ level,
+ trace
+ }, null, 4);
+ const styled = `${this.getStyle(level)}${message}${index_1.ANSI.RESET}
+`;
+ this.getStream(level)(styled);
+ }
+ getStream(level) {
+ if (level === index_1.LogLevel.ERROR) {
+ return console.error;
+ }
+ return console.log;
+ }
+ getStyle(level) {
+ switch (level) {
+ case index_1.LogLevel.UNKNOWN:
+ case index_1.LogLevel.INFO:
+ return `${index_1.ANSI.MAGENTA}`;
+ case index_1.LogLevel.DEBUG:
+ return `${index_1.ANSI.CYAN}`;
+ case index_1.LogLevel.WARN:
+ return `${index_1.ANSI.BRIGHT_YELLOW}`;
+ case index_1.LogLevel.ERROR:
+ return `${index_1.ANSI.BRIGHT_RED}`;
+ case index_1.LogLevel.SYS:
+ return `${index_1.ANSI.DIM}${index_1.ANSI.BLUE}`;
+ }
+ }
+ };
+ exports2.PrettyJsonConsoleLogger = PrettyJsonConsoleLogger;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/log/trace.js
+var require_trace2 = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/log/trace.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.LogTrace = void 0;
+ var pengueno_1 = require_dist2();
+ var index_1 = require_log();
+ var LogTrace = class _LogTrace {
+ logger;
+ traces;
+ defaultLevel;
+ allowedLevels;
+ constructor(logger = new index_1.PrettyJsonConsoleLogger(), traces = [defaultTrace], defaultLevel = index_1.LogLevel.INFO, allowedLevels = defaultAllowedLevelsSupplier) {
+ this.logger = logger;
+ this.traces = traces;
+ this.defaultLevel = defaultLevel;
+ this.allowedLevels = allowedLevels;
+ }
+ traceScope(trace) {
+ return new _LogTrace(this.logger, this.traces.concat(trace), this.defaultLevel, this.allowedLevels);
+ }
+ trace(trace) {
+ const { traces, level: _level } = this.foldTraces(this.traces.concat(trace));
+ if (!this.allowedLevels().has(_level))
+ return;
+ const level = _level === index_1.LogLevel.UNKNOWN ? this.defaultLevel : _level;
+ this.logger.log(level, ...traces);
+ }
+ foldTraces(_traces) {
+ const _logTraces = _traces.map((trace) => typeof trace === "function" ? trace() : trace);
+ const _level = _logTraces.filter((trace) => (0, index_1.isLogLevel)(trace)).reduce((acc, level2) => Math.max(index_1.logLevelOrder.indexOf(level2), acc), -1);
+ const level = index_1.logLevelOrder[_level] ?? index_1.LogLevel.UNKNOWN;
+ const traces = _logTraces.filter((trace) => !(0, index_1.isLogLevel)(trace)).map((trace) => {
+ if (typeof trace === "object") {
+ return `TracedException.Name = ${trace.name}, TracedException.Message = ${trace.message}, TracedException.Stack = ${trace.stack}`;
+ }
+ return trace;
+ });
+ return {
+ level,
+ traces
+ };
+ }
+ };
+ exports2.LogTrace = LogTrace;
+ var defaultTrace = () => `TimeStamp = ${(/* @__PURE__ */ new Date()).toISOString()}`;
+ var defaultAllowedLevels = (0, pengueno_1.memoize)((isDebug) => /* @__PURE__ */ new Set([
+ index_1.LogLevel.UNKNOWN,
+ ...isDebug ? [index_1.LogLevel.DEBUG] : [],
+ index_1.LogLevel.INFO,
+ index_1.LogLevel.WARN,
+ index_1.LogLevel.ERROR,
+ index_1.LogLevel.SYS
+ ]));
+ var defaultAllowedLevelsSupplier = () => defaultAllowedLevels((0, pengueno_1.isDebug)());
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/log/index.js
+var require_log = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/log/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_ansi(), exports2);
+ __exportStar(require_level(), exports2);
+ __exportStar(require_logger(), exports2);
+ __exportStar(require_pretty_json_console(), exports2);
+ __exportStar(require_trace2(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/trace.js
+var require_trace3 = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/trace.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.LogMetricTraceable = exports2.LogMetricTrace = exports2.EmbeddedMetricsTraceable = exports2.LogTraceable = void 0;
+ var _1 = require_trace4();
+ var LogTraceable = class _LogTraceable extends _1.TraceableImpl {
+ static LogTrace = new _1.LogTrace();
+ static of(t) {
+ return new _LogTraceable(t, _LogTraceable.LogTrace);
+ }
+ };
+ exports2.LogTraceable = LogTraceable;
+ var getEmbeddedMetricConsumer = (logTrace) => (metrics) => {
+ if (metrics.length === 0)
+ return;
+ logTrace.traceScope(_1.LogLevel.SYS).trace(`Metrics = <metrics>${JSON.stringify(metrics)}</metrics>`);
+ };
+ var EmbeddedMetricsTraceable = class _EmbeddedMetricsTraceable extends _1.TraceableImpl {
+ static MetricsTrace = new _1.MetricsTrace(getEmbeddedMetricConsumer(LogTraceable.LogTrace));
+ static of(t, metricsTrace = _EmbeddedMetricsTraceable.MetricsTrace) {
+ return new _EmbeddedMetricsTraceable(t, metricsTrace);
+ }
+ };
+ exports2.EmbeddedMetricsTraceable = EmbeddedMetricsTraceable;
+ var LogMetricTrace = class _LogMetricTrace {
+ logTrace;
+ metricsTrace;
+ constructor(logTrace, metricsTrace) {
+ this.logTrace = logTrace;
+ this.metricsTrace = metricsTrace;
+ }
+ traceScope(trace) {
+ if ((0, _1.isMetricsTraceSupplier)(trace)) {
+ return new _LogMetricTrace(this.logTrace, this.metricsTrace.traceScope(trace));
+ }
+ return new _LogMetricTrace(this.logTrace.traceScope(trace), this.metricsTrace);
+ }
+ trace(trace) {
+ if ((0, _1.isMetricsTraceSupplier)(trace)) {
+ this.metricsTrace.trace(trace);
+ return this;
+ }
+ this.logTrace.trace(trace);
+ return this;
+ }
+ };
+ exports2.LogMetricTrace = LogMetricTrace;
+ var LogMetricTraceable = class _LogMetricTraceable extends _1.TraceableImpl {
+ static ofLogTraceable(t) {
+ const metricsTrace = new _1.MetricsTrace(getEmbeddedMetricConsumer(t.trace));
+ return new _LogMetricTraceable(t.get(), new LogMetricTrace(t.trace, metricsTrace));
+ }
+ static of(t) {
+ const logTrace = LogTraceable.of(t);
+ return _LogMetricTraceable.ofLogTraceable(logTrace);
+ }
+ };
+ exports2.LogMetricTraceable = LogMetricTraceable;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/util.js
+var require_util = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/util.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.TraceUtil = void 0;
+ var pengueno_1 = require_dist2();
+ var TraceUtil = class _TraceUtil {
+ static promiseify(mapper) {
+ return (traceablePromise) => traceablePromise.flatMapAsync(async (t) => t.move(await t.get()).map(mapper)).get();
+ }
+ static traceResultingEither(metric, warnOnFailure = false) {
+ return (t) => {
+ if (metric)
+ t.trace.trace(t.get().fold((_err) => warnOnFailure ? metric.warn : metric.failure, (_ok) => metric.success));
+ return t.traceScope((_t) => _t.get().fold((_err) => warnOnFailure ? pengueno_1.LogLevel.WARN : pengueno_1.LogLevel.ERROR, (_ok) => pengueno_1.LogLevel.INFO));
+ };
+ }
+ static withTrace(trace) {
+ return (t) => t.traceScope(() => trace);
+ }
+ static withMetricTrace(metric) {
+ return _TraceUtil.withTrace(metric);
+ }
+ static withFunctionTrace(f) {
+ return _TraceUtil.withTrace(`fn.${f.name}`);
+ }
+ static withClassTrace(c) {
+ return _TraceUtil.withTrace(`class.${c.constructor.name}`);
+ }
+ };
+ exports2.TraceUtil = TraceUtil;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/trace/index.js
+var require_trace4 = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/trace/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_itrace(), exports2);
+ __exportStar(require_metric2(), exports2);
+ __exportStar(require_log(), exports2);
+ __exportStar(require_trace3(), exports2);
+ __exportStar(require_util(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/process/exec.js
+var require_exec = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/process/exec.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.getStdoutMany = exports2.getStdout = exports2.CmdMetric = void 0;
+ var pengueno_1 = require_dist2();
+ var node_child_process_1 = require("node:child_process");
+ exports2.CmdMetric = pengueno_1.Metric.fromName("Exec").asResult();
+ var getStdout = (cmd, options = { streamTraceable: [] }) => cmd.flatMap(pengueno_1.TraceUtil.withFunctionTrace(exports2.getStdout)).flatMap((tCmd) => tCmd.traceScope(() => `Command = ${tCmd.get()}`)).map((tCmd) => {
+ const cmd2 = tCmd.get();
+ const _exec = typeof cmd2 === "string" ? cmd2 : cmd2.join(" ");
+ const env = options.clearEnv ? options.env : { ...process.env, ...options.env };
+ return pengueno_1.Either.fromFailableAsync(new Promise((res, rej) => {
+ const proc = (0, node_child_process_1.exec)(_exec, { env });
+ let stdout = "";
+ proc.stdout?.on("data", (d) => {
+ const s = d.toString();
+ stdout += s;
+ if (options.streamTraceable?.includes("stdout")) {
+ tCmd.trace.trace(s);
+ }
+ });
+ const stderr = "";
+ proc.stderr?.on("data", (d) => {
+ const s = d.toString();
+ stdout += s;
+ if (options.streamTraceable?.includes("stderr")) {
+ tCmd.trace.trace(s);
+ }
+ });
+ proc.on("exit", (code) => {
+ const streams = { stdout, stderr };
+ if (code === 0) {
+ res(streams);
+ } else {
+ rej(new Error(`exited with non-zero code: ${code}. ${stderr}`));
+ }
+ });
+ }));
+ }).map(pengueno_1.TraceUtil.promiseify((tEitherStdStreams) => tEitherStdStreams.get().mapRight(({ stderr, stdout }) => {
+ if (stderr)
+ tEitherStdStreams.trace.traceScope(pengueno_1.LogLevel.DEBUG).trace(`StdErr = ${stderr}`);
+ return stdout;
+ }))).peek(pengueno_1.TraceUtil.promiseify(pengueno_1.TraceUtil.traceResultingEither(exports2.CmdMetric))).get();
+ exports2.getStdout = getStdout;
+ var getStdoutMany = (cmds, options = { streamTraceable: [] }) => cmds.coExtend((t) => t.get()).reduce(async (_result, tCmd) => {
+ const result = await _result;
+ return result.joinRightAsync(() => tCmd.map((cmd) => (0, exports2.getStdout)(cmd, options)).get(), (stdout, pre) => pre.concat(stdout));
+ }, Promise.resolve(pengueno_1.Either.right([])));
+ exports2.getStdoutMany = getStdoutMany;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/process/env.js
+var require_env = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/process/env.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.getRequiredEnvVars = exports2.getRequiredEnv = exports2.getEnv = void 0;
+ var pengueno_1 = require_dist2();
+ var getEnv = (name) => pengueno_1.Optional.from(process.env[name]);
+ exports2.getEnv = getEnv;
+ var getRequiredEnv = (name) => pengueno_1.Either.fromFailable(() => (0, exports2.getEnv)(name).get()).mapLeft(() => new Error(`environment variable "${name}" is required D:`));
+ exports2.getRequiredEnv = getRequiredEnv;
+ var getRequiredEnvVars = (vars) => {
+ const emptyEnvironment = pengueno_1.Either.right({});
+ const addTo = (env, key, val) => ({
+ ...env,
+ [key]: val
+ });
+ return vars.reduce((environment, key) => environment.joinRight((0, exports2.getRequiredEnv)(key), (value, environment2) => addTo(environment2, key, value)), emptyEnvironment);
+ };
+ exports2.getRequiredEnvVars = getRequiredEnvVars;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/process/validate_identifier.js
+var require_validate_identifier = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/process/validate_identifier.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.validateExecutionEntries = exports2.validateIdentifier = void 0;
+ var pengueno_1 = require_dist2();
+ var validateIdentifier = (token) => {
+ return /^[a-zA-Z0-9_\?\&\=\-:. \/]+$/.test(token) && !token.includes("..");
+ };
+ exports2.validateIdentifier = validateIdentifier;
+ var validateExecutionEntries = (obj) => {
+ const invalidEntries = Object.entries(obj).filter((e) => !e.every((x) => typeof x === "string" && (0, exports2.validateIdentifier)(x)));
+ if (invalidEntries.length > 0)
+ return pengueno_1.Either.left(invalidEntries);
+ return pengueno_1.Either.right(obj);
+ };
+ exports2.validateExecutionEntries = validateExecutionEntries;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/process/argv.js
+var require_argv = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/process/argv.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.argv = exports2.getArg = exports2.isArgKey = void 0;
+ var pengueno_1 = require_dist2();
+ var isArgKey = (k) => k.startsWith("--");
+ exports2.isArgKey = isArgKey;
+ var getArg = (arg, argv2, whenValue) => {
+ const argIndex = pengueno_1.Optional.from(argv2.findIndex((_argv) => (0, exports2.isArgKey)(_argv) && _argv.split("=")[0] === arg)).filter((index) => index >= 0 && index < argv2.length);
+ if (!argIndex.present()) {
+ return pengueno_1.Optional.from(whenValue.absent).map((v) => pengueno_1.Either.right(v)).orSome(() => pengueno_1.Either.left(new Error(`arg ${arg} is not present in arguments list and does not have an 'absent' value`))).get();
+ }
+ return argIndex.flatMap((idx) => pengueno_1.Optional.from(argv2.at(idx)).map((_argv) => _argv.includes("=") ? _argv.split("=")[1] : argv2.at(idx + 1))).filter((next) => !(0, exports2.isArgKey)(next)).map((next) => whenValue.present(next)).orSome(() => whenValue.unspecified).map((v) => pengueno_1.Either.right(v)).get();
+ };
+ exports2.getArg = getArg;
+ var argv = (args, handlers, argv2 = process.argv.slice(2)) => {
+ const defaultHandler = { present: (value) => value };
+ const processArg = (arg) => {
+ const handler = handlers?.[arg] ?? defaultHandler;
+ return (0, exports2.getArg)(arg, argv2, handler).mapRight((value) => [arg, value]);
+ };
+ const res = args.map(processArg).reduce((acc, current) => acc.flatMap((accValue) => current.mapRight(([key, value]) => ({
+ ...accValue,
+ [key]: value
+ }))), pengueno_1.Either.right({})).mapRight((result) => result);
+ return res;
+ };
+ exports2.argv = argv;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/process/signals.js
+var require_signals = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/process/signals.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.Signals = exports2.SigTermMetric = exports2.SigIntMetric = void 0;
+ var pengueno_1 = require_dist2();
+ exports2.SigIntMetric = pengueno_1.Metric.fromName("SigInt").asResult();
+ exports2.SigTermMetric = pengueno_1.Metric.fromName("SigTerm").asResult();
+ var Signals = class {
+ static async awaitClose(t) {
+ const success = pengueno_1.Either.right(void 0);
+ return new Promise((res) => {
+ const metricizedInterruptHandler = (metric) => (err) => t.flatMap(pengueno_1.TraceUtil.withMetricTrace(metric)).peek((_t) => _t.trace.trace("closing")).move(pengueno_1.Optional.from(err).map((e) => pengueno_1.Either.left(e)).orSome(() => success).get()).flatMap(pengueno_1.TraceUtil.traceResultingEither(metric)).map((e) => res(e.get())).peek((_t) => _t.trace.trace("finished")).get();
+ const sigintCloser = metricizedInterruptHandler(exports2.SigIntMetric);
+ const sigtermCloser = metricizedInterruptHandler(exports2.SigTermMetric);
+ process.on("SIGINT", () => t.flatMap(pengueno_1.TraceUtil.withTrace("SIGINT")).get().close(sigintCloser));
+ process.on("SIGTERM", () => t.flatMap(pengueno_1.TraceUtil.withTrace("SIGTERM")).get().close(sigtermCloser));
+ });
+ }
+ };
+ exports2.Signals = Signals;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/process/index.js
+var require_process = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/process/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_exec(), exports2);
+ __exportStar(require_env(), exports2);
+ __exportStar(require_validate_identifier(), exports2);
+ __exportStar(require_argv(), exports2);
+ __exportStar(require_signals(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/http/body.js
+var require_body = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/http/body.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/http/status.js
+var require_status = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/http/status.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.HttpStatusCodes = void 0;
+ exports2.HttpStatusCodes = {
+ 100: "Continue",
+ 101: "Switching Protocols",
+ 102: "Processing (WebDAV)",
+ 200: "OK",
+ 201: "Created",
+ 202: "Accepted",
+ 203: "Non-Authoritative Information",
+ 204: "No Content",
+ 205: "Reset Content",
+ 206: "Partial Content",
+ 207: "Multi-Status (WebDAV)",
+ 208: "Already Reported (WebDAV)",
+ 226: "IM Used",
+ 300: "Multiple Choices",
+ 301: "Moved Permanently",
+ 302: "Found",
+ 303: "See Other",
+ 304: "Not Modified",
+ 305: "Use Proxy",
+ 306: "(Unused)",
+ 307: "Temporary Redirect",
+ 308: "Permanent Redirect (experimental)",
+ 400: "Bad Request",
+ 401: "Unauthorized",
+ 402: "Payment Required",
+ 403: "Forbidden",
+ 404: "Not Found",
+ 405: "Method Not Allowed",
+ 406: "Not Acceptable",
+ 407: "Proxy Authentication Required",
+ 408: "Request Timeout",
+ 409: "Conflict",
+ 410: "Gone",
+ 411: "Length Required",
+ 412: "Precondition Failed",
+ 413: "Request Entity Too Large",
+ 414: "Request-URI Too Long",
+ 415: "Unsupported Media Type",
+ 416: "Requested Range Not Satisfiable",
+ 417: "Expectation Failed",
+ 418: "I'm a teapot (RFC 2324)",
+ 420: "Enhance Your Calm (Twitter)",
+ 422: "Unprocessable Entity (WebDAV)",
+ 423: "Locked (WebDAV)",
+ 424: "Failed Dependency (WebDAV)",
+ 425: "Reserved for WebDAV",
+ 426: "Upgrade Required",
+ 428: "Precondition Required",
+ 429: "Too Many Requests",
+ 431: "Request Header Fields Too Large",
+ 444: "No Response (Nginx)",
+ 449: "Retry With (Microsoft)",
+ 450: "Blocked by Windows Parental Controls (Microsoft)",
+ 451: "Unavailable For Legal Reasons",
+ 499: "Client Closed Request (Nginx)",
+ 500: "Internal Server Error",
+ 501: "Not Implemented",
+ 502: "Bad Gateway",
+ 503: "Service Unavailable",
+ 504: "Gateway Timeout",
+ 505: "HTTP Version Not Supported",
+ 506: "Variant Also Negotiates (Experimental)",
+ 507: "Insufficient Storage (WebDAV)",
+ 508: "Loop Detected (WebDAV)",
+ 509: "Bandwidth Limit Exceeded (Apache)",
+ 510: "Not Extended",
+ 511: "Network Authentication Required",
+ 598: "Network read timeout error",
+ 599: "Network connect timeout error"
+ };
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/http/method.js
+var require_method = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/http/method.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/http/index.js
+var require_http = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/http/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_body(), exports2);
+ __exportStar(require_status(), exports2);
+ __exportStar(require_method(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/response/pengueno.js
+var require_pengueno = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/response/pengueno.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.JsonResponse = exports2.PenguenoResponse = exports2.getResponseMetrics = void 0;
+ var pengueno_1 = require_dist2();
+ var getHeaders = (req, extraHeaders) => {
+ const optHeaders = {
+ ...req.getResponseHeaders(),
+ ...extraHeaders
+ };
+ optHeaders["Content-Type"] = (optHeaders["Content-Type"] ?? "text/plain") + "; charset=utf-8";
+ return optHeaders;
+ };
+ var ResponseCodeMetrics = [0, 1, 2, 3, 4, 5].map((x) => pengueno_1.Metric.fromName(`response.${x}xx`).asResult());
+ var getResponseMetrics = (status, elapsedMs) => {
+ const index = Math.floor(status / 100);
+ return ResponseCodeMetrics.flatMap((metric, i) => pengueno_1.Optional.from(i).filter((i2) => i2 === index).map(() => [metric.count.withValue(1)]).flatMap((metricValues) => pengueno_1.Optional.from(elapsedMs).map((ms) => metricValues.concat(metric.time.withValue(ms))).orSome(() => metricValues)).orSome(() => [metric.count.withValue(0)]).get());
+ };
+ exports2.getResponseMetrics = getResponseMetrics;
+ var PenguenoResponse = class {
+ _body;
+ statusText;
+ status;
+ headers;
+ constructor(req, _body, opts) {
+ this._body = _body;
+ this.headers = getHeaders(req.get(), opts?.headers ?? {});
+ this.status = opts.status;
+ this.statusText = opts.statusText ?? pengueno_1.HttpStatusCodes[this.status];
+ req.trace.trace((0, exports2.getResponseMetrics)(opts.status, req.get().elapsedTimeMs()));
+ }
+ body() {
+ return this._body;
+ }
+ };
+ exports2.PenguenoResponse = PenguenoResponse;
+ var JsonResponse = class extends PenguenoResponse {
+ constructor(req, e, _opts) {
+ const opts = { ..._opts, headers: { ..._opts.headers, "Content-Type": "application/json" } };
+ if ((0, pengueno_1.isEither)(e)) {
+ super(req, JSON.stringify(e.fold((error) => ({ error, ok: void 0 }), (ok) => ({ ok }))), opts);
+ return;
+ }
+ super(req, JSON.stringify(Math.floor(opts.status / 100) > 4 ? { error: e } : { ok: e }), opts);
+ }
+ };
+ exports2.JsonResponse = JsonResponse;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/response/index.js
+var require_response = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/response/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_pengueno(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/request/pengueno.js
+var require_pengueno2 = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/request/pengueno.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.PenguenoRequest = void 0;
+ var greetings = ["hewwo :D", "hiya cutie", "boop!", "sending virtual hugs!", "stay pawsitive"];
+ var penguenoGreeting = () => greetings[Math.floor(Math.random() * greetings.length)];
+ var PenguenoRequest = class _PenguenoRequest {
+ req;
+ id;
+ at;
+ constructor(req, id, at) {
+ this.req = req;
+ this.id = id;
+ this.at = at;
+ }
+ elapsedTimeMs(after = () => Date.now()) {
+ return after() - this.at.getTime();
+ }
+ getResponseHeaders() {
+ const RequestId = this.id;
+ const RequestReceivedUnix = this.at.getTime();
+ const RequestHandleUnix = Date.now();
+ const DeltaUnix = this.elapsedTimeMs(() => RequestHandleUnix);
+ const Hai = penguenoGreeting();
+ return Object.entries({
+ RequestId,
+ RequestReceivedUnix,
+ RequestHandleUnix,
+ DeltaUnix,
+ Hai
+ }).reduce((acc, [key, val]) => ({ ...acc, [key]: val.toString() }), {});
+ }
+ static from(request) {
+ const id = crypto.randomUUID();
+ return request.bimap((tRequest) => {
+ const request2 = tRequest.get();
+ const url = new URL(request2.url);
+ const { pathname } = url;
+ const trace = `RequestId = ${id}, Method = ${request2.method}, Path = ${pathname}`;
+ return { item: new _PenguenoRequest(request2, id, /* @__PURE__ */ new Date()), trace };
+ });
+ }
+ };
+ exports2.PenguenoRequest = PenguenoRequest;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/request/index.js
+var require_request = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/request/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_pengueno2(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/activity/health.js
+var require_health = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/activity/health.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.HealthCheckActivityImpl = exports2.HealthCheckOutput = exports2.HealthCheckInput = void 0;
+ var pengueno_1 = require_dist2();
+ var HealthCheckInput;
+ (function(HealthCheckInput2) {
+ HealthCheckInput2[HealthCheckInput2["CHECK"] = 0] = "CHECK";
+ })(HealthCheckInput || (exports2.HealthCheckInput = HealthCheckInput = {}));
+ var HealthCheckOutput;
+ (function(HealthCheckOutput2) {
+ HealthCheckOutput2[HealthCheckOutput2["YAASSSLAYQUEEN"] = 0] = "YAASSSLAYQUEEN";
+ })(HealthCheckOutput || (exports2.HealthCheckOutput = HealthCheckOutput = {}));
+ var healthCheckMetric = pengueno_1.Metric.fromName("Health").asResult();
+ var HealthCheckActivityImpl = class {
+ check;
+ constructor(check) {
+ this.check = check;
+ }
+ checkHealth(req) {
+ return req.flatMap(pengueno_1.TraceUtil.withFunctionTrace(this.checkHealth)).flatMap(pengueno_1.TraceUtil.withMetricTrace(healthCheckMetric)).flatMap((r) => r.move(HealthCheckInput.CHECK).map((input) => this.check(input))).peek(pengueno_1.TraceUtil.promiseify(pengueno_1.TraceUtil.traceResultingEither(healthCheckMetric))).map(pengueno_1.TraceUtil.promiseify((h) => {
+ const { status, message } = h.get().fold(() => ({ status: 500, message: "err" }), () => ({ status: 200, message: "ok" }));
+ return new pengueno_1.JsonResponse(req, message, { status });
+ })).get();
+ }
+ };
+ exports2.HealthCheckActivityImpl = HealthCheckActivityImpl;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/activity/fourohfour.js
+var require_fourohfour = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/activity/fourohfour.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.FourOhFourActivityImpl = void 0;
+ var pengueno_1 = require_dist2();
+ var messages = [
+ "D: meow-t found! your api call ran away!",
+ "404-bidden! but like...in a cute way >:3 !",
+ ":< your data went on a paw-sible vacation!",
+ "uwu~ not found, but found our hearts instead!"
+ ];
+ var randomFourOhFour = () => messages[Math.floor(Math.random() * messages.length)];
+ var FourOhFourActivityImpl = class {
+ fourOhFour(req) {
+ return req.move(new pengueno_1.JsonResponse(req, randomFourOhFour(), { status: 404 })).map((resp) => Promise.resolve(resp.get())).get();
+ }
+ };
+ exports2.FourOhFourActivityImpl = FourOhFourActivityImpl;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/activity/index.js
+var require_activity = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/activity/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_health(), exports2);
+ __exportStar(require_fourohfour(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/filter/method.js
+var require_method2 = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/filter/method.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.requireMethod = void 0;
+ var pengueno_1 = require_dist2();
+ var requireMethod = (methods) => (req) => req.flatMap(pengueno_1.TraceUtil.withFunctionTrace(exports2.requireMethod)).map((t) => {
+ const { req: { method } } = t.get();
+ if (!methods.includes(method)) {
+ const msg = "that's not how you pet me (\u22DF\uFE4F\u22DE)~";
+ t.trace.traceScope(pengueno_1.LogLevel.WARN).trace(msg);
+ return pengueno_1.Either.left(new pengueno_1.PenguenoError(msg, 405));
+ }
+ return pengueno_1.Either.right(method);
+ }).get();
+ exports2.requireMethod = requireMethod;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/filter/json.js
+var require_json = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/filter/json.js"(exports2) {
+ "use strict";
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.jsonModel = void 0;
+ var pengueno_1 = require_dist2();
+ var ParseJsonMetric = pengueno_1.Metric.fromName("JsonParse").asResult();
+ var jsonModel = (jsonTransformer) => (r) => r.flatMap(pengueno_1.TraceUtil.withFunctionTrace(exports2.jsonModel)).flatMap(pengueno_1.TraceUtil.withMetricTrace(ParseJsonMetric)).map((j) => pengueno_1.Either.fromFailableAsync(j.get().req.json()).then((either) => either.mapLeft((errReason) => {
+ j.trace.traceScope(pengueno_1.LogLevel.WARN).trace(errReason);
+ return new pengueno_1.PenguenoError("seems to be invalid JSON (>//<) can you fix?", 400);
+ }))).flatMapAsync(pengueno_1.TraceUtil.promiseify(pengueno_1.TraceUtil.traceResultingEither(ParseJsonMetric))).map(pengueno_1.TraceUtil.promiseify((traceableEitherJson) => traceableEitherJson.get().mapRight((j) => traceableEitherJson.move(j)).flatMap(jsonTransformer))).get();
+ exports2.jsonModel = jsonModel;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/filter/index.js
+var require_filter = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/filter/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.PenguenoError = exports2.ErrorSource = void 0;
+ var pengueno_1 = require_dist2();
+ var ErrorSource;
+ (function(ErrorSource2) {
+ ErrorSource2["USER"] = "WARN";
+ ErrorSource2["SYSTEM"] = "ERROR";
+ })(ErrorSource || (exports2.ErrorSource = ErrorSource = {}));
+ var PenguenoError = class extends Error {
+ message;
+ status;
+ source;
+ constructor(message, status) {
+ super(message);
+ this.message = message;
+ this.status = status;
+ this.source = Math.floor(status / 100) === 4 ? ErrorSource.USER : ErrorSource.SYSTEM;
+ }
+ };
+ exports2.PenguenoError = PenguenoError;
+ __exportStar(require_method2(), exports2);
+ __exportStar(require_json(), exports2);
+ }
+});
+
+// node_modules/hono/dist/cjs/compose.js
+var require_compose = __commonJS({
+ "node_modules/hono/dist/cjs/compose.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var compose_exports = {};
+ __export(compose_exports, {
+ compose: () => compose
+ });
+ module2.exports = __toCommonJS(compose_exports);
+ var compose = (middleware, onError, onNotFound) => {
+ return (context, next) => {
+ let index = -1;
+ return dispatch(0);
+ async function dispatch(i) {
+ if (i <= index) {
+ throw new Error("next() called multiple times");
+ }
+ index = i;
+ let res;
+ let isError = false;
+ let handler;
+ if (middleware[i]) {
+ handler = middleware[i][0][0];
+ context.req.routeIndex = i;
+ } else {
+ handler = i === middleware.length && next || void 0;
+ }
+ if (handler) {
+ try {
+ res = await handler(context, () => dispatch(i + 1));
+ } catch (err) {
+ if (err instanceof Error && onError) {
+ context.error = err;
+ res = await onError(err, context);
+ isError = true;
+ } else {
+ throw err;
+ }
+ }
+ } else {
+ if (context.finalized === false && onNotFound) {
+ res = await onNotFound(context);
+ }
+ }
+ if (res && (context.finalized === false || isError)) {
+ context.res = res;
+ }
+ return context;
+ }
+ };
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/http-exception.js
+var require_http_exception = __commonJS({
+ "node_modules/hono/dist/cjs/http-exception.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var http_exception_exports = {};
+ __export(http_exception_exports, {
+ HTTPException: () => HTTPException
+ });
+ module2.exports = __toCommonJS(http_exception_exports);
+ var HTTPException = class extends Error {
+ res;
+ status;
+ constructor(status = 500, options) {
+ super(options?.message, { cause: options?.cause });
+ this.res = options?.res;
+ this.status = status;
+ }
+ getResponse() {
+ if (this.res) {
+ const newResponse = new Response(this.res.body, {
+ status: this.status,
+ headers: this.res.headers
+ });
+ return newResponse;
+ }
+ return new Response(this.message, {
+ status: this.status
+ });
+ }
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/request/constants.js
+var require_constants = __commonJS({
+ "node_modules/hono/dist/cjs/request/constants.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var constants_exports = {};
+ __export(constants_exports, {
+ GET_MATCH_RESULT: () => GET_MATCH_RESULT
+ });
+ module2.exports = __toCommonJS(constants_exports);
+ var GET_MATCH_RESULT = Symbol();
+ }
+});
+
+// node_modules/hono/dist/cjs/utils/body.js
+var require_body2 = __commonJS({
+ "node_modules/hono/dist/cjs/utils/body.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var body_exports = {};
+ __export(body_exports, {
+ parseBody: () => parseBody
+ });
+ module2.exports = __toCommonJS(body_exports);
+ var import_request = require_request2();
+ var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
+ const { all = false, dot = false } = options;
+ const headers = request instanceof import_request.HonoRequest ? request.raw.headers : request.headers;
+ const contentType = headers.get("Content-Type");
+ if (contentType?.startsWith("multipart/form-data") || contentType?.startsWith("application/x-www-form-urlencoded")) {
+ return parseFormData(request, { all, dot });
+ }
+ return {};
+ };
+ async function parseFormData(request, options) {
+ const formData = await request.formData();
+ if (formData) {
+ return convertFormDataToBodyData(formData, options);
+ }
+ return {};
+ }
+ function convertFormDataToBodyData(formData, options) {
+ const form = /* @__PURE__ */ Object.create(null);
+ formData.forEach((value, key) => {
+ const shouldParseAllValues = options.all || key.endsWith("[]");
+ if (!shouldParseAllValues) {
+ form[key] = value;
+ } else {
+ handleParsingAllValues(form, key, value);
+ }
+ });
+ if (options.dot) {
+ Object.entries(form).forEach(([key, value]) => {
+ const shouldParseDotValues = key.includes(".");
+ if (shouldParseDotValues) {
+ handleParsingNestedValues(form, key, value);
+ delete form[key];
+ }
+ });
+ }
+ return form;
+ }
+ var handleParsingAllValues = (form, key, value) => {
+ if (form[key] !== void 0) {
+ if (Array.isArray(form[key])) {
+ ;
+ form[key].push(value);
+ } else {
+ form[key] = [form[key], value];
+ }
+ } else {
+ if (!key.endsWith("[]")) {
+ form[key] = value;
+ } else {
+ form[key] = [value];
+ }
+ }
+ };
+ var handleParsingNestedValues = (form, key, value) => {
+ let nestedForm = form;
+ const keys = key.split(".");
+ keys.forEach((key2, index) => {
+ if (index === keys.length - 1) {
+ nestedForm[key2] = value;
+ } else {
+ if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) {
+ nestedForm[key2] = /* @__PURE__ */ Object.create(null);
+ }
+ nestedForm = nestedForm[key2];
+ }
+ });
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/utils/url.js
+var require_url = __commonJS({
+ "node_modules/hono/dist/cjs/utils/url.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var url_exports = {};
+ __export(url_exports, {
+ checkOptionalParameter: () => checkOptionalParameter,
+ decodeURIComponent_: () => decodeURIComponent_,
+ getPath: () => getPath,
+ getPathNoStrict: () => getPathNoStrict,
+ getPattern: () => getPattern,
+ getQueryParam: () => getQueryParam,
+ getQueryParams: () => getQueryParams,
+ getQueryStrings: () => getQueryStrings,
+ mergePath: () => mergePath,
+ splitPath: () => splitPath,
+ splitRoutingPath: () => splitRoutingPath,
+ tryDecode: () => tryDecode
+ });
+ module2.exports = __toCommonJS(url_exports);
+ var splitPath = (path) => {
+ const paths = path.split("/");
+ if (paths[0] === "") {
+ paths.shift();
+ }
+ return paths;
+ };
+ var splitRoutingPath = (routePath) => {
+ const { groups, path } = extractGroupsFromPath(routePath);
+ const paths = splitPath(path);
+ return replaceGroupMarks(paths, groups);
+ };
+ var extractGroupsFromPath = (path) => {
+ const groups = [];
+ path = path.replace(/\{[^}]+\}/g, (match, index) => {
+ const mark = `@${index}`;
+ groups.push([mark, match]);
+ return mark;
+ });
+ return { groups, path };
+ };
+ var replaceGroupMarks = (paths, groups) => {
+ for (let i = groups.length - 1; i >= 0; i--) {
+ const [mark] = groups[i];
+ for (let j = paths.length - 1; j >= 0; j--) {
+ if (paths[j].includes(mark)) {
+ paths[j] = paths[j].replace(mark, groups[i][1]);
+ break;
+ }
+ }
+ }
+ return paths;
+ };
+ var patternCache = {};
+ var getPattern = (label, next) => {
+ if (label === "*") {
+ return "*";
+ }
+ const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
+ if (match) {
+ const cacheKey = `${label}#${next}`;
+ if (!patternCache[cacheKey]) {
+ if (match[2]) {
+ patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey, match[1], new RegExp(`^${match[2]}(?=/${next})`)] : [label, match[1], new RegExp(`^${match[2]}$`)];
+ } else {
+ patternCache[cacheKey] = [label, match[1], true];
+ }
+ }
+ return patternCache[cacheKey];
+ }
+ return null;
+ };
+ var tryDecode = (str, decoder) => {
+ try {
+ return decoder(str);
+ } catch {
+ return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
+ try {
+ return decoder(match);
+ } catch {
+ return match;
+ }
+ });
+ }
+ };
+ var tryDecodeURI = (str) => tryDecode(str, decodeURI);
+ var getPath = (request) => {
+ const url = request.url;
+ const start = url.indexOf("/", url.indexOf(":") + 4);
+ let i = start;
+ for (; i < url.length; i++) {
+ const charCode = url.charCodeAt(i);
+ if (charCode === 37) {
+ const queryIndex = url.indexOf("?", i);
+ const path = url.slice(start, queryIndex === -1 ? void 0 : queryIndex);
+ return tryDecodeURI(path.includes("%25") ? path.replace(/%25/g, "%2525") : path);
+ } else if (charCode === 63) {
+ break;
+ }
+ }
+ return url.slice(start, i);
+ };
+ var getQueryStrings = (url) => {
+ const queryIndex = url.indexOf("?", 8);
+ return queryIndex === -1 ? "" : "?" + url.slice(queryIndex + 1);
+ };
+ var getPathNoStrict = (request) => {
+ const result = getPath(request);
+ return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
+ };
+ var mergePath = (base, sub, ...rest) => {
+ if (rest.length) {
+ sub = mergePath(sub, ...rest);
+ }
+ return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
+ };
+ var checkOptionalParameter = (path) => {
+ if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":")) {
+ return null;
+ }
+ const segments = path.split("/");
+ const results = [];
+ let basePath = "";
+ segments.forEach((segment) => {
+ if (segment !== "" && !/\:/.test(segment)) {
+ basePath += "/" + segment;
+ } else if (/\:/.test(segment)) {
+ if (/\?/.test(segment)) {
+ if (results.length === 0 && basePath === "") {
+ results.push("/");
+ } else {
+ results.push(basePath);
+ }
+ const optionalSegment = segment.replace("?", "");
+ basePath += "/" + optionalSegment;
+ results.push(basePath);
+ } else {
+ basePath += "/" + segment;
+ }
+ }
+ });
+ return results.filter((v, i, a) => a.indexOf(v) === i);
+ };
+ var _decodeURI = (value) => {
+ if (!/[%+]/.test(value)) {
+ return value;
+ }
+ if (value.indexOf("+") !== -1) {
+ value = value.replace(/\+/g, " ");
+ }
+ return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value;
+ };
+ var _getQueryParam = (url, key, multiple) => {
+ let encoded;
+ if (!multiple && key && !/[%+]/.test(key)) {
+ let keyIndex2 = url.indexOf("?", 8);
+ if (keyIndex2 === -1) {
+ return void 0;
+ }
+ if (!url.startsWith(key, keyIndex2 + 1)) {
+ keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
+ }
+ while (keyIndex2 !== -1) {
+ const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
+ if (trailingKeyCode === 61) {
+ const valueIndex = keyIndex2 + key.length + 2;
+ const endIndex = url.indexOf("&", valueIndex);
+ return _decodeURI(url.slice(valueIndex, endIndex === -1 ? void 0 : endIndex));
+ } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) {
+ return "";
+ }
+ keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
+ }
+ encoded = /[%+]/.test(url);
+ if (!encoded) {
+ return void 0;
+ }
+ }
+ const results = {};
+ encoded ??= /[%+]/.test(url);
+ let keyIndex = url.indexOf("?", 8);
+ while (keyIndex !== -1) {
+ const nextKeyIndex = url.indexOf("&", keyIndex + 1);
+ let valueIndex = url.indexOf("=", keyIndex);
+ if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) {
+ valueIndex = -1;
+ }
+ let name = url.slice(
+ keyIndex + 1,
+ valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex
+ );
+ if (encoded) {
+ name = _decodeURI(name);
+ }
+ keyIndex = nextKeyIndex;
+ if (name === "") {
+ continue;
+ }
+ let value;
+ if (valueIndex === -1) {
+ value = "";
+ } else {
+ value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex);
+ if (encoded) {
+ value = _decodeURI(value);
+ }
+ }
+ if (multiple) {
+ if (!(results[name] && Array.isArray(results[name]))) {
+ results[name] = [];
+ }
+ ;
+ results[name].push(value);
+ } else {
+ results[name] ??= value;
+ }
+ }
+ return key ? results[key] : results;
+ };
+ var getQueryParam = _getQueryParam;
+ var getQueryParams = (url, key) => {
+ return _getQueryParam(url, key, true);
+ };
+ var decodeURIComponent_ = decodeURIComponent;
+ }
+});
+
+// node_modules/hono/dist/cjs/request.js
+var require_request2 = __commonJS({
+ "node_modules/hono/dist/cjs/request.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var request_exports = {};
+ __export(request_exports, {
+ HonoRequest: () => HonoRequest,
+ cloneRawRequest: () => cloneRawRequest
+ });
+ module2.exports = __toCommonJS(request_exports);
+ var import_http_exception = require_http_exception();
+ var import_constants = require_constants();
+ var import_body = require_body2();
+ var import_url = require_url();
+ var tryDecodeURIComponent = (str) => (0, import_url.tryDecode)(str, import_url.decodeURIComponent_);
+ var HonoRequest = class {
+ raw;
+ #validatedData;
+ #matchResult;
+ routeIndex = 0;
+ path;
+ bodyCache = {};
+ constructor(request, path = "/", matchResult = [[]]) {
+ this.raw = request;
+ this.path = path;
+ this.#matchResult = matchResult;
+ this.#validatedData = {};
+ }
+ param(key) {
+ return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
+ }
+ #getDecodedParam(key) {
+ const paramKey = this.#matchResult[0][this.routeIndex][1][key];
+ const param = this.#getParamValue(paramKey);
+ return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param;
+ }
+ #getAllDecodedParams() {
+ const decoded = {};
+ const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]);
+ for (const key of keys) {
+ const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
+ if (value !== void 0) {
+ decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value;
+ }
+ }
+ return decoded;
+ }
+ #getParamValue(paramKey) {
+ return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey;
+ }
+ query(key) {
+ return (0, import_url.getQueryParam)(this.url, key);
+ }
+ queries(key) {
+ return (0, import_url.getQueryParams)(this.url, key);
+ }
+ header(name) {
+ if (name) {
+ return this.raw.headers.get(name) ?? void 0;
+ }
+ const headerData = {};
+ this.raw.headers.forEach((value, key) => {
+ headerData[key] = value;
+ });
+ return headerData;
+ }
+ async parseBody(options) {
+ return this.bodyCache.parsedBody ??= await (0, import_body.parseBody)(this, options);
+ }
+ #cachedBody = (key) => {
+ const { bodyCache, raw } = this;
+ const cachedBody = bodyCache[key];
+ if (cachedBody) {
+ return cachedBody;
+ }
+ const anyCachedKey = Object.keys(bodyCache)[0];
+ if (anyCachedKey) {
+ return bodyCache[anyCachedKey].then((body) => {
+ if (anyCachedKey === "json") {
+ body = JSON.stringify(body);
+ }
+ return new Response(body)[key]();
+ });
+ }
+ return bodyCache[key] = raw[key]();
+ };
+ json() {
+ return this.#cachedBody("text").then((text) => JSON.parse(text));
+ }
+ text() {
+ return this.#cachedBody("text");
+ }
+ arrayBuffer() {
+ return this.#cachedBody("arrayBuffer");
+ }
+ blob() {
+ return this.#cachedBody("blob");
+ }
+ formData() {
+ return this.#cachedBody("formData");
+ }
+ addValidatedData(target, data) {
+ this.#validatedData[target] = data;
+ }
+ valid(target) {
+ return this.#validatedData[target];
+ }
+ get url() {
+ return this.raw.url;
+ }
+ get method() {
+ return this.raw.method;
+ }
+ get [import_constants.GET_MATCH_RESULT]() {
+ return this.#matchResult;
+ }
+ get matchedRoutes() {
+ return this.#matchResult[0].map(([[, route]]) => route);
+ }
+ get routePath() {
+ return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path;
+ }
+ };
+ var cloneRawRequest = async (req) => {
+ if (!req.raw.bodyUsed) {
+ return req.raw.clone();
+ }
+ const cacheKey = Object.keys(req.bodyCache)[0];
+ if (!cacheKey) {
+ throw new import_http_exception.HTTPException(500, {
+ message: "Cannot clone request: body was already consumed and not cached. Please use HonoRequest methods (e.g., req.json(), req.text()) instead of consuming req.raw directly."
+ });
+ }
+ const requestInit = {
+ body: await req[cacheKey](),
+ cache: req.raw.cache,
+ credentials: req.raw.credentials,
+ headers: req.header(),
+ integrity: req.raw.integrity,
+ keepalive: req.raw.keepalive,
+ method: req.method,
+ mode: req.raw.mode,
+ redirect: req.raw.redirect,
+ referrer: req.raw.referrer,
+ referrerPolicy: req.raw.referrerPolicy,
+ signal: req.raw.signal
+ };
+ return new Request(req.url, requestInit);
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/utils/html.js
+var require_html = __commonJS({
+ "node_modules/hono/dist/cjs/utils/html.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var html_exports = {};
+ __export(html_exports, {
+ HtmlEscapedCallbackPhase: () => HtmlEscapedCallbackPhase,
+ escapeToBuffer: () => escapeToBuffer,
+ raw: () => raw,
+ resolveCallback: () => resolveCallback,
+ resolveCallbackSync: () => resolveCallbackSync,
+ stringBufferToString: () => stringBufferToString
+ });
+ module2.exports = __toCommonJS(html_exports);
+ var HtmlEscapedCallbackPhase = {
+ Stringify: 1,
+ BeforeStream: 2,
+ Stream: 3
+ };
+ var raw = (value, callbacks) => {
+ const escapedString = new String(value);
+ escapedString.isEscaped = true;
+ escapedString.callbacks = callbacks;
+ return escapedString;
+ };
+ var escapeRe = /[&<>'"]/;
+ var stringBufferToString = async (buffer, callbacks) => {
+ let str = "";
+ callbacks ||= [];
+ const resolvedBuffer = await Promise.all(buffer);
+ for (let i = resolvedBuffer.length - 1; ; i--) {
+ str += resolvedBuffer[i];
+ i--;
+ if (i < 0) {
+ break;
+ }
+ let r = resolvedBuffer[i];
+ if (typeof r === "object") {
+ callbacks.push(...r.callbacks || []);
+ }
+ const isEscaped = r.isEscaped;
+ r = await (typeof r === "object" ? r.toString() : r);
+ if (typeof r === "object") {
+ callbacks.push(...r.callbacks || []);
+ }
+ if (r.isEscaped ?? isEscaped) {
+ str += r;
+ } else {
+ const buf = [str];
+ escapeToBuffer(r, buf);
+ str = buf[0];
+ }
+ }
+ return raw(str, callbacks);
+ };
+ var escapeToBuffer = (str, buffer) => {
+ const match = str.search(escapeRe);
+ if (match === -1) {
+ buffer[0] += str;
+ return;
+ }
+ let escape;
+ let index;
+ let lastIndex = 0;
+ for (index = match; index < str.length; index++) {
+ switch (str.charCodeAt(index)) {
+ case 34:
+ escape = "&quot;";
+ break;
+ case 39:
+ escape = "&#39;";
+ break;
+ case 38:
+ escape = "&amp;";
+ break;
+ case 60:
+ escape = "&lt;";
+ break;
+ case 62:
+ escape = "&gt;";
+ break;
+ default:
+ continue;
+ }
+ buffer[0] += str.substring(lastIndex, index) + escape;
+ lastIndex = index + 1;
+ }
+ buffer[0] += str.substring(lastIndex, index);
+ };
+ var resolveCallbackSync = (str) => {
+ const callbacks = str.callbacks;
+ if (!callbacks?.length) {
+ return str;
+ }
+ const buffer = [str];
+ const context = {};
+ callbacks.forEach((c) => c({ phase: HtmlEscapedCallbackPhase.Stringify, buffer, context }));
+ return buffer[0];
+ };
+ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
+ if (typeof str === "object" && !(str instanceof String)) {
+ if (!(str instanceof Promise)) {
+ str = str.toString();
+ }
+ if (str instanceof Promise) {
+ str = await str;
+ }
+ }
+ const callbacks = str.callbacks;
+ if (!callbacks?.length) {
+ return Promise.resolve(str);
+ }
+ if (buffer) {
+ buffer[0] += str;
+ } else {
+ buffer = [str];
+ }
+ const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then(
+ (res) => Promise.all(
+ res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))
+ ).then(() => buffer[0])
+ );
+ if (preserveCallbacks) {
+ return raw(await resStr, callbacks);
+ } else {
+ return resStr;
+ }
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/context.js
+var require_context = __commonJS({
+ "node_modules/hono/dist/cjs/context.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var context_exports = {};
+ __export(context_exports, {
+ Context: () => Context,
+ TEXT_PLAIN: () => TEXT_PLAIN
+ });
+ module2.exports = __toCommonJS(context_exports);
+ var import_request = require_request2();
+ var import_html = require_html();
+ var TEXT_PLAIN = "text/plain; charset=UTF-8";
+ var setDefaultContentType = (contentType, headers) => {
+ return {
+ "Content-Type": contentType,
+ ...headers
+ };
+ };
+ var Context = class {
+ #rawRequest;
+ #req;
+ env = {};
+ #var;
+ finalized = false;
+ error;
+ #status;
+ #executionCtx;
+ #res;
+ #layout;
+ #renderer;
+ #notFoundHandler;
+ #preparedHeaders;
+ #matchResult;
+ #path;
+ constructor(req, options) {
+ this.#rawRequest = req;
+ if (options) {
+ this.#executionCtx = options.executionCtx;
+ this.env = options.env;
+ this.#notFoundHandler = options.notFoundHandler;
+ this.#path = options.path;
+ this.#matchResult = options.matchResult;
+ }
+ }
+ get req() {
+ this.#req ??= new import_request.HonoRequest(this.#rawRequest, this.#path, this.#matchResult);
+ return this.#req;
+ }
+ get event() {
+ if (this.#executionCtx && "respondWith" in this.#executionCtx) {
+ return this.#executionCtx;
+ } else {
+ throw Error("This context has no FetchEvent");
+ }
+ }
+ get executionCtx() {
+ if (this.#executionCtx) {
+ return this.#executionCtx;
+ } else {
+ throw Error("This context has no ExecutionContext");
+ }
+ }
+ get res() {
+ return this.#res ||= new Response(null, {
+ headers: this.#preparedHeaders ??= new Headers()
+ });
+ }
+ set res(_res) {
+ if (this.#res && _res) {
+ _res = new Response(_res.body, _res);
+ for (const [k, v] of this.#res.headers.entries()) {
+ if (k === "content-type") {
+ continue;
+ }
+ if (k === "set-cookie") {
+ const cookies = this.#res.headers.getSetCookie();
+ _res.headers.delete("set-cookie");
+ for (const cookie of cookies) {
+ _res.headers.append("set-cookie", cookie);
+ }
+ } else {
+ _res.headers.set(k, v);
+ }
+ }
+ }
+ this.#res = _res;
+ this.finalized = true;
+ }
+ render = (...args) => {
+ this.#renderer ??= (content) => this.html(content);
+ return this.#renderer(...args);
+ };
+ setLayout = (layout) => this.#layout = layout;
+ getLayout = () => this.#layout;
+ setRenderer = (renderer) => {
+ this.#renderer = renderer;
+ };
+ header = (name, value, options) => {
+ if (this.finalized) {
+ this.#res = new Response(this.#res.body, this.#res);
+ }
+ const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers();
+ if (value === void 0) {
+ headers.delete(name);
+ } else if (options?.append) {
+ headers.append(name, value);
+ } else {
+ headers.set(name, value);
+ }
+ };
+ status = (status) => {
+ this.#status = status;
+ };
+ set = (key, value) => {
+ this.#var ??= /* @__PURE__ */ new Map();
+ this.#var.set(key, value);
+ };
+ get = (key) => {
+ return this.#var ? this.#var.get(key) : void 0;
+ };
+ get var() {
+ if (!this.#var) {
+ return {};
+ }
+ return Object.fromEntries(this.#var);
+ }
+ #newResponse(data, arg, headers) {
+ const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers();
+ if (typeof arg === "object" && "headers" in arg) {
+ const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers);
+ for (const [key, value] of argHeaders) {
+ if (key.toLowerCase() === "set-cookie") {
+ responseHeaders.append(key, value);
+ } else {
+ responseHeaders.set(key, value);
+ }
+ }
+ }
+ if (headers) {
+ for (const [k, v] of Object.entries(headers)) {
+ if (typeof v === "string") {
+ responseHeaders.set(k, v);
+ } else {
+ responseHeaders.delete(k);
+ for (const v2 of v) {
+ responseHeaders.append(k, v2);
+ }
+ }
+ }
+ }
+ const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
+ return new Response(data, { status, headers: responseHeaders });
+ }
+ newResponse = (...args) => this.#newResponse(...args);
+ body = (data, arg, headers) => this.#newResponse(data, arg, headers);
+ text = (text, arg, headers) => {
+ return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse(
+ text,
+ arg,
+ setDefaultContentType(TEXT_PLAIN, headers)
+ );
+ };
+ json = (object, arg, headers) => {
+ return this.#newResponse(
+ JSON.stringify(object),
+ arg,
+ setDefaultContentType("application/json", headers)
+ );
+ };
+ html = (html, arg, headers) => {
+ const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers));
+ return typeof html === "object" ? (0, import_html.resolveCallback)(html, import_html.HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html);
+ };
+ redirect = (location, status) => {
+ const locationString = String(location);
+ this.header(
+ "Location",
+ !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString)
+ );
+ return this.newResponse(null, status ?? 302);
+ };
+ notFound = () => {
+ this.#notFoundHandler ??= () => new Response();
+ return this.#notFoundHandler(this);
+ };
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/router.js
+var require_router = __commonJS({
+ "node_modules/hono/dist/cjs/router.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var router_exports = {};
+ __export(router_exports, {
+ MESSAGE_MATCHER_IS_ALREADY_BUILT: () => MESSAGE_MATCHER_IS_ALREADY_BUILT,
+ METHODS: () => METHODS,
+ METHOD_NAME_ALL: () => METHOD_NAME_ALL,
+ METHOD_NAME_ALL_LOWERCASE: () => METHOD_NAME_ALL_LOWERCASE,
+ UnsupportedPathError: () => UnsupportedPathError
+ });
+ module2.exports = __toCommonJS(router_exports);
+ var METHOD_NAME_ALL = "ALL";
+ var METHOD_NAME_ALL_LOWERCASE = "all";
+ var METHODS = ["get", "post", "put", "delete", "options", "patch"];
+ var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
+ var UnsupportedPathError = class extends Error {
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/utils/constants.js
+var require_constants2 = __commonJS({
+ "node_modules/hono/dist/cjs/utils/constants.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var constants_exports = {};
+ __export(constants_exports, {
+ COMPOSED_HANDLER: () => COMPOSED_HANDLER
+ });
+ module2.exports = __toCommonJS(constants_exports);
+ var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
+ }
+});
+
+// node_modules/hono/dist/cjs/hono-base.js
+var require_hono_base = __commonJS({
+ "node_modules/hono/dist/cjs/hono-base.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var hono_base_exports = {};
+ __export(hono_base_exports, {
+ HonoBase: () => Hono2
+ });
+ module2.exports = __toCommonJS(hono_base_exports);
+ var import_compose = require_compose();
+ var import_context = require_context();
+ var import_router = require_router();
+ var import_constants = require_constants2();
+ var import_url = require_url();
+ var notFoundHandler = (c) => {
+ return c.text("404 Not Found", 404);
+ };
+ var errorHandler = (err, c) => {
+ if ("getResponse" in err) {
+ const res = err.getResponse();
+ return c.newResponse(res.body, res);
+ }
+ console.error(err);
+ return c.text("Internal Server Error", 500);
+ };
+ var Hono2 = class _Hono {
+ get;
+ post;
+ put;
+ delete;
+ options;
+ patch;
+ all;
+ on;
+ use;
+ router;
+ getPath;
+ _basePath = "/";
+ #path = "/";
+ routes = [];
+ constructor(options = {}) {
+ const allMethods = [...import_router.METHODS, import_router.METHOD_NAME_ALL_LOWERCASE];
+ allMethods.forEach((method) => {
+ this[method] = (args1, ...args) => {
+ if (typeof args1 === "string") {
+ this.#path = args1;
+ } else {
+ this.#addRoute(method, this.#path, args1);
+ }
+ args.forEach((handler) => {
+ this.#addRoute(method, this.#path, handler);
+ });
+ return this;
+ };
+ });
+ this.on = (method, path, ...handlers) => {
+ for (const p of [path].flat()) {
+ this.#path = p;
+ for (const m of [method].flat()) {
+ handlers.map((handler) => {
+ this.#addRoute(m.toUpperCase(), this.#path, handler);
+ });
+ }
+ }
+ return this;
+ };
+ this.use = (arg1, ...handlers) => {
+ if (typeof arg1 === "string") {
+ this.#path = arg1;
+ } else {
+ this.#path = "*";
+ handlers.unshift(arg1);
+ }
+ handlers.forEach((handler) => {
+ this.#addRoute(import_router.METHOD_NAME_ALL, this.#path, handler);
+ });
+ return this;
+ };
+ const { strict, ...optionsWithoutStrict } = options;
+ Object.assign(this, optionsWithoutStrict);
+ this.getPath = strict ?? true ? options.getPath ?? import_url.getPath : import_url.getPathNoStrict;
+ }
+ #clone() {
+ const clone = new _Hono({
+ router: this.router,
+ getPath: this.getPath
+ });
+ clone.errorHandler = this.errorHandler;
+ clone.#notFoundHandler = this.#notFoundHandler;
+ clone.routes = this.routes;
+ return clone;
+ }
+ #notFoundHandler = notFoundHandler;
+ errorHandler = errorHandler;
+ route(path, app) {
+ const subApp = this.basePath(path);
+ app.routes.map((r) => {
+ let handler;
+ if (app.errorHandler === errorHandler) {
+ handler = r.handler;
+ } else {
+ handler = async (c, next) => (await (0, import_compose.compose)([], app.errorHandler)(c, () => r.handler(c, next))).res;
+ handler[import_constants.COMPOSED_HANDLER] = r.handler;
+ }
+ subApp.#addRoute(r.method, r.path, handler);
+ });
+ return this;
+ }
+ basePath(path) {
+ const subApp = this.#clone();
+ subApp._basePath = (0, import_url.mergePath)(this._basePath, path);
+ return subApp;
+ }
+ onError = (handler) => {
+ this.errorHandler = handler;
+ return this;
+ };
+ notFound = (handler) => {
+ this.#notFoundHandler = handler;
+ return this;
+ };
+ mount(path, applicationHandler, options) {
+ let replaceRequest;
+ let optionHandler;
+ if (options) {
+ if (typeof options === "function") {
+ optionHandler = options;
+ } else {
+ optionHandler = options.optionHandler;
+ if (options.replaceRequest === false) {
+ replaceRequest = (request) => request;
+ } else {
+ replaceRequest = options.replaceRequest;
+ }
+ }
+ }
+ const getOptions = optionHandler ? (c) => {
+ const options2 = optionHandler(c);
+ return Array.isArray(options2) ? options2 : [options2];
+ } : (c) => {
+ let executionContext = void 0;
+ try {
+ executionContext = c.executionCtx;
+ } catch {
+ }
+ return [c.env, executionContext];
+ };
+ replaceRequest ||= (() => {
+ const mergedPath = (0, import_url.mergePath)(this._basePath, path);
+ const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
+ return (request) => {
+ const url = new URL(request.url);
+ url.pathname = url.pathname.slice(pathPrefixLength) || "/";
+ return new Request(url, request);
+ };
+ })();
+ const handler = async (c, next) => {
+ const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c));
+ if (res) {
+ return res;
+ }
+ await next();
+ };
+ this.#addRoute(import_router.METHOD_NAME_ALL, (0, import_url.mergePath)(path, "*"), handler);
+ return this;
+ }
+ #addRoute(method, path, handler) {
+ method = method.toUpperCase();
+ path = (0, import_url.mergePath)(this._basePath, path);
+ const r = { basePath: this._basePath, path, method, handler };
+ this.router.add(method, path, [handler, r]);
+ this.routes.push(r);
+ }
+ #handleError(err, c) {
+ if (err instanceof Error) {
+ return this.errorHandler(err, c);
+ }
+ throw err;
+ }
+ #dispatch(request, executionCtx, env, method) {
+ if (method === "HEAD") {
+ return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
+ }
+ const path = this.getPath(request, { env });
+ const matchResult = this.router.match(method, path);
+ const c = new import_context.Context(request, {
+ path,
+ matchResult,
+ env,
+ executionCtx,
+ notFoundHandler: this.#notFoundHandler
+ });
+ if (matchResult[0].length === 1) {
+ let res;
+ try {
+ res = matchResult[0][0][0][0](c, async () => {
+ c.res = await this.#notFoundHandler(c);
+ });
+ } catch (err) {
+ return this.#handleError(err, c);
+ }
+ return res instanceof Promise ? res.then(
+ (resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c))
+ ).catch((err) => this.#handleError(err, c)) : res ?? this.#notFoundHandler(c);
+ }
+ const composed = (0, import_compose.compose)(matchResult[0], this.errorHandler, this.#notFoundHandler);
+ return (async () => {
+ try {
+ const context = await composed(c);
+ if (!context.finalized) {
+ throw new Error(
+ "Context is not finalized. Did you forget to return a Response object or `await next()`?"
+ );
+ }
+ return context.res;
+ } catch (err) {
+ return this.#handleError(err, c);
+ }
+ })();
+ }
+ fetch = (request, ...rest) => {
+ return this.#dispatch(request, rest[1], rest[0], request.method);
+ };
+ request = (input, requestInit, Env, executionCtx) => {
+ if (input instanceof Request) {
+ return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx);
+ }
+ input = input.toString();
+ return this.fetch(
+ new Request(
+ /^https?:\/\//.test(input) ? input : `http://localhost${(0, import_url.mergePath)("/", input)}`,
+ requestInit
+ ),
+ Env,
+ executionCtx
+ );
+ };
+ fire = () => {
+ addEventListener("fetch", (event) => {
+ event.respondWith(this.#dispatch(event.request, event, void 0, event.request.method));
+ });
+ };
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/router/reg-exp-router/matcher.js
+var require_matcher = __commonJS({
+ "node_modules/hono/dist/cjs/router/reg-exp-router/matcher.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var matcher_exports = {};
+ __export(matcher_exports, {
+ emptyParam: () => emptyParam,
+ match: () => match
+ });
+ module2.exports = __toCommonJS(matcher_exports);
+ var import_router = require_router();
+ var emptyParam = [];
+ function match(method, path) {
+ const matchers = this.buildAllMatchers();
+ const match2 = (method2, path2) => {
+ const matcher = matchers[method2] || matchers[import_router.METHOD_NAME_ALL];
+ const staticMatch = matcher[2][path2];
+ if (staticMatch) {
+ return staticMatch;
+ }
+ const match3 = path2.match(matcher[0]);
+ if (!match3) {
+ return [[], emptyParam];
+ }
+ const index = match3.indexOf("", 1);
+ return [matcher[1][index], match3];
+ };
+ this.match = match2;
+ return match2(method, path);
+ }
+ }
+});
+
+// node_modules/hono/dist/cjs/router/reg-exp-router/node.js
+var require_node = __commonJS({
+ "node_modules/hono/dist/cjs/router/reg-exp-router/node.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var node_exports = {};
+ __export(node_exports, {
+ Node: () => Node,
+ PATH_ERROR: () => PATH_ERROR
+ });
+ module2.exports = __toCommonJS(node_exports);
+ var LABEL_REG_EXP_STR = "[^/]+";
+ var ONLY_WILDCARD_REG_EXP_STR = ".*";
+ var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
+ var PATH_ERROR = Symbol();
+ var regExpMetaChars = new Set(".\\+*[^]$()");
+ function compareKey(a, b) {
+ if (a.length === 1) {
+ return b.length === 1 ? a < b ? -1 : 1 : -1;
+ }
+ if (b.length === 1) {
+ return 1;
+ }
+ if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) {
+ return 1;
+ } else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) {
+ return -1;
+ }
+ if (a === LABEL_REG_EXP_STR) {
+ return 1;
+ } else if (b === LABEL_REG_EXP_STR) {
+ return -1;
+ }
+ return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
+ }
+ var Node = class _Node {
+ #index;
+ #varIndex;
+ #children = /* @__PURE__ */ Object.create(null);
+ insert(tokens, index, paramMap, context, pathErrorCheckOnly) {
+ if (tokens.length === 0) {
+ if (this.#index !== void 0) {
+ throw PATH_ERROR;
+ }
+ if (pathErrorCheckOnly) {
+ return;
+ }
+ this.#index = index;
+ return;
+ }
+ const [token, ...restTokens] = tokens;
+ const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
+ let node;
+ if (pattern) {
+ const name = pattern[1];
+ let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
+ if (name && pattern[2]) {
+ if (regexpStr === ".*") {
+ throw PATH_ERROR;
+ }
+ regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
+ if (/\((?!\?:)/.test(regexpStr)) {
+ throw PATH_ERROR;
+ }
+ }
+ node = this.#children[regexpStr];
+ if (!node) {
+ if (Object.keys(this.#children).some(
+ (k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
+ )) {
+ throw PATH_ERROR;
+ }
+ if (pathErrorCheckOnly) {
+ return;
+ }
+ node = this.#children[regexpStr] = new _Node();
+ if (name !== "") {
+ node.#varIndex = context.varIndex++;
+ }
+ }
+ if (!pathErrorCheckOnly && name !== "") {
+ paramMap.push([name, node.#varIndex]);
+ }
+ } else {
+ node = this.#children[token];
+ if (!node) {
+ if (Object.keys(this.#children).some(
+ (k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
+ )) {
+ throw PATH_ERROR;
+ }
+ if (pathErrorCheckOnly) {
+ return;
+ }
+ node = this.#children[token] = new _Node();
+ }
+ }
+ node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly);
+ }
+ buildRegExpStr() {
+ const childKeys = Object.keys(this.#children).sort(compareKey);
+ const strList = childKeys.map((k) => {
+ const c = this.#children[k];
+ return (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + c.buildRegExpStr();
+ });
+ if (typeof this.#index === "number") {
+ strList.unshift(`#${this.#index}`);
+ }
+ if (strList.length === 0) {
+ return "";
+ }
+ if (strList.length === 1) {
+ return strList[0];
+ }
+ return "(?:" + strList.join("|") + ")";
+ }
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/router/reg-exp-router/trie.js
+var require_trie = __commonJS({
+ "node_modules/hono/dist/cjs/router/reg-exp-router/trie.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var trie_exports = {};
+ __export(trie_exports, {
+ Trie: () => Trie
+ });
+ module2.exports = __toCommonJS(trie_exports);
+ var import_node = require_node();
+ var Trie = class {
+ #context = { varIndex: 0 };
+ #root = new import_node.Node();
+ insert(path, index, pathErrorCheckOnly) {
+ const paramAssoc = [];
+ const groups = [];
+ for (let i = 0; ; ) {
+ let replaced = false;
+ path = path.replace(/\{[^}]+\}/g, (m) => {
+ const mark = `@\\${i}`;
+ groups[i] = [mark, m];
+ i++;
+ replaced = true;
+ return mark;
+ });
+ if (!replaced) {
+ break;
+ }
+ }
+ const tokens = path.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
+ for (let i = groups.length - 1; i >= 0; i--) {
+ const [mark] = groups[i];
+ for (let j = tokens.length - 1; j >= 0; j--) {
+ if (tokens[j].indexOf(mark) !== -1) {
+ tokens[j] = tokens[j].replace(mark, groups[i][1]);
+ break;
+ }
+ }
+ }
+ this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly);
+ return paramAssoc;
+ }
+ buildRegExp() {
+ let regexp = this.#root.buildRegExpStr();
+ if (regexp === "") {
+ return [/^$/, [], []];
+ }
+ let captureIndex = 0;
+ const indexReplacementMap = [];
+ const paramReplacementMap = [];
+ regexp = regexp.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handlerIndex, paramIndex) => {
+ if (handlerIndex !== void 0) {
+ indexReplacementMap[++captureIndex] = Number(handlerIndex);
+ return "$()";
+ }
+ if (paramIndex !== void 0) {
+ paramReplacementMap[Number(paramIndex)] = ++captureIndex;
+ return "";
+ }
+ return "";
+ });
+ return [new RegExp(`^${regexp}`), indexReplacementMap, paramReplacementMap];
+ }
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/router/reg-exp-router/router.js
+var require_router2 = __commonJS({
+ "node_modules/hono/dist/cjs/router/reg-exp-router/router.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var router_exports = {};
+ __export(router_exports, {
+ RegExpRouter: () => RegExpRouter2
+ });
+ module2.exports = __toCommonJS(router_exports);
+ var import_router = require_router();
+ var import_url = require_url();
+ var import_matcher = require_matcher();
+ var import_node = require_node();
+ var import_trie = require_trie();
+ var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
+ var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
+ function buildWildcardRegExp(path) {
+ return wildcardRegExpCache[path] ??= new RegExp(
+ path === "*" ? "" : `^${path.replace(
+ /\/\*$|([.\\+*[^\]$()])/g,
+ (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)"
+ )}$`
+ );
+ }
+ function clearWildcardRegExpCache() {
+ wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
+ }
+ function buildMatcherFromPreprocessedRoutes(routes) {
+ const trie = new import_trie.Trie();
+ const handlerData = [];
+ if (routes.length === 0) {
+ return nullMatcher;
+ }
+ const routesWithStaticPathFlag = routes.map(
+ (route) => [!/\*|\/:/.test(route[0]), ...route]
+ ).sort(
+ ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
+ );
+ const staticMap = /* @__PURE__ */ Object.create(null);
+ for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
+ const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i];
+ if (pathErrorCheckOnly) {
+ staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), import_matcher.emptyParam];
+ } else {
+ j++;
+ }
+ let paramAssoc;
+ try {
+ paramAssoc = trie.insert(path, j, pathErrorCheckOnly);
+ } catch (e) {
+ throw e === import_node.PATH_ERROR ? new import_router.UnsupportedPathError(path) : e;
+ }
+ if (pathErrorCheckOnly) {
+ continue;
+ }
+ handlerData[j] = handlers.map(([h, paramCount]) => {
+ const paramIndexMap = /* @__PURE__ */ Object.create(null);
+ paramCount -= 1;
+ for (; paramCount >= 0; paramCount--) {
+ const [key, value] = paramAssoc[paramCount];
+ paramIndexMap[key] = value;
+ }
+ return [h, paramIndexMap];
+ });
+ }
+ const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
+ for (let i = 0, len = handlerData.length; i < len; i++) {
+ for (let j = 0, len2 = handlerData[i].length; j < len2; j++) {
+ const map = handlerData[i][j]?.[1];
+ if (!map) {
+ continue;
+ }
+ const keys = Object.keys(map);
+ for (let k = 0, len3 = keys.length; k < len3; k++) {
+ map[keys[k]] = paramReplacementMap[map[keys[k]]];
+ }
+ }
+ }
+ const handlerMap = [];
+ for (const i in indexReplacementMap) {
+ handlerMap[i] = handlerData[indexReplacementMap[i]];
+ }
+ return [regexp, handlerMap, staticMap];
+ }
+ function findMiddleware(middleware, path) {
+ if (!middleware) {
+ return void 0;
+ }
+ for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) {
+ if (buildWildcardRegExp(k).test(path)) {
+ return [...middleware[k]];
+ }
+ }
+ return void 0;
+ }
+ var RegExpRouter2 = class {
+ name = "RegExpRouter";
+ #middleware;
+ #routes;
+ constructor() {
+ this.#middleware = { [import_router.METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
+ this.#routes = { [import_router.METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
+ }
+ add(method, path, handler) {
+ const middleware = this.#middleware;
+ const routes = this.#routes;
+ if (!middleware || !routes) {
+ throw new Error(import_router.MESSAGE_MATCHER_IS_ALREADY_BUILT);
+ }
+ if (!middleware[method]) {
+ ;
+ [middleware, routes].forEach((handlerMap) => {
+ handlerMap[method] = /* @__PURE__ */ Object.create(null);
+ Object.keys(handlerMap[import_router.METHOD_NAME_ALL]).forEach((p) => {
+ handlerMap[method][p] = [...handlerMap[import_router.METHOD_NAME_ALL][p]];
+ });
+ });
+ }
+ if (path === "/*") {
+ path = "*";
+ }
+ const paramCount = (path.match(/\/:/g) || []).length;
+ if (/\*$/.test(path)) {
+ const re = buildWildcardRegExp(path);
+ if (method === import_router.METHOD_NAME_ALL) {
+ Object.keys(middleware).forEach((m) => {
+ middleware[m][path] ||= findMiddleware(middleware[m], path) || findMiddleware(middleware[import_router.METHOD_NAME_ALL], path) || [];
+ });
+ } else {
+ middleware[method][path] ||= findMiddleware(middleware[method], path) || findMiddleware(middleware[import_router.METHOD_NAME_ALL], path) || [];
+ }
+ Object.keys(middleware).forEach((m) => {
+ if (method === import_router.METHOD_NAME_ALL || method === m) {
+ Object.keys(middleware[m]).forEach((p) => {
+ re.test(p) && middleware[m][p].push([handler, paramCount]);
+ });
+ }
+ });
+ Object.keys(routes).forEach((m) => {
+ if (method === import_router.METHOD_NAME_ALL || method === m) {
+ Object.keys(routes[m]).forEach(
+ (p) => re.test(p) && routes[m][p].push([handler, paramCount])
+ );
+ }
+ });
+ return;
+ }
+ const paths = (0, import_url.checkOptionalParameter)(path) || [path];
+ for (let i = 0, len = paths.length; i < len; i++) {
+ const path2 = paths[i];
+ Object.keys(routes).forEach((m) => {
+ if (method === import_router.METHOD_NAME_ALL || method === m) {
+ routes[m][path2] ||= [
+ ...findMiddleware(middleware[m], path2) || findMiddleware(middleware[import_router.METHOD_NAME_ALL], path2) || []
+ ];
+ routes[m][path2].push([handler, paramCount - len + i + 1]);
+ }
+ });
+ }
+ }
+ match = import_matcher.match;
+ buildAllMatchers() {
+ const matchers = /* @__PURE__ */ Object.create(null);
+ Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
+ matchers[method] ||= this.#buildMatcher(method);
+ });
+ this.#middleware = this.#routes = void 0;
+ clearWildcardRegExpCache();
+ return matchers;
+ }
+ #buildMatcher(method) {
+ const routes = [];
+ let hasOwnRoute = method === import_router.METHOD_NAME_ALL;
+ [this.#middleware, this.#routes].forEach((r) => {
+ const ownRoute = r[method] ? Object.keys(r[method]).map((path) => [path, r[method][path]]) : [];
+ if (ownRoute.length !== 0) {
+ hasOwnRoute ||= true;
+ routes.push(...ownRoute);
+ } else if (method !== import_router.METHOD_NAME_ALL) {
+ routes.push(
+ ...Object.keys(r[import_router.METHOD_NAME_ALL]).map((path) => [path, r[import_router.METHOD_NAME_ALL][path]])
+ );
+ }
+ });
+ if (!hasOwnRoute) {
+ return null;
+ } else {
+ return buildMatcherFromPreprocessedRoutes(routes);
+ }
+ }
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/router/reg-exp-router/prepared-router.js
+var require_prepared_router = __commonJS({
+ "node_modules/hono/dist/cjs/router/reg-exp-router/prepared-router.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var prepared_router_exports = {};
+ __export(prepared_router_exports, {
+ PreparedRegExpRouter: () => PreparedRegExpRouter2,
+ buildInitParams: () => buildInitParams2,
+ serializeInitParams: () => serializeInitParams2
+ });
+ module2.exports = __toCommonJS(prepared_router_exports);
+ var import_router = require_router();
+ var import_matcher = require_matcher();
+ var import_router2 = require_router2();
+ var PreparedRegExpRouter2 = class {
+ name = "PreparedRegExpRouter";
+ #matchers;
+ #relocateMap;
+ constructor(matchers, relocateMap) {
+ this.#matchers = matchers;
+ this.#relocateMap = relocateMap;
+ }
+ #addWildcard(method, handlerData) {
+ const matcher = this.#matchers[method];
+ matcher[1].forEach((list) => list && list.push(handlerData));
+ Object.values(matcher[2]).forEach((list) => list[0].push(handlerData));
+ }
+ #addPath(method, path, handler, indexes, map) {
+ const matcher = this.#matchers[method];
+ if (!map) {
+ matcher[2][path][0].push([handler, {}]);
+ } else {
+ indexes.forEach((index) => {
+ if (typeof index === "number") {
+ matcher[1][index].push([handler, map]);
+ } else {
+ ;
+ matcher[2][index || path][0].push([handler, map]);
+ }
+ });
+ }
+ }
+ add(method, path, handler) {
+ if (!this.#matchers[method]) {
+ const all = this.#matchers[import_router.METHOD_NAME_ALL];
+ const staticMap = {};
+ for (const key in all[2]) {
+ staticMap[key] = [all[2][key][0].slice(), import_matcher.emptyParam];
+ }
+ this.#matchers[method] = [
+ all[0],
+ all[1].map((list) => Array.isArray(list) ? list.slice() : 0),
+ staticMap
+ ];
+ }
+ if (path === "/*" || path === "*") {
+ const handlerData = [handler, {}];
+ if (method === import_router.METHOD_NAME_ALL) {
+ for (const m in this.#matchers) {
+ this.#addWildcard(m, handlerData);
+ }
+ } else {
+ this.#addWildcard(method, handlerData);
+ }
+ return;
+ }
+ const data = this.#relocateMap[path];
+ if (!data) {
+ throw new Error(`Path ${path} is not registered`);
+ }
+ for (const [indexes, map] of data) {
+ if (method === import_router.METHOD_NAME_ALL) {
+ for (const m in this.#matchers) {
+ this.#addPath(m, path, handler, indexes, map);
+ }
+ } else {
+ this.#addPath(method, path, handler, indexes, map);
+ }
+ }
+ }
+ buildAllMatchers() {
+ return this.#matchers;
+ }
+ match = import_matcher.match;
+ };
+ var buildInitParams2 = ({ paths }) => {
+ const RegExpRouterWithMatcherExport = class extends import_router2.RegExpRouter {
+ buildAndExportAllMatchers() {
+ return this.buildAllMatchers();
+ }
+ };
+ const router = new RegExpRouterWithMatcherExport();
+ for (const path of paths) {
+ router.add(import_router.METHOD_NAME_ALL, path, path);
+ }
+ const matchers = router.buildAndExportAllMatchers();
+ const all = matchers[import_router.METHOD_NAME_ALL];
+ const relocateMap = {};
+ for (const path of paths) {
+ if (path === "/*" || path === "*") {
+ continue;
+ }
+ all[1].forEach((list, i) => {
+ list.forEach(([p, map]) => {
+ if (p === path) {
+ if (relocateMap[path]) {
+ relocateMap[path][0][1] = {
+ ...relocateMap[path][0][1],
+ ...map
+ };
+ } else {
+ relocateMap[path] = [[[], map]];
+ }
+ if (relocateMap[path][0][0].findIndex((j) => j === i) === -1) {
+ relocateMap[path][0][0].push(i);
+ }
+ }
+ });
+ });
+ for (const path2 in all[2]) {
+ all[2][path2][0].forEach(([p]) => {
+ if (p === path) {
+ relocateMap[path] ||= [[[]]];
+ const value = path2 === path ? "" : path2;
+ if (relocateMap[path][0][0].findIndex((v) => v === value) === -1) {
+ relocateMap[path][0][0].push(value);
+ }
+ }
+ });
+ }
+ }
+ for (let i = 0, len = all[1].length; i < len; i++) {
+ all[1][i] = all[1][i] ? [] : 0;
+ }
+ for (const path in all[2]) {
+ all[2][path][0] = [];
+ }
+ return [matchers, relocateMap];
+ };
+ var serializeInitParams2 = ([matchers, relocateMap]) => {
+ const matchersStr = JSON.stringify(
+ matchers,
+ (_, value) => value instanceof RegExp ? `##${value.toString()}##` : value
+ ).replace(/"##(.+?)##"/g, (_, str) => str.replace(/\\\\/g, "\\"));
+ const relocateMapStr = JSON.stringify(relocateMap);
+ return `[${matchersStr},${relocateMapStr}]`;
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/router/reg-exp-router/index.js
+var require_reg_exp_router = __commonJS({
+ "node_modules/hono/dist/cjs/router/reg-exp-router/index.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var reg_exp_router_exports = {};
+ __export(reg_exp_router_exports, {
+ PreparedRegExpRouter: () => import_prepared_router.PreparedRegExpRouter,
+ RegExpRouter: () => import_router.RegExpRouter,
+ buildInitParams: () => import_prepared_router.buildInitParams,
+ serializeInitParams: () => import_prepared_router.serializeInitParams
+ });
+ module2.exports = __toCommonJS(reg_exp_router_exports);
+ var import_router = require_router2();
+ var import_prepared_router = require_prepared_router();
+ }
+});
+
+// node_modules/hono/dist/cjs/router/smart-router/router.js
+var require_router3 = __commonJS({
+ "node_modules/hono/dist/cjs/router/smart-router/router.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var router_exports = {};
+ __export(router_exports, {
+ SmartRouter: () => SmartRouter2
+ });
+ module2.exports = __toCommonJS(router_exports);
+ var import_router = require_router();
+ var SmartRouter2 = class {
+ name = "SmartRouter";
+ #routers = [];
+ #routes = [];
+ constructor(init) {
+ this.#routers = init.routers;
+ }
+ add(method, path, handler) {
+ if (!this.#routes) {
+ throw new Error(import_router.MESSAGE_MATCHER_IS_ALREADY_BUILT);
+ }
+ this.#routes.push([method, path, handler]);
+ }
+ match(method, path) {
+ if (!this.#routes) {
+ throw new Error("Fatal error");
+ }
+ const routers = this.#routers;
+ const routes = this.#routes;
+ const len = routers.length;
+ let i = 0;
+ let res;
+ for (; i < len; i++) {
+ const router = routers[i];
+ try {
+ for (let i2 = 0, len2 = routes.length; i2 < len2; i2++) {
+ router.add(...routes[i2]);
+ }
+ res = router.match(method, path);
+ } catch (e) {
+ if (e instanceof import_router.UnsupportedPathError) {
+ continue;
+ }
+ throw e;
+ }
+ this.match = router.match.bind(router);
+ this.#routers = [router];
+ this.#routes = void 0;
+ break;
+ }
+ if (i === len) {
+ throw new Error("Fatal error");
+ }
+ this.name = `SmartRouter + ${this.activeRouter.name}`;
+ return res;
+ }
+ get activeRouter() {
+ if (this.#routes || this.#routers.length !== 1) {
+ throw new Error("No active router has been determined yet.");
+ }
+ return this.#routers[0];
+ }
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/router/smart-router/index.js
+var require_smart_router = __commonJS({
+ "node_modules/hono/dist/cjs/router/smart-router/index.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var smart_router_exports = {};
+ __export(smart_router_exports, {
+ SmartRouter: () => import_router.SmartRouter
+ });
+ module2.exports = __toCommonJS(smart_router_exports);
+ var import_router = require_router3();
+ }
+});
+
+// node_modules/hono/dist/cjs/router/trie-router/node.js
+var require_node2 = __commonJS({
+ "node_modules/hono/dist/cjs/router/trie-router/node.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var node_exports = {};
+ __export(node_exports, {
+ Node: () => Node
+ });
+ module2.exports = __toCommonJS(node_exports);
+ var import_router = require_router();
+ var import_url = require_url();
+ var emptyParams = /* @__PURE__ */ Object.create(null);
+ var Node = class _Node {
+ #methods;
+ #children;
+ #patterns;
+ #order = 0;
+ #params = emptyParams;
+ constructor(method, handler, children) {
+ this.#children = children || /* @__PURE__ */ Object.create(null);
+ this.#methods = [];
+ if (method && handler) {
+ const m = /* @__PURE__ */ Object.create(null);
+ m[method] = { handler, possibleKeys: [], score: 0 };
+ this.#methods = [m];
+ }
+ this.#patterns = [];
+ }
+ insert(method, path, handler) {
+ this.#order = ++this.#order;
+ let curNode = this;
+ const parts = (0, import_url.splitRoutingPath)(path);
+ const possibleKeys = [];
+ for (let i = 0, len = parts.length; i < len; i++) {
+ const p = parts[i];
+ const nextP = parts[i + 1];
+ const pattern = (0, import_url.getPattern)(p, nextP);
+ const key = Array.isArray(pattern) ? pattern[0] : p;
+ if (key in curNode.#children) {
+ curNode = curNode.#children[key];
+ if (pattern) {
+ possibleKeys.push(pattern[1]);
+ }
+ continue;
+ }
+ curNode.#children[key] = new _Node();
+ if (pattern) {
+ curNode.#patterns.push(pattern);
+ possibleKeys.push(pattern[1]);
+ }
+ curNode = curNode.#children[key];
+ }
+ curNode.#methods.push({
+ [method]: {
+ handler,
+ possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i),
+ score: this.#order
+ }
+ });
+ return curNode;
+ }
+ #getHandlerSets(node, method, nodeParams, params) {
+ const handlerSets = [];
+ for (let i = 0, len = node.#methods.length; i < len; i++) {
+ const m = node.#methods[i];
+ const handlerSet = m[method] || m[import_router.METHOD_NAME_ALL];
+ const processedSet = {};
+ if (handlerSet !== void 0) {
+ handlerSet.params = /* @__PURE__ */ Object.create(null);
+ handlerSets.push(handlerSet);
+ if (nodeParams !== emptyParams || params && params !== emptyParams) {
+ for (let i2 = 0, len2 = handlerSet.possibleKeys.length; i2 < len2; i2++) {
+ const key = handlerSet.possibleKeys[i2];
+ const processed = processedSet[handlerSet.score];
+ handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key];
+ processedSet[handlerSet.score] = true;
+ }
+ }
+ }
+ }
+ return handlerSets;
+ }
+ search(method, path) {
+ const handlerSets = [];
+ this.#params = emptyParams;
+ const curNode = this;
+ let curNodes = [curNode];
+ const parts = (0, import_url.splitPath)(path);
+ const curNodesQueue = [];
+ for (let i = 0, len = parts.length; i < len; i++) {
+ const part = parts[i];
+ const isLast = i === len - 1;
+ const tempNodes = [];
+ for (let j = 0, len2 = curNodes.length; j < len2; j++) {
+ const node = curNodes[j];
+ const nextNode = node.#children[part];
+ if (nextNode) {
+ nextNode.#params = node.#params;
+ if (isLast) {
+ if (nextNode.#children["*"]) {
+ handlerSets.push(
+ ...this.#getHandlerSets(nextNode.#children["*"], method, node.#params)
+ );
+ }
+ handlerSets.push(...this.#getHandlerSets(nextNode, method, node.#params));
+ } else {
+ tempNodes.push(nextNode);
+ }
+ }
+ for (let k = 0, len3 = node.#patterns.length; k < len3; k++) {
+ const pattern = node.#patterns[k];
+ const params = node.#params === emptyParams ? {} : { ...node.#params };
+ if (pattern === "*") {
+ const astNode = node.#children["*"];
+ if (astNode) {
+ handlerSets.push(...this.#getHandlerSets(astNode, method, node.#params));
+ astNode.#params = params;
+ tempNodes.push(astNode);
+ }
+ continue;
+ }
+ const [key, name, matcher] = pattern;
+ if (!part && !(matcher instanceof RegExp)) {
+ continue;
+ }
+ const child = node.#children[key];
+ const restPathString = parts.slice(i).join("/");
+ if (matcher instanceof RegExp) {
+ const m = matcher.exec(restPathString);
+ if (m) {
+ params[name] = m[0];
+ handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params));
+ if (Object.keys(child.#children).length) {
+ child.#params = params;
+ const componentCount = m[0].match(/\//)?.length ?? 0;
+ const targetCurNodes = curNodesQueue[componentCount] ||= [];
+ targetCurNodes.push(child);
+ }
+ continue;
+ }
+ }
+ if (matcher === true || matcher.test(part)) {
+ params[name] = part;
+ if (isLast) {
+ handlerSets.push(...this.#getHandlerSets(child, method, params, node.#params));
+ if (child.#children["*"]) {
+ handlerSets.push(
+ ...this.#getHandlerSets(child.#children["*"], method, params, node.#params)
+ );
+ }
+ } else {
+ child.#params = params;
+ tempNodes.push(child);
+ }
+ }
+ }
+ }
+ curNodes = tempNodes.concat(curNodesQueue.shift() ?? []);
+ }
+ if (handlerSets.length > 1) {
+ handlerSets.sort((a, b) => {
+ return a.score - b.score;
+ });
+ }
+ return [handlerSets.map(({ handler, params }) => [handler, params])];
+ }
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/router/trie-router/router.js
+var require_router4 = __commonJS({
+ "node_modules/hono/dist/cjs/router/trie-router/router.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var router_exports = {};
+ __export(router_exports, {
+ TrieRouter: () => TrieRouter2
+ });
+ module2.exports = __toCommonJS(router_exports);
+ var import_url = require_url();
+ var import_node = require_node2();
+ var TrieRouter2 = class {
+ name = "TrieRouter";
+ #node;
+ constructor() {
+ this.#node = new import_node.Node();
+ }
+ add(method, path, handler) {
+ const results = (0, import_url.checkOptionalParameter)(path);
+ if (results) {
+ for (let i = 0, len = results.length; i < len; i++) {
+ this.#node.insert(method, results[i], handler);
+ }
+ return;
+ }
+ this.#node.insert(method, path, handler);
+ }
+ match(method, path) {
+ return this.#node.search(method, path);
+ }
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/router/trie-router/index.js
+var require_trie_router = __commonJS({
+ "node_modules/hono/dist/cjs/router/trie-router/index.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var trie_router_exports = {};
+ __export(trie_router_exports, {
+ TrieRouter: () => import_router.TrieRouter
+ });
+ module2.exports = __toCommonJS(trie_router_exports);
+ var import_router = require_router4();
+ }
+});
+
+// node_modules/hono/dist/cjs/hono.js
+var require_hono = __commonJS({
+ "node_modules/hono/dist/cjs/hono.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var hono_exports = {};
+ __export(hono_exports, {
+ Hono: () => Hono2
+ });
+ module2.exports = __toCommonJS(hono_exports);
+ var import_hono_base = require_hono_base();
+ var import_reg_exp_router = require_reg_exp_router();
+ var import_smart_router = require_smart_router();
+ var import_trie_router = require_trie_router();
+ var Hono2 = class extends import_hono_base.HonoBase {
+ constructor(options = {}) {
+ super(options);
+ this.router = options.router ?? new import_smart_router.SmartRouter({
+ routers: [new import_reg_exp_router.RegExpRouter(), new import_trie_router.TrieRouter()]
+ });
+ }
+ };
+ }
+});
+
+// node_modules/hono/dist/cjs/index.js
+var require_cjs = __commonJS({
+ "node_modules/hono/dist/cjs/index.js"(exports2, module2) {
+ "use strict";
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var src_exports = {};
+ __export(src_exports, {
+ Hono: () => import_hono.Hono
+ });
+ module2.exports = __toCommonJS(src_exports);
+ var import_hono = require_hono();
+ }
+});
+
+// node_modules/@hono/node-server/dist/index.js
+var require_dist = __commonJS({
+ "node_modules/@hono/node-server/dist/index.js"(exports2, module2) {
+ "use strict";
+ var __create2 = Object.create;
+ var __defProp2 = Object.defineProperty;
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
+ var __getProtoOf2 = Object.getPrototypeOf;
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp2(target, name, { get: all[name], enumerable: true });
+ };
+ var __copyProps2 = (to, from, except, desc) => {
+ if (from && typeof from === "object" || typeof from === "function") {
+ for (let key of __getOwnPropNames2(from))
+ if (!__hasOwnProp2.call(to, key) && key !== except)
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
+ }
+ return to;
+ };
+ var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps2(
+ // If the importer is in node compatibility mode or this is not an ESM
+ // file that has been converted to a CommonJS file using a Babel-
+ // compatible transform (i.e. "__esModule" has not been set), then set
+ // "default" to the CommonJS "module.exports" for node compatibility.
+ isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
+ mod
+ ));
+ var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
+ var src_exports = {};
+ __export(src_exports, {
+ RequestError: () => RequestError,
+ createAdaptorServer: () => createAdaptorServer,
+ getRequestListener: () => getRequestListener,
+ serve: () => serve
+ });
+ module2.exports = __toCommonJS(src_exports);
+ var import_node_http = require("http");
+ var import_node_http22 = require("http2");
+ var import_node_http2 = require("http2");
+ var import_node_stream = require("stream");
+ var RequestError = class extends Error {
+ constructor(message, options) {
+ super(message, options);
+ this.name = "RequestError";
+ }
+ };
+ var toRequestError = (e) => {
+ if (e instanceof RequestError) {
+ return e;
+ }
+ return new RequestError(e.message, { cause: e });
+ };
+ var GlobalRequest = global.Request;
+ var Request2 = class extends GlobalRequest {
+ constructor(input, options) {
+ if (typeof input === "object" && getRequestCache in input) {
+ input = input[getRequestCache]();
+ }
+ if (typeof options?.body?.getReader !== "undefined") {
+ ;
+ options.duplex ??= "half";
+ }
+ super(input, options);
+ }
+ };
+ var newHeadersFromIncoming = (incoming) => {
+ const headerRecord = [];
+ const rawHeaders = incoming.rawHeaders;
+ for (let i = 0; i < rawHeaders.length; i += 2) {
+ const { [i]: key, [i + 1]: value } = rawHeaders;
+ if (key.charCodeAt(0) !== /*:*/
+ 58) {
+ headerRecord.push([key, value]);
+ }
+ }
+ return new Headers(headerRecord);
+ };
+ var wrapBodyStream = Symbol("wrapBodyStream");
+ var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
+ const init = {
+ method,
+ headers,
+ signal: abortController.signal
+ };
+ if (method === "TRACE") {
+ init.method = "GET";
+ const req = new Request2(url, init);
+ Object.defineProperty(req, "method", {
+ get() {
+ return "TRACE";
+ }
+ });
+ return req;
+ }
+ if (!(method === "GET" || method === "HEAD")) {
+ if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
+ init.body = new ReadableStream({
+ start(controller) {
+ controller.enqueue(incoming.rawBody);
+ controller.close();
+ }
+ });
+ } else if (incoming[wrapBodyStream]) {
+ let reader;
+ init.body = new ReadableStream({
+ async pull(controller) {
+ try {
+ reader ||= import_node_stream.Readable.toWeb(incoming).getReader();
+ const { done, value } = await reader.read();
+ if (done) {
+ controller.close();
+ } else {
+ controller.enqueue(value);
+ }
+ } catch (error) {
+ controller.error(error);
+ }
+ }
+ });
+ } else {
+ init.body = import_node_stream.Readable.toWeb(incoming);
+ }
+ }
+ return new Request2(url, init);
+ };
+ var getRequestCache = Symbol("getRequestCache");
+ var requestCache = Symbol("requestCache");
+ var incomingKey = Symbol("incomingKey");
+ var urlKey = Symbol("urlKey");
+ var headersKey = Symbol("headersKey");
+ var abortControllerKey = Symbol("abortControllerKey");
+ var getAbortController = Symbol("getAbortController");
+ var requestPrototype = {
+ get method() {
+ return this[incomingKey].method || "GET";
+ },
+ get url() {
+ return this[urlKey];
+ },
+ get headers() {
+ return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
+ },
+ [getAbortController]() {
+ this[getRequestCache]();
+ return this[abortControllerKey];
+ },
+ [getRequestCache]() {
+ this[abortControllerKey] ||= new AbortController();
+ return this[requestCache] ||= newRequestFromIncoming(
+ this.method,
+ this[urlKey],
+ this.headers,
+ this[incomingKey],
+ this[abortControllerKey]
+ );
+ }
+ };
+ [
+ "body",
+ "bodyUsed",
+ "cache",
+ "credentials",
+ "destination",
+ "integrity",
+ "mode",
+ "redirect",
+ "referrer",
+ "referrerPolicy",
+ "signal",
+ "keepalive"
+ ].forEach((k) => {
+ Object.defineProperty(requestPrototype, k, {
+ get() {
+ return this[getRequestCache]()[k];
+ }
+ });
+ });
+ ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
+ Object.defineProperty(requestPrototype, k, {
+ value: function() {
+ return this[getRequestCache]()[k]();
+ }
+ });
+ });
+ Object.setPrototypeOf(requestPrototype, Request2.prototype);
+ var newRequest = (incoming, defaultHostname) => {
+ const req = Object.create(requestPrototype);
+ req[incomingKey] = incoming;
+ const incomingUrl = incoming.url || "";
+ if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
+ (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
+ if (incoming instanceof import_node_http2.Http2ServerRequest) {
+ throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
+ }
+ try {
+ const url2 = new URL(incomingUrl);
+ req[urlKey] = url2.href;
+ } catch (e) {
+ throw new RequestError("Invalid absolute URL", { cause: e });
+ }
+ return req;
+ }
+ const host = (incoming instanceof import_node_http2.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
+ if (!host) {
+ throw new RequestError("Missing host header");
+ }
+ let scheme;
+ if (incoming instanceof import_node_http2.Http2ServerRequest) {
+ scheme = incoming.scheme;
+ if (!(scheme === "http" || scheme === "https")) {
+ throw new RequestError("Unsupported scheme");
+ }
+ } else {
+ scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
+ }
+ const url = new URL(`${scheme}://${host}${incomingUrl}`);
+ if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
+ throw new RequestError("Invalid host header");
+ }
+ req[urlKey] = url.href;
+ return req;
+ };
+ var responseCache = Symbol("responseCache");
+ var getResponseCache = Symbol("getResponseCache");
+ var cacheKey = Symbol("cache");
+ var GlobalResponse = global.Response;
+ var Response2 = class _Response {
+ #body;
+ #init;
+ [getResponseCache]() {
+ delete this[cacheKey];
+ return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
+ }
+ constructor(body, init) {
+ let headers;
+ this.#body = body;
+ if (init instanceof _Response) {
+ const cachedGlobalResponse = init[responseCache];
+ if (cachedGlobalResponse) {
+ this.#init = cachedGlobalResponse;
+ this[getResponseCache]();
+ return;
+ } else {
+ this.#init = init.#init;
+ headers = new Headers(init.#init.headers);
+ }
+ } else {
+ this.#init = init;
+ }
+ if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
+ headers ||= init?.headers || { "content-type": "text/plain; charset=UTF-8" };
+ this[cacheKey] = [init?.status || 200, body, headers];
+ }
+ }
+ get headers() {
+ const cache = this[cacheKey];
+ if (cache) {
+ if (!(cache[2] instanceof Headers)) {
+ cache[2] = new Headers(cache[2]);
+ }
+ return cache[2];
+ }
+ return this[getResponseCache]().headers;
+ }
+ get status() {
+ return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
+ }
+ get ok() {
+ const status = this.status;
+ return status >= 200 && status < 300;
+ }
+ };
+ ["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
+ Object.defineProperty(Response2.prototype, k, {
+ get() {
+ return this[getResponseCache]()[k];
+ }
+ });
+ });
+ ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
+ Object.defineProperty(Response2.prototype, k, {
+ value: function() {
+ return this[getResponseCache]()[k]();
+ }
+ });
+ });
+ Object.setPrototypeOf(Response2, GlobalResponse);
+ Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
+ async function readWithoutBlocking(readPromise) {
+ return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
+ }
+ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
+ const cancel = (error) => {
+ reader.cancel(error).catch(() => {
+ });
+ };
+ writable.on("close", cancel);
+ writable.on("error", cancel);
+ (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
+ return reader.closed.finally(() => {
+ writable.off("close", cancel);
+ writable.off("error", cancel);
+ });
+ function handleStreamError(error) {
+ if (error) {
+ writable.destroy(error);
+ }
+ }
+ function onDrain() {
+ reader.read().then(flow, handleStreamError);
+ }
+ function flow({ done, value }) {
+ try {
+ if (done) {
+ writable.end();
+ } else if (!writable.write(value)) {
+ writable.once("drain", onDrain);
+ } else {
+ return reader.read().then(flow, handleStreamError);
+ }
+ } catch (e) {
+ handleStreamError(e);
+ }
+ }
+ }
+ function writeFromReadableStream(stream, writable) {
+ if (stream.locked) {
+ throw new TypeError("ReadableStream is locked.");
+ } else if (writable.destroyed) {
+ return;
+ }
+ return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
+ }
+ var buildOutgoingHttpHeaders = (headers) => {
+ const res = {};
+ if (!(headers instanceof Headers)) {
+ headers = new Headers(headers ?? void 0);
+ }
+ const cookies = [];
+ for (const [k, v] of headers) {
+ if (k === "set-cookie") {
+ cookies.push(v);
+ } else {
+ res[k] = v;
+ }
+ }
+ if (cookies.length > 0) {
+ res["set-cookie"] = cookies;
+ }
+ res["content-type"] ??= "text/plain; charset=UTF-8";
+ return res;
+ };
+ var X_ALREADY_SENT = "x-hono-already-sent";
+ var import_node_crypto = __toESM2(require("crypto"));
+ var webFetch = global.fetch;
+ if (typeof global.crypto === "undefined") {
+ global.crypto = import_node_crypto.default;
+ }
+ global.fetch = (info, init) => {
+ init = {
+ // Disable compression handling so people can return the result of a fetch
+ // directly in the loader without messing with the Content-Encoding header.
+ compress: false,
+ ...init
+ };
+ return webFetch(info, init);
+ };
+ var outgoingEnded = Symbol("outgoingEnded");
+ var handleRequestError = () => new Response(null, {
+ status: 400
+ });
+ var handleFetchError = (e) => new Response(null, {
+ status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
+ });
+ var handleResponseError = (e, outgoing) => {
+ const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
+ if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
+ console.info("The user aborted a request.");
+ } else {
+ console.error(e);
+ if (!outgoing.headersSent) {
+ outgoing.writeHead(500, { "Content-Type": "text/plain" });
+ }
+ outgoing.end(`Error: ${err.message}`);
+ outgoing.destroy(err);
+ }
+ };
+ var flushHeaders = (outgoing) => {
+ if ("flushHeaders" in outgoing && outgoing.writable) {
+ outgoing.flushHeaders();
+ }
+ };
+ var responseViaCache = async (res, outgoing) => {
+ let [status, body, header] = res[cacheKey];
+ if (header instanceof Headers) {
+ header = buildOutgoingHttpHeaders(header);
+ }
+ if (typeof body === "string") {
+ header["Content-Length"] = Buffer.byteLength(body);
+ } else if (body instanceof Uint8Array) {
+ header["Content-Length"] = body.byteLength;
+ } else if (body instanceof Blob) {
+ header["Content-Length"] = body.size;
+ }
+ outgoing.writeHead(status, header);
+ if (typeof body === "string" || body instanceof Uint8Array) {
+ outgoing.end(body);
+ } else if (body instanceof Blob) {
+ outgoing.end(new Uint8Array(await body.arrayBuffer()));
+ } else {
+ flushHeaders(outgoing);
+ await writeFromReadableStream(body, outgoing)?.catch(
+ (e) => handleResponseError(e, outgoing)
+ );
+ }
+ ;
+ outgoing[outgoingEnded]?.();
+ };
+ var isPromise = (res) => typeof res.then === "function";
+ var responseViaResponseObject = async (res, outgoing, options = {}) => {
+ if (isPromise(res)) {
+ if (options.errorHandler) {
+ try {
+ res = await res;
+ } catch (err) {
+ const errRes = await options.errorHandler(err);
+ if (!errRes) {
+ return;
+ }
+ res = errRes;
+ }
+ } else {
+ res = await res.catch(handleFetchError);
+ }
+ }
+ if (cacheKey in res) {
+ return responseViaCache(res, outgoing);
+ }
+ const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
+ if (res.body) {
+ const reader = res.body.getReader();
+ const values = [];
+ let done = false;
+ let currentReadPromise = void 0;
+ if (resHeaderRecord["transfer-encoding"] !== "chunked") {
+ let maxReadCount = 2;
+ for (let i = 0; i < maxReadCount; i++) {
+ currentReadPromise ||= reader.read();
+ const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
+ console.error(e);
+ done = true;
+ });
+ if (!chunk) {
+ if (i === 1) {
+ await new Promise((resolve) => setTimeout(resolve));
+ maxReadCount = 3;
+ continue;
+ }
+ break;
+ }
+ currentReadPromise = void 0;
+ if (chunk.value) {
+ values.push(chunk.value);
+ }
+ if (chunk.done) {
+ done = true;
+ break;
+ }
+ }
+ if (done && !("content-length" in resHeaderRecord)) {
+ resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
+ }
+ }
+ outgoing.writeHead(res.status, resHeaderRecord);
+ values.forEach((value) => {
+ ;
+ outgoing.write(value);
+ });
+ if (done) {
+ outgoing.end();
+ } else {
+ if (values.length === 0) {
+ flushHeaders(outgoing);
+ }
+ await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
+ }
+ } else if (resHeaderRecord[X_ALREADY_SENT]) {
+ } else {
+ outgoing.writeHead(res.status, resHeaderRecord);
+ outgoing.end();
+ }
+ ;
+ outgoing[outgoingEnded]?.();
+ };
+ var getRequestListener = (fetchCallback, options = {}) => {
+ const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
+ if (options.overrideGlobalObjects !== false && global.Request !== Request2) {
+ Object.defineProperty(global, "Request", {
+ value: Request2
+ });
+ Object.defineProperty(global, "Response", {
+ value: Response2
+ });
+ }
+ return async (incoming, outgoing) => {
+ let res, req;
+ try {
+ req = newRequest(incoming, options.hostname);
+ let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
+ if (!incomingEnded) {
+ ;
+ incoming[wrapBodyStream] = true;
+ incoming.on("end", () => {
+ incomingEnded = true;
+ });
+ if (incoming instanceof import_node_http22.Http2ServerRequest) {
+ ;
+ outgoing[outgoingEnded] = () => {
+ if (!incomingEnded) {
+ setTimeout(() => {
+ if (!incomingEnded) {
+ setTimeout(() => {
+ incoming.destroy();
+ outgoing.destroy();
+ });
+ }
+ });
+ }
+ };
+ }
+ }
+ outgoing.on("close", () => {
+ const abortController = req[abortControllerKey];
+ if (abortController) {
+ if (incoming.errored) {
+ req[abortControllerKey].abort(incoming.errored.toString());
+ } else if (!outgoing.writableFinished) {
+ req[abortControllerKey].abort("Client connection prematurely closed.");
+ }
+ }
+ if (!incomingEnded) {
+ setTimeout(() => {
+ if (!incomingEnded) {
+ setTimeout(() => {
+ incoming.destroy();
+ });
+ }
+ });
+ }
+ });
+ res = fetchCallback(req, { incoming, outgoing });
+ if (cacheKey in res) {
+ return responseViaCache(res, outgoing);
+ }
+ } catch (e) {
+ if (!res) {
+ if (options.errorHandler) {
+ res = await options.errorHandler(req ? e : toRequestError(e));
+ if (!res) {
+ return;
+ }
+ } else if (!req) {
+ res = handleRequestError();
+ } else {
+ res = handleFetchError(e);
+ }
+ } else {
+ return handleResponseError(e, outgoing);
+ }
+ }
+ try {
+ return await responseViaResponseObject(res, outgoing, options);
+ } catch (e) {
+ return handleResponseError(e, outgoing);
+ }
+ };
+ };
+ var createAdaptorServer = (options) => {
+ const fetchCallback = options.fetch;
+ const requestListener = getRequestListener(fetchCallback, {
+ hostname: options.hostname,
+ overrideGlobalObjects: options.overrideGlobalObjects,
+ autoCleanupIncoming: options.autoCleanupIncoming
+ });
+ const createServer = options.createServer || import_node_http.createServer;
+ const server = createServer(options.serverOptions || {}, requestListener);
+ return server;
+ };
+ var serve = (options, listeningListener) => {
+ const server = createAdaptorServer(options);
+ server.listen(options?.port ?? 3e3, options.hostname, () => {
+ const serverInfo = server.address();
+ listeningListener && listeningListener(serverInfo);
+ });
+ return server;
+ };
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/hono/proxy.js
+var require_proxy = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/hono/proxy.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+ } : function(o, v) {
+ o["default"] = v;
+ });
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
+ var ownKeys = function(o) {
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
+ var ar = [];
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
+ return ar;
+ };
+ return ownKeys(o);
+ };
+ return function(mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) {
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
+ }
+ __setModuleDefault(result, mod);
+ return result;
+ };
+ }();
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ exports2.HonoProxy = void 0;
+ var pengueno_1 = require_dist2();
+ var AppLifetimeMetric = pengueno_1.Metric.fromName("HonoAppLifetime").asResult();
+ var AppRequestMetric = pengueno_1.Metric.fromName("HonoAppRequest");
+ var HonoProxy = class {
+ server;
+ app;
+ constructor(server) {
+ this.server = server;
+ }
+ async initializeApp() {
+ if (this.app)
+ return this.app;
+ const { Hono: Hono2 } = await Promise.resolve().then(() => __importStar(require_cjs()));
+ this.app = pengueno_1.LogMetricTraceable.of(new Hono2()).flatMap(pengueno_1.TraceUtil.withTrace(`AppId = ${crypto.randomUUID()}`)).flatMap(pengueno_1.TraceUtil.withMetricTrace(AppLifetimeMetric));
+ return this.app;
+ }
+ async serve(port, hostname) {
+ const { serve } = await Promise.resolve().then(() => __importStar(require_dist()));
+ const app = await this.initializeApp();
+ return app.map((tApp) => pengueno_1.Either.fromFailable(() => {
+ const app2 = tApp.get();
+ app2.all("*", async (c) => tApp.flatMap(pengueno_1.TraceUtil.withMetricTrace(AppRequestMetric)).move(c.req).flatMap((tRequest) => pengueno_1.PenguenoRequest.from(tRequest)).map((req) => this.server.serve(req)).map(pengueno_1.TraceUtil.promiseify((tResponse) => {
+ tResponse.trace.trace(AppRequestMetric.count.withValue(1));
+ return new Response(tResponse.get().body(), tResponse.get());
+ })).get());
+ return serve({
+ fetch: (_r) => app2.fetch(_r),
+ port,
+ hostname
+ });
+ })).peek(pengueno_1.TraceUtil.traceResultingEither()).peek((tServe) => tServe.get().mapRight(() => tServe.trace.trace(`haii im still listening at http://${hostname}:${port} ~uwu dont think i forgot`))).map((tEitherServer) => tEitherServer.get().mapRight((server) => tEitherServer.move(server)).flatMapAsync((tServer) => pengueno_1.Signals.awaitClose(tServer))).peek(pengueno_1.TraceUtil.promiseify(pengueno_1.TraceUtil.traceResultingEither(AppLifetimeMetric))).get();
+ }
+ };
+ exports2.HonoProxy = HonoProxy;
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/hono/index.js
+var require_hono2 = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/hono/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_proxy(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/server/index.js
+var require_server = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/server/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_http(), exports2);
+ __exportStar(require_response(), exports2);
+ __exportStar(require_request(), exports2);
+ __exportStar(require_activity(), exports2);
+ __exportStar(require_filter(), exports2);
+ __exportStar(require_hono2(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/pengueno/dist/index.js
+var require_dist2 = __commonJS({
+ "node_modules/@emprespresso/pengueno/dist/index.js"(exports2) {
+ "use strict";
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() {
+ return m[k];
+ } };
+ }
+ Object.defineProperty(o, k2, desc);
+ } : function(o, m, k, k2) {
+ if (k2 === void 0) k2 = k;
+ o[k2] = m[k];
+ });
+ var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
+ };
+ Object.defineProperty(exports2, "__esModule", { value: true });
+ __exportStar(require_leftpadesque(), exports2);
+ __exportStar(require_types(), exports2);
+ __exportStar(require_trace4(), exports2);
+ __exportStar(require_process(), exports2);
+ __exportStar(require_server(), exports2);
+ }
+});
+
+// node_modules/@emprespresso/ci_model/dist/job/index.js
+var import_pengueno = __toESM(require_dist2(), 1);
+var JobTypes = [
+ "fetch_code",
+ "ci_pipeline",
+ "build_docker_image.js",
+ "ansible_playbook.js",
+ "checkout_ci.js",
+ "npm_publish.js",
+ "coolify_webhook.js"
+];
+var isJobType = (j) => typeof j === "string" && JobTypes.includes(j);
+var isJob = (j) => !!((0, import_pengueno.isObject)(j) && "arguments" in j && (0, import_pengueno.isObject)(j.arguments) && "type" in j && isJobType(j.type) && j);
+
+// node_modules/@emprespresso/ci_model/dist/pipeline/index.js
+var import_pengueno3 = __toESM(require_dist2(), 1);
+
+// node_modules/@emprespresso/ci_model/dist/pipeline/builder.js
+var BasePipelineBuilder = class {
+ stages = [];
+ addStage(stage) {
+ this.stages.push(stage);
+ return this;
+ }
+ build() {
+ return new PipelineImpl(this.stages);
+ }
+};
+var DefaultGitHookPipelineBuilder = class extends BasePipelineBuilder {
+ remoteUrl;
+ refname;
+ constructor(remoteUrl = process.env.remote, rev = process.env.rev, refname = process.env.refname) {
+ super();
+ this.remoteUrl = remoteUrl;
+ this.refname = refname;
+ this.addStage({
+ parallelJobs: [
+ {
+ type: "fetch_code",
+ arguments: {
+ remoteUrl,
+ checkout: rev,
+ path: this.getSourceDestination()
+ }
+ }
+ ]
+ });
+ }
+ getSourceDestination() {
+ return this.remoteUrl.replace(".git", "").split("/").at(-1) ?? "src";
+ }
+ getBranch() {
+ const branchRefPrefix = "refs/heads/";
+ return this.refname.split(branchRefPrefix).at(1);
+ }
+};
+
+// node_modules/@emprespresso/ci_model/dist/pipeline/impl.js
+var import_pengueno2 = __toESM(require_dist2(), 1);
+var PipelineImpl = class _PipelineImpl {
+ serialJobs;
+ constructor(serialJobs) {
+ this.serialJobs = serialJobs;
+ }
+ serialize() {
+ return JSON.stringify({ serialJobs: this.serialJobs });
+ }
+ static from(s) {
+ return import_pengueno2.Either.fromFailable(() => JSON.parse(s)).flatMap((eitherPipelineJson) => isPipeline(eitherPipelineJson) ? import_pengueno2.Either.right(eitherPipelineJson) : import_pengueno2.Either.left(new Error("oh noes D: its a bad pipewine :(("))).mapRight((pipeline) => new _PipelineImpl(pipeline.serialJobs));
+ }
+};
+
+// node_modules/@emprespresso/ci_model/dist/pipeline/index.js
+var isPipelineStage = (t) => (0, import_pengueno3.isObject)(t) && "parallelJobs" in t && Array.isArray(t.parallelJobs) && t.parallelJobs.every((j) => isJob(j));
+var isPipeline = (t) => (0, import_pengueno3.isObject)(t) && "serialJobs" in t && Array.isArray(t.serialJobs) && t.serialJobs.every((p) => isPipelineStage(p));
+
+// dist/ci.js
+var REGISTRY = "img.liz.coffee";
+var NAMESPACE = "emprespresso";
+var IMG = "adelie";
+var getPipeline = () => {
+ const gitHookPipeline = new DefaultGitHookPipelineBuilder();
+ const branch = gitHookPipeline.getBranch();
+ if (!branch)
+ return gitHookPipeline.build();
+ const commonBuildArgs = {
+ context: gitHookPipeline.getSourceDestination(),
+ registry: REGISTRY,
+ namespace: NAMESPACE,
+ imageTag: branch
+ };
+ const adeliePackageBuild = {
+ type: "build_docker_image.js",
+ arguments: {
+ ...commonBuildArgs,
+ repository: IMG,
+ buildTarget: IMG,
+ dockerfile: "Dockerfile"
+ }
+ };
+ gitHookPipeline.addStage({
+ parallelJobs: [adeliePackageBuild]
+ });
+ const webhookUrl = getReleaseDeployment(branch);
+ if (webhookUrl === null) {
+ return gitHookPipeline.build();
+ }
+ const release = {
+ type: "coolify_webhook.js",
+ arguments: {
+ webhookUrl
+ }
+ };
+ gitHookPipeline.addStage({ parallelJobs: [release] });
+ return gitHookPipeline.build();
+};
+var getReleaseDeployment = (branch) => {
+ switch (branch) {
+ case "release":
+ return "https://plane.liz.coffee/api/v1/deploy?uuid=mkgcsgw800cwkog004sco44w&force=false";
+ case "main":
+ return "https://plane.liz.coffee/api/v1/deploy?uuid=l8wksc08gcossck408gscgo8&force=false";
+ default:
+ return null;
+ }
+};
+var main = () => {
+ const data = getPipeline().serialize();
+ process.stdout.write(data);
+};
+main();
diff --git a/.ci/ci.json b/.ci/ci.json
new file mode 100644
index 0000000..6a51028
--- /dev/null
+++ b/.ci/ci.json
@@ -0,0 +1,3 @@
+{
+ "workflow": ".ci/ci.cjs"
+}
diff --git a/.ci/ci.ts b/.ci/ci.ts
new file mode 100644
index 0000000..a08a283
--- /dev/null
+++ b/.ci/ci.ts
@@ -0,0 +1,76 @@
+#!/usr/bin/env node
+
+import {
+ AnsiblePlaybookJob,
+ BuildDockerImageJob,
+ DefaultGitHookPipelineBuilder,
+ NpmPublishJob,
+ FetchCodeJob,
+ CoolifyWebhookJob,
+ Job,
+} from "@emprespresso/ci_model";
+import { join } from "path";
+
+const REGISTRY = "img.liz.coffee";
+const NAMESPACE = "emprespresso";
+const IMG = "adelie";
+const REMOTE = "https://code.liz.coffee";
+
+const getPipeline = () => {
+ const gitHookPipeline = new DefaultGitHookPipelineBuilder();
+ const branch = gitHookPipeline.getBranch();
+ if (!branch) return gitHookPipeline.build();
+
+ const commonBuildArgs = {
+ context: gitHookPipeline.getSourceDestination(),
+ registry: REGISTRY,
+ namespace: NAMESPACE,
+ imageTag: branch,
+ };
+
+ const adeliePackageBuild: BuildDockerImageJob = {
+ type: "build_docker_image.js",
+ arguments: {
+ ...commonBuildArgs,
+ repository: IMG,
+ buildTarget: IMG,
+ dockerfile: "Dockerfile",
+ },
+ };
+ gitHookPipeline.addStage({
+ parallelJobs: [adeliePackageBuild],
+ });
+
+ const webhookUrl = getReleaseDeployment(branch);
+ if (webhookUrl === null) {
+ return gitHookPipeline.build();
+ }
+
+ const release: CoolifyWebhookJob = {
+ type: "coolify_webhook.js",
+ arguments: {
+ webhookUrl: webhookUrl!!,
+ },
+ };
+ gitHookPipeline.addStage({ parallelJobs: [release] });
+
+ return gitHookPipeline.build();
+};
+
+const getReleaseDeployment = (branch: string) => {
+ switch (branch) {
+ case "release":
+ return "https://plane.liz.coffee/api/v1/deploy?uuid=p8g8gg4g88wow48488sgko8g&force=false";
+ case "main":
+ return "https://plane.liz.coffee/api/v1/deploy?uuid=l8wksc08gcossck408gscgo8&force=false";
+ default:
+ return null;
+ }
+};
+
+const main = () => {
+ const data = getPipeline().serialize();
+ process.stdout.write(data);
+};
+
+main();
diff --git a/.ci/package-lock.json b/.ci/package-lock.json
new file mode 100644
index 0000000..b400133
--- /dev/null
+++ b/.ci/package-lock.json
@@ -0,0 +1,544 @@
+{
+ "name": ".ci",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "@emprespresso/ci_model": "^0.3.0"
+ },
+ "devDependencies": {
+ "@types/node": "^24.10.1",
+ "esbuild": "0.25.5"
+ }
+ },
+ "node_modules/@emprespresso/ci_model": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@emprespresso/ci_model/-/ci_model-0.3.0.tgz",
+ "integrity": "sha512-Ik7hYZXqsTr+VH70F+ms8HGHb0QeSOpojiFYgQoyW4iXvEdih5jsAH5npWOqxOHviynRu8PIeqJ3z5HizvO1JQ==",
+ "dependencies": {
+ "@emprespresso/pengueno": "^0.0.17"
+ }
+ },
+ "node_modules/@emprespresso/pengueno": {
+ "version": "0.0.17",
+ "resolved": "https://registry.npmjs.org/@emprespresso/pengueno/-/pengueno-0.0.17.tgz",
+ "integrity": "sha512-pyfXLYGoLlQlMQAyYptRLLiRrnQmCju4I1/sv1KtsJv06oPvNqzHqUzJJGHrXg/90krg7GRcxLKQ0TnQ2Bskjw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=22.16.0",
+ "npm": ">=10.0.0"
+ },
+ "optionalDependencies": {
+ "@hono/node-server": "^1.18.2",
+ "hono": "^4.8.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
+ "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
+ "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
+ "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
+ "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
+ "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
+ "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
+ "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
+ "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
+ "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
+ "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
+ "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
+ "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
+ "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
+ "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
+ "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
+ "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
+ "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
+ "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
+ "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
+ "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
+ "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
+ "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@hono/node-server": {
+ "version": "1.19.7",
+ "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.7.tgz",
+ "integrity": "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=18.14.1"
+ },
+ "peerDependencies": {
+ "hono": "^4"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "24.10.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.3.tgz",
+ "integrity": "sha512-gqkrWUsS8hcm0r44yn7/xZeV1ERva/nLgrLxFRUGb7aoNMIJfZJ3AC261zDQuOAKC7MiXai1WCpYc48jAHoShQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.16.0"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
+ "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.5",
+ "@esbuild/android-arm": "0.25.5",
+ "@esbuild/android-arm64": "0.25.5",
+ "@esbuild/android-x64": "0.25.5",
+ "@esbuild/darwin-arm64": "0.25.5",
+ "@esbuild/darwin-x64": "0.25.5",
+ "@esbuild/freebsd-arm64": "0.25.5",
+ "@esbuild/freebsd-x64": "0.25.5",
+ "@esbuild/linux-arm": "0.25.5",
+ "@esbuild/linux-arm64": "0.25.5",
+ "@esbuild/linux-ia32": "0.25.5",
+ "@esbuild/linux-loong64": "0.25.5",
+ "@esbuild/linux-mips64el": "0.25.5",
+ "@esbuild/linux-ppc64": "0.25.5",
+ "@esbuild/linux-riscv64": "0.25.5",
+ "@esbuild/linux-s390x": "0.25.5",
+ "@esbuild/linux-x64": "0.25.5",
+ "@esbuild/netbsd-arm64": "0.25.5",
+ "@esbuild/netbsd-x64": "0.25.5",
+ "@esbuild/openbsd-arm64": "0.25.5",
+ "@esbuild/openbsd-x64": "0.25.5",
+ "@esbuild/sunos-x64": "0.25.5",
+ "@esbuild/win32-arm64": "0.25.5",
+ "@esbuild/win32-ia32": "0.25.5",
+ "@esbuild/win32-x64": "0.25.5"
+ }
+ },
+ "node_modules/hono": {
+ "version": "4.10.8",
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.10.8.tgz",
+ "integrity": "sha512-DDT0A0r6wzhe8zCGoYOmMeuGu3dyTAE40HHjwUsWFTEy5WxK1x2WDSsBPlEXgPbRIFY6miDualuUDbasPogIww==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=16.9.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "dev": true,
+ "license": "MIT"
+ }
+ }
+}
diff --git a/.ci/package.json b/.ci/package.json
new file mode 100644
index 0000000..e8b3c72
--- /dev/null
+++ b/.ci/package.json
@@ -0,0 +1,17 @@
+{
+ "scripts": {
+ "build": "tsc && esbuild --format=cjs --target=node22 --platform=node --bundle --outfile=ci.cjs dist/ci.js && chmod +x ci.cjs",
+ "clean": "rm -rf dist ci.cjs"
+ },
+ "dependencies": {
+ "@emprespresso/ci_model": "^0.3.0"
+ },
+ "devDependencies": {
+ "@types/node": "^24.10.1",
+ "esbuild": "0.25.5"
+ },
+ "files": [
+ "dist/**/*",
+ "package.json"
+ ]
+}
diff --git a/.ci/tsconfig.json b/.ci/tsconfig.json
new file mode 100644
index 0000000..7cfeadc
--- /dev/null
+++ b/.ci/tsconfig.json
@@ -0,0 +1,28 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "lib": ["ES2022"],
+ "moduleResolution": "node",
+ "outDir": "./dist",
+ "rootDir": "./",
+ "composite": true,
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "noEmit": false,
+ "strict": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noUncheckedIndexedAccess": true,
+ "exactOptionalPropertyTypes": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["**/*.ts"],
+ "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
+}
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..fa7cf1c
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,8 @@
+node_modules
+dist
+*.log
+.git
+.gitignore
+.DS_Store
+data
+README.md
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644
index 0000000..ab3fde4
--- /dev/null
+++ b/.eslintrc.cjs
@@ -0,0 +1,12 @@
+module.exports = {
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaVersion: 2022,
+ sourceType: 'module',
+ },
+ extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
+ rules: {
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
+ },
+};
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7970f70
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+node_modules
+dist
+*.log
+.DS_Store
+data
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..96fec79
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,7 @@
+{
+ "semi": true,
+ "trailingComma": "all",
+ "singleQuote": true,
+ "printWidth": 120,
+ "tabWidth": 4
+}
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..5fa41f6
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,17 @@
+FROM node:24-slim AS base
+
+WORKDIR /app
+
+COPY package*.json ./
+RUN npm ci --quiet
+
+COPY . .
+RUN npm run build
+
+# Create data directory
+RUN mkdir -p /app/data
+
+EXPOSE 9000
+
+ENTRYPOINT ["node", "dist/index.js"]
+CMD ["--port", "9000", "--host", "0.0.0.0", "--data-dir", "/app/data"]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..064fa71
--- /dev/null
+++ b/README.md
@@ -0,0 +1,345 @@
+# Posthook - Dynamic Webhook Receiver
+
+A simple API service for receiving and storing webhook requests with dynamic route registration.
+
+## Features
+
+- Dynamic route/topic registration
+- Multiple content type support (JSON, form, text, raw)
+- CSRF token protection with HMAC-signed stateless tokens
+- hCaptcha protection per route
+- ntfy notification alerts when webhooks are received
+- Form redirect support (`_redirect` field)
+- Request storage with timestamp-prefixed UUIDs
+- Per-topic storage organization
+- TypeScript with Pengueno framework
+- Comprehensive metrics and tracing
+- Single Dockerfile deployment
+
+## API Endpoints
+
+### Route Prefixes
+
+- **`/`** - Public routes (webhooks, token generation, health)
+- **`/admin`** - Admin routes (route management) - Put behind OAuth proxy
+
+### Admin Endpoints
+
+**⚠️ Recommendation**: Put `/admin/*` behind an OAuth proxy (e.g., OAuth2 Proxy, Pomerium) for authentication.
+
+#### Register a Route
+```bash
+POST /admin/routes
+Content-Type: application/json
+
+{
+ "name": "my-webhook",
+ "contentType": "json",
+ "hcaptchaProtected": false
+}
+```
+
+With hCaptcha protection:
+```bash
+POST /admin/routes
+Content-Type: application/json
+
+{
+ "name": "protected-webhook",
+ "contentType": "json",
+ "hcaptchaProtected": true,
+ "hcaptchaSecret": "your-hcaptcha-secret"
+}
+```
+
+With ntfy notifications:
+```bash
+POST /admin/routes
+Content-Type: application/json
+
+{
+ "name": "notified-webhook",
+ "contentType": "json",
+ "hcaptchaProtected": false,
+ "ntfy": {
+ "enabled": true,
+ "server": "https://ntfy.sh",
+ "topic": "my-webhook-alerts"
+ }
+}
+```
+
+With CSRF token protection:
+```bash
+POST /admin/routes
+Content-Type: application/json
+
+{
+ "name": "secure-form",
+ "contentType": "form",
+ "hcaptchaProtected": false,
+ "requireToken": true
+}
+```
+
+#### List Routes
+```bash
+GET /admin/routes
+```
+
+### Public Webhook Endpoints
+
+#### Get CSRF Token (for routes with requireToken: true)
+```bash
+GET /hook/{routeName}/token
+```
+
+Response:
+```json
+{
+ "ok": {
+ "token": "eyJ0aW1lc3RhbXAiOjE3MDI4MzQ1Njc4OTB5...",
+ "expiresAt": 1702835467890
+ }
+}
+```
+
+**Note**: Tokens expire in **30 seconds**. Generate the token server-side when rendering your form, not via client-side fetch.
+
+#### Send Webhook
+
+Send webhooks to registered routes:
+```bash
+POST /hook/{routeName}
+Content-Type: application/json
+
+{
+ "your": "data"
+}
+```
+
+For hCaptcha-protected routes, include the token:
+```bash
+POST /hook/{routeName}
+H-Captcha-Response: <token>
+Content-Type: application/json
+
+{
+ "your": "data"
+}
+```
+
+For form submissions with redirect (returns 303 redirect instead of JSON):
+```bash
+POST /hook/{routeName}
+Content-Type: application/x-www-form-urlencoded
+
+name=John&email=john@example.com&_redirect=https://example.com/thank-you
+```
+
+Or in HTML:
+```html
+<form action="/hook/my-form" method="POST">
+ <input type="text" name="name" required>
+ <input type="email" name="email" required>
+ <input type="hidden" name="_redirect" value="https://example.com/thank-you">
+ <button type="submit">Submit</button>
+</form>
+```
+
+For token-protected routes, include the token:
+```bash
+POST /hook/{routeName}
+X-CSRF-Token: <token>
+Content-Type: application/json
+
+{
+ "your": "data"
+}
+```
+
+Or in form data:
+```bash
+POST /hook/{routeName}
+Content-Type: application/x-www-form-urlencoded
+
+name=John&email=john@example.com&_token=<token>
+```
+
+#### Health Check
+```bash
+GET /health
+```
+
+## Content Types
+
+- `json` - Parse request body as JSON
+- `form` - Parse as URL-encoded form data (supports `_redirect` field)
+- `text` - Store as plain text
+- `raw` - Store raw body
+- `multipart` - Multipart form data (not yet implemented, will support `_redirect` field)
+
+## CSRF Token Protection
+
+Posthook supports stateless CSRF token protection using HMAC-signed tokens. When `requireToken: true` is set on a route, clients must include a valid token with their request.
+
+### How it works:
+
+1. **Token Generation**: Tokens are HMAC-signed with a secret and contain:
+ - Route name (prevents token reuse across routes)
+ - Timestamp (30-second TTL)
+
+2. **Token Delivery**: Tokens can be provided via:
+ - `_token` field in form data (extracted and not stored)
+ - `X-CSRF-Token` request header
+
+3. **Validation**: Server validates:
+ - HMAC signature
+ - Route name matches
+ - Token not expired (30 seconds)
+ - Timestamp not from future
+
+### Token Secret Configuration:
+
+```bash
+# Via environment variable (recommended for production)
+export POSTHOOK_TOKEN_SECRET=your-long-random-secret-here
+npm start
+
+# Via command line
+npm start -- --token-secret your-long-random-secret-here
+
+# Auto-generated (not recommended - changes on restart)
+npm start # Warns and generates random secret
+```
+
+### Server-Side Token Generation (Recommended):
+
+With a 30-second TTL, you should generate the token server-side when rendering the form, not via client-side JavaScript.
+
+**Example with server-side rendering**:
+```html
+<!-- Your server fetches the token before rendering -->
+<form action="/hook/contact-form" method="POST">
+ <input type="hidden" name="_token" value="<%= token %>">
+ <input type="text" name="name" required>
+ <input type="email" name="email" required>
+ <input type="hidden" name="_redirect" value="/thanks">
+ <button type="submit">Submit</button>
+</form>
+```
+
+**Your server** (Node.js example):
+```javascript
+app.get('/contact', async (req, res) => {
+ const response = await fetch('http://localhost:9000/hook/contact-form/token');
+ const { ok: { token } } = await response.json();
+ res.render('contact', { token });
+});
+```
+
+## Form Redirects
+
+When using `contentType: "form"` or `contentType: "multipart"`, you can include a `_redirect` field in your form data. If the request is successfully stored, the server will respond with a `303 See Other` redirect to the specified URL instead of a JSON response.
+
+The `_redirect` field is:
+- Extracted from the form data and not stored in the request body
+- Only honored on successful requests (validation failures, errors, etc. will still return JSON error responses)
+- Useful for traditional HTML form submissions where you want to redirect users after submission
+
+Example form flow:
+1. User submits form with `_redirect` field (and `_token` if required)
+2. Posthook validates token (if required) and stores the request
+3. Posthook sends ntfy notification (if configured)
+4. Posthook responds with `303 See Other` and `Location: {redirect_url}` header
+5. Browser automatically redirects user to the specified URL
+
+## ntfy Notifications
+
+When you register a route with ntfy enabled, posthook will send a notification to your specified ntfy server and topic whenever a webhook is received. The notification includes:
+
+- Request timestamp
+- Request UUID
+- HTTP method
+- Route name
+
+Example notification:
+```
+Title: Webhook received: my-webhook
+Message: Method: POST
+Timestamp: 2024-12-14T19:30:45.123Z
+UUID: 123e4567-e89b-12d3-a456-426614174000
+```
+
+## Storage Format
+
+Requests are stored per-topic in `data/{routeName}/{timestamp}_{uuid}.json`:
+
+```json
+{
+ "timestamp": 1702834567890,
+ "uuid": "123e4567-e89b-12d3-a456-426614174000",
+ "routeName": "my-webhook",
+ "method": "POST",
+ "headers": {
+ "content-type": "application/json"
+ },
+ "body": {
+ "your": "data"
+ }
+}
+```
+
+## Usage
+
+### Development
+```bash
+npm install
+npm run build
+export POSTHOOK_TOKEN_SECRET=your-secret-here
+npm start -- --port 9000 --host 0.0.0.0 --data-dir ./data
+```
+
+### Docker
+```bash
+docker build -t posthook .
+docker run -p 9000:9000 \
+ -v $(pwd)/data:/app/data \
+ -e POSTHOOK_TOKEN_SECRET=your-secret-here \
+ posthook
+```
+
+### With OAuth Proxy (Recommended for Production)
+
+Protect admin routes with an OAuth proxy:
+
+```bash
+# Run posthook
+docker run -p 9000:9000 posthook
+
+# Run OAuth2 Proxy in front of /admin routes
+docker run -p 4180:4180 \
+ quay.io/oauth2-proxy/oauth2-proxy:latest \
+ --upstream=http://localhost:9000/admin \
+ --http-address=0.0.0.0:4180 \
+ --provider=google \
+ --client-id=your-client-id \
+ --client-secret=your-client-secret \
+ --cookie-secret=random-secret-here \
+ --email-domain=yourdomain.com
+```
+
+Then configure your reverse proxy:
+- `/admin/*` → OAuth2 Proxy on port 4180
+- `/` → Posthook on port 9000
+
+## Configuration
+
+### Command Line Arguments:
+- `--port` - Server port (default: 9000)
+- `--host` - Server host (default: 0.0.0.0)
+- `--data-dir` - Data storage directory (default: ./data)
+- `--token-secret` - HMAC secret for token signing (optional, generates random if not provided)
+
+### Environment Variables:
+- `POSTHOOK_TOKEN_SECRET` - HMAC secret for token signing (recommended for production)
diff --git a/examples.sh b/examples.sh
new file mode 100755
index 0000000..69c1eb8
--- /dev/null
+++ b/examples.sh
@@ -0,0 +1,162 @@
+#!/bin/bash
+
+# Example usage of posthook API
+
+BASE_URL="${BASE_URL:-http://localhost:9000}"
+
+echo "=== Posthook Examples ==="
+echo
+
+# 1. Register a simple JSON webhook
+echo "1. Registering a simple JSON webhook..."
+curl -X POST "$BASE_URL/admin/routes" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "simple-webhook",
+ "contentType": "json",
+ "hcaptchaProtected": false
+ }'
+echo
+echo
+
+# 2. Register a form webhook
+echo "2. Registering a form webhook..."
+curl -X POST "$BASE_URL/admin/routes" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "form-webhook",
+ "contentType": "form",
+ "hcaptchaProtected": false
+ }'
+echo
+echo
+
+# 3. Register an hCaptcha-protected webhook
+echo "3. Registering an hCaptcha-protected webhook..."
+curl -X POST "$BASE_URL/admin/routes" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "protected-webhook",
+ "contentType": "json",
+ "hcaptchaProtected": true,
+ "hcaptchaSecret": "0x0000000000000000000000000000000000000000"
+ }'
+echo
+echo
+
+# 3b. Register a webhook with ntfy notifications
+echo "3b. Registering a webhook with ntfy notifications..."
+curl -X POST "$BASE_URL/admin/routes" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "ntfy-webhook",
+ "contentType": "json",
+ "hcaptchaProtected": false,
+ "ntfy": {
+ "enabled": true,
+ "server": "https://ntfy.sh",
+ "topic": "posthook-demo-alerts"
+ }
+ }'
+echo
+echo
+
+# 3c. Register a CSRF token-protected form
+echo "3c. Registering a CSRF token-protected form..."
+curl -X POST "$BASE_URL/admin/routes" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "secure-form",
+ "contentType": "form",
+ "hcaptchaProtected": false,
+ "requireToken": true
+ }'
+echo
+echo
+
+# 4. List all routes
+echo "4. Listing all routes..."
+curl -X GET "$BASE_URL/admin/routes"
+echo
+echo
+
+# 5. Send a test webhook to simple-webhook
+echo "5. Sending test data to simple-webhook..."
+curl -X POST "$BASE_URL/hook/simple-webhook" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "event": "test",
+ "data": {
+ "foo": "bar",
+ "timestamp": 1234567890
+ }
+ }'
+echo
+echo
+
+# 6. Send a form webhook
+echo "6. Sending form data to form-webhook..."
+curl -X POST "$BASE_URL/hook/form-webhook" \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "name=John&email=john@example.com&message=Hello+World"
+echo
+echo
+
+# 6b. Send a webhook to ntfy-enabled route (will trigger notification)
+echo "6b. Sending webhook to ntfy-webhook (check https://ntfy.sh/posthook-demo-alerts)..."
+curl -X POST "$BASE_URL/hook/ntfy-webhook" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "event": "test-notification",
+ "message": "This should trigger an ntfy alert"
+ }'
+echo
+echo
+
+# 6c. Send a form with redirect (should return 303 redirect)
+echo "6c. Sending form with _redirect (should return 303 redirect)..."
+curl -v -X POST "$BASE_URL/hook/form-webhook" \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "name=Jane&email=jane@example.com&message=Testing+redirect&_redirect=https://example.com/thank-you"
+echo
+echo
+
+# 6d. Get CSRF token for secure-form
+echo "6d. Getting CSRF token for secure-form..."
+TOKEN_RESPONSE=$(curl -s -X GET "$BASE_URL/hook/secure-form/token")
+TOKEN=$(echo $TOKEN_RESPONSE | jq -r '.ok.token')
+echo "Token: $TOKEN"
+echo
+echo
+
+# 6e. Send form with CSRF token
+echo "6e. Sending form with CSRF token..."
+curl -X POST "$BASE_URL/hook/secure-form" \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "name=Secure&email=secure@example.com&message=With+token&_token=$TOKEN"
+echo
+echo
+
+# 6f. Try sending without token (should fail with 400)
+echo "6f. Trying to send without token (should fail)..."
+curl -X POST "$BASE_URL/hook/secure-form" \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "name=Insecure&email=insecure@example.com&message=No+token"
+echo
+echo
+
+# 7. Test 404 on non-existent route
+echo "7. Testing 404 on non-existent route..."
+curl -X POST "$BASE_URL/hook/does-not-exist" \
+ -H "Content-Type: application/json" \
+ -d '{"test": true}'
+echo
+echo
+
+# 8. Health check
+echo "8. Health check..."
+curl -X GET "$BASE_URL/health"
+echo
+echo
+
+echo "=== Examples complete ==="
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..d771e35
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1861 @@
+{
+ "name": "@emprespresso/posthook",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@emprespresso/posthook",
+ "version": "0.1.0",
+ "dependencies": {
+ "@emprespresso/pengueno": "^0.0.17",
+ "@hono/node-server": "^1.14.0",
+ "hono": "^4.8.9"
+ },
+ "devDependencies": {
+ "@types/node": "^24.0.3",
+ "@typescript-eslint/eslint-plugin": "^8.34.1",
+ "@typescript-eslint/parser": "^8.34.1",
+ "eslint": "^8.34.1",
+ "eslint-config-prettier": "^10.1.5",
+ "eslint-plugin-prettier": "^5.5.0",
+ "prettier": "^3.5.3",
+ "typescript": "^5.8.3"
+ },
+ "engines": {
+ "node": ">=22.16.0",
+ "npm": ">=10.0.0"
+ }
+ },
+ "node_modules/@emprespresso/pengueno": {
+ "version": "0.0.17",
+ "resolved": "https://registry.npmjs.org/@emprespresso/pengueno/-/pengueno-0.0.17.tgz",
+ "integrity": "sha512-pyfXLYGoLlQlMQAyYptRLLiRrnQmCju4I1/sv1KtsJv06oPvNqzHqUzJJGHrXg/90krg7GRcxLKQ0TnQ2Bskjw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=22.16.0",
+ "npm": ">=10.0.0"
+ },
+ "optionalDependencies": {
+ "@hono/node-server": "^1.18.2",
+ "hono": "^4.8.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
+ "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
+ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@hono/node-server": {
+ "version": "1.19.7",
+ "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.7.tgz",
+ "integrity": "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.14.1"
+ },
+ "peerDependencies": {
+ "hono": "^4"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
+ "deprecated": "Use @eslint/config-array instead",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.3",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "deprecated": "Use @eslint/object-schema instead",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@pkgr/core": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
+ "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/pkgr"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "24.10.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz",
+ "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.16.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.49.0.tgz",
+ "integrity": "sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "8.49.0",
+ "@typescript-eslint/type-utils": "8.49.0",
+ "@typescript-eslint/utils": "8.49.0",
+ "@typescript-eslint/visitor-keys": "8.49.0",
+ "ignore": "^7.0.0",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.1.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.49.0",
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.49.0.tgz",
+ "integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.49.0",
+ "@typescript-eslint/types": "8.49.0",
+ "@typescript-eslint/typescript-estree": "8.49.0",
+ "@typescript-eslint/visitor-keys": "8.49.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.49.0.tgz",
+ "integrity": "sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.49.0",
+ "@typescript-eslint/types": "^8.49.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.49.0.tgz",
+ "integrity": "sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.49.0",
+ "@typescript-eslint/visitor-keys": "8.49.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/tsconfig-utils": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.49.0.tgz",
+ "integrity": "sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.49.0.tgz",
+ "integrity": "sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.49.0",
+ "@typescript-eslint/typescript-estree": "8.49.0",
+ "@typescript-eslint/utils": "8.49.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^2.1.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.49.0.tgz",
+ "integrity": "sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.49.0.tgz",
+ "integrity": "sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.49.0",
+ "@typescript-eslint/tsconfig-utils": "8.49.0",
+ "@typescript-eslint/types": "8.49.0",
+ "@typescript-eslint/visitor-keys": "8.49.0",
+ "debug": "^4.3.4",
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.1.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.49.0.tgz",
+ "integrity": "sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.7.0",
+ "@typescript-eslint/scope-manager": "8.49.0",
+ "@typescript-eslint/types": "8.49.0",
+ "@typescript-eslint/typescript-estree": "8.49.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.49.0.tgz",
+ "integrity": "sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.49.0",
+ "eslint-visitor-keys": "^4.2.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
+ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
+ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
+ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.1",
+ "@humanwhocodes/config-array": "^0.13.0",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "10.1.8",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
+ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint-config-prettier"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-prettier": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz",
+ "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prettier-linter-helpers": "^1.0.0",
+ "synckit": "^0.11.7"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint-plugin-prettier"
+ },
+ "peerDependencies": {
+ "@types/eslint": ">=8.0.0",
+ "eslint": ">=8.0.0",
+ "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
+ "prettier": ">=3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/eslint": {
+ "optional": true
+ },
+ "eslint-config-prettier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/eslint/node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/eslint/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-diff": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
+ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fastq": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+ "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+ "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hono": {
+ "version": "4.11.1",
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.1.tgz",
+ "integrity": "sha512-KsFcH0xxHes0J4zaQgWbYwmz3UPOOskdqZmItstUG93+Wk1ePBLkLGwbP9zlmh1BFUiL8Qp+Xfu9P7feJWpGNg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.9.0"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+ "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "3.7.4",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
+ "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-diff": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/synckit": {
+ "version": "0.11.11",
+ "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
+ "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@pkgr/core": "^0.2.9"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/synckit"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/ts-api-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
+ "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..7232519
--- /dev/null
+++ b/package.json
@@ -0,0 +1,36 @@
+{
+ "name": "@emprespresso/posthook",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "build": "tsc",
+ "dev": "tsc --watch",
+ "lint": "eslint src --ext .ts",
+ "lint:fix": "eslint src --ext .ts --fix",
+ "format": "prettier --write .",
+ "format:check": "prettier --check .",
+ "type-check": "tsc --noEmit",
+ "clean": "rm -rf dist node_modules",
+ "start": "node dist/index.js"
+ },
+ "dependencies": {
+ "@emprespresso/pengueno": "^0.0.17",
+ "@hono/node-server": "^1.14.0",
+ "hono": "^4.8.9"
+ },
+ "devDependencies": {
+ "@types/node": "^24.0.3",
+ "@typescript-eslint/eslint-plugin": "^8.34.1",
+ "@typescript-eslint/parser": "^8.34.1",
+ "eslint": "^8.34.1",
+ "eslint-config-prettier": "^10.1.5",
+ "eslint-plugin-prettier": "^5.5.0",
+ "prettier": "^3.5.3",
+ "typescript": "^5.8.3"
+ },
+ "engines": {
+ "node": ">=22.16.0",
+ "npm": ">=10.0.0"
+ }
+}
diff --git a/src/activity/index.ts b/src/activity/index.ts
new file mode 100644
index 0000000..20d123c
--- /dev/null
+++ b/src/activity/index.ts
@@ -0,0 +1,438 @@
+import {
+ Either,
+ ErrorSource,
+ type IActivity,
+ type IEither,
+ type ITraceable,
+ jsonModel,
+ JsonResponse,
+ LogLevel,
+ LogMetricTraceSupplier,
+ Metric,
+ PenguenoError,
+ PenguenoResponse,
+ type PenguenoRequest,
+ type ServerTrace,
+ TraceUtil,
+} from '@emprespresso/pengueno';
+import type { Storage } from '../storage/index.js';
+import type { RouteConfig } from '../types/index.js';
+import { isRouteConfig, ContentType } from '../types/index.js';
+import { verifyHCaptcha } from '../integrations/hcaptcha.js';
+import { sendNtfyNotification } from '../integrations/ntfy.js';
+import { TokenSigner } from '../token/index.js';
+
+const routeConfigMetric = Metric.fromName('Route.Config').asResult();
+const webhookRequestMetric = Metric.fromName('Webhook.Process').asResult();
+const listRoutesMetric = Metric.fromName('Routes.List').asResult();
+const tokenGenerateMetric = Metric.fromName('Token.Generate').asResult();
+
+export interface IRegisterRouteActivity {
+ registerRoute: IActivity;
+}
+
+export class RegisterRouteActivityImpl implements IRegisterRouteActivity {
+ constructor(private readonly storage: Storage) {}
+
+ private trace(r: ITraceable<PenguenoRequest, ServerTrace>) {
+ return r.flatMap(TraceUtil.withClassTrace(this)).flatMap(TraceUtil.withMetricTrace(routeConfigMetric));
+ }
+
+ public registerRoute(r: ITraceable<PenguenoRequest, ServerTrace>) {
+ const routeConfigTransformer = (j: ITraceable<unknown, ServerTrace>): IEither<PenguenoError, RouteConfig> => {
+ const config = j.get();
+ if (!isRouteConfig(config)) {
+ const err = 'Invalid route configuration';
+ j.trace.traceScope(LogLevel.WARN).trace(err);
+ return Either.left(new PenguenoError(err, 400));
+ }
+ return Either.right(config);
+ };
+
+ return this.trace(r)
+ .map(jsonModel(routeConfigTransformer))
+ .map(async (tEitherConfig) => {
+ const eitherConfig = await tEitherConfig.get();
+ return eitherConfig.flatMapAsync(async (config) => {
+ const eitherStored = await this.storage.registerRoute(config);
+ return eitherStored.mapLeft((e) => new PenguenoError(e.message, 500));
+ });
+ })
+ .flatMapAsync(
+ TraceUtil.promiseify((tEitherStored) => {
+ const errorSource = tEitherStored
+ .get()
+ .left()
+ .map(({ source }) => source)
+ .orSome(() => ErrorSource.SYSTEM)
+ .get();
+ const shouldWarn = errorSource === ErrorSource.USER;
+ return TraceUtil.traceResultingEither<PenguenoError, void, LogMetricTraceSupplier>(
+ routeConfigMetric,
+ shouldWarn,
+ )(tEitherStored);
+ }),
+ )
+ .peek(
+ TraceUtil.promiseify((tResult) =>
+ tResult.get().mapRight(() => tResult.trace.trace('Route registered successfully')),
+ ),
+ )
+ .map(
+ TraceUtil.promiseify((tEitherResult) => {
+ const result = tEitherResult.get().mapRight(() => ({ success: true }));
+ return new JsonResponse(r, result, {
+ status: result.fold(
+ ({ status }) => status,
+ () => 200,
+ ),
+ });
+ }),
+ )
+ .get();
+ }
+}
+
+export interface IWebhookActivity {
+ processWebhook: (routeName: string) => IActivity;
+}
+
+export class WebhookActivityImpl implements IWebhookActivity {
+ constructor(
+ private readonly storage: Storage,
+ private readonly signer: TokenSigner,
+ ) {}
+
+ private trace(r: ITraceable<PenguenoRequest, ServerTrace>) {
+ return r.flatMap(TraceUtil.withClassTrace(this)).flatMap(TraceUtil.withMetricTrace(webhookRequestMetric));
+ }
+
+ private async parseBody(
+ req: PenguenoRequest,
+ contentType: ContentType,
+ ): Promise<IEither<PenguenoError, { body: unknown; redirect: string | undefined; token: string | undefined }>> {
+ try {
+ const rawBody = await req.req.text();
+
+ type ParsedBody = { body: unknown; redirect: string | undefined; token: string | undefined };
+
+ switch (contentType) {
+ case ContentType.JSON:
+ try {
+ return Either.right(<ParsedBody>{
+ body: JSON.parse(rawBody),
+ redirect: undefined,
+ token: undefined,
+ });
+ } catch {
+ return Either.left(new PenguenoError('Invalid JSON', 400));
+ }
+
+ case ContentType.FORM:
+ try {
+ const formData = new URLSearchParams(rawBody);
+ const obj: Record<string, string> = {};
+ let redirect: string | undefined;
+ let token: string | undefined;
+
+ for (const [key, value] of formData.entries()) {
+ if (key === '_redirect') {
+ redirect = value;
+ } else if (key === '_token') {
+ token = value;
+ } else {
+ obj[key] = value;
+ }
+ }
+ return Either.right(<ParsedBody>{ body: obj, redirect, token });
+ } catch {
+ return Either.left(new PenguenoError('Invalid form data', 400));
+ }
+
+ case ContentType.TEXT:
+ return Either.right(<ParsedBody>{ body: rawBody, redirect: undefined, token: undefined });
+
+ case ContentType.RAW:
+ return Either.right(<ParsedBody>{ body: rawBody, redirect: undefined, token: undefined });
+
+ case ContentType.MULTIPART:
+ return Either.left(new PenguenoError('Multipart not yet implemented', 501));
+
+ default:
+ return Either.right(<ParsedBody>{ body: rawBody, redirect: undefined, token: undefined });
+ }
+ } catch (err) {
+ return Either.left(new PenguenoError(err instanceof Error ? err.message : String(err), 500));
+ }
+ }
+
+ public processWebhook(routeName: string) {
+ return (r: ITraceable<PenguenoRequest, ServerTrace>) => {
+ type WebhookResult = { success: true; stored: string; redirect: string | undefined };
+
+ return this.trace(r)
+ .flatMapAsync(async (tReq) => {
+ const route = this.storage.getRoute(routeName);
+ if (!route) {
+ tReq.trace.traceScope(LogLevel.WARN).trace(`Route not found: ${routeName}`);
+ return tReq.move(
+ Either.left<PenguenoError, WebhookResult>(new PenguenoError('Route not found', 404)),
+ );
+ }
+
+ const req = tReq.get().req;
+ const headers = req.header();
+ const query = req.query();
+
+ // Extract hCaptcha token if route is protected
+ if (route.hcaptchaProtected) {
+ const hCaptchaToken = headers['h-captcha-response'] ?? query['h-captcha-response'];
+ if (!hCaptchaToken) {
+ tReq.trace.traceScope(LogLevel.WARN).trace('Missing hCaptcha token');
+ return tReq.move(
+ Either.left<PenguenoError, WebhookResult>(
+ new PenguenoError('Missing hCaptcha token', 400),
+ ),
+ );
+ }
+
+ if (!route.hcaptchaSecret) {
+ tReq.trace.traceScope(LogLevel.ERROR).trace('hCaptcha secret not configured');
+ return tReq.move(
+ Either.left<PenguenoError, WebhookResult>(
+ new PenguenoError('Server misconfiguration', 500),
+ ),
+ );
+ }
+
+ const verifyResult = await verifyHCaptcha(hCaptchaToken, route.hcaptchaSecret);
+ const isValid = verifyResult.fold(
+ () => false,
+ (success) => success,
+ );
+
+ if (!isValid) {
+ tReq.trace.traceScope(LogLevel.WARN).trace('hCaptcha verification failed');
+ return tReq.move(
+ Either.left<PenguenoError, WebhookResult>(
+ new PenguenoError('hCaptcha verification failed', 403),
+ ),
+ );
+ }
+ }
+
+ // Parse body based on content type
+ const bodyResult = await this.parseBody(tReq.get(), route.contentType);
+ if (bodyResult.left().present()) {
+ return tReq.move(Either.left<PenguenoError, WebhookResult>(bodyResult.left().get()));
+ }
+
+ const { body, redirect, token: bodyToken } = bodyResult.right().get();
+
+ // Validate token if required
+ if (route.requireToken) {
+ const csrfToken = bodyToken ?? headers['x-csrf-token'];
+ if (!csrfToken) {
+ tReq.trace.traceScope(LogLevel.WARN).trace('Missing CSRF token');
+ return tReq.move(
+ Either.left<PenguenoError, WebhookResult>(new PenguenoError('Missing CSRF token', 400)),
+ );
+ }
+
+ const validationResult = this.signer.validate(csrfToken, routeName);
+ if (validationResult.left().present()) {
+ const error = validationResult.left().get();
+ tReq.trace.traceScope(LogLevel.WARN).trace(`Token validation failed: ${error.message}`);
+ return tReq.move(
+ Either.left<PenguenoError, WebhookResult>(
+ new PenguenoError('Invalid or expired token', 403),
+ ),
+ );
+ }
+ }
+
+ // Store the request
+ const storeResult = await this.storage.storeRequest(routeName, req.method, headers, body);
+ if (storeResult.left().present()) {
+ return tReq.move(
+ Either.left<PenguenoError, WebhookResult>(
+ new PenguenoError(storeResult.left().get().message, 500),
+ ),
+ );
+ }
+
+ const storedRequest = storeResult.right().get();
+
+ // Send ntfy notification if configured
+ if (route.ntfy?.enabled) {
+ const ntfyResult = await sendNtfyNotification(route.ntfy, storedRequest);
+ if (ntfyResult.left().present()) {
+ const err = ntfyResult.left().get();
+ tReq.trace.traceScope(LogLevel.WARN).trace(`ntfy notification failed: ${err.message}`);
+ } else {
+ tReq.trace.trace('ntfy notification sent');
+ }
+ }
+
+ const filename = `${storedRequest.timestamp}_${storedRequest.uuid}.json`;
+ return tReq.move(
+ Either.right<PenguenoError, WebhookResult>({
+ success: true,
+ stored: filename,
+ redirect,
+ }),
+ );
+ })
+ .flatMapAsync(
+ TraceUtil.promiseify((tEitherResult) => {
+ const errorSource = tEitherResult
+ .get()
+ .left()
+ .map(({ source }) => source)
+ .orSome(() => ErrorSource.SYSTEM)
+ .get();
+ const shouldWarn = errorSource === ErrorSource.USER;
+ return TraceUtil.traceResultingEither<PenguenoError, WebhookResult, LogMetricTraceSupplier>(
+ webhookRequestMetric,
+ shouldWarn,
+ )(tEitherResult);
+ }),
+ )
+ .peek(
+ TraceUtil.promiseify((tResult) =>
+ tResult.get().mapRight(() => tResult.trace.trace('Webhook request processed successfully')),
+ ),
+ )
+ .map(
+ TraceUtil.promiseify((tEitherResult) => {
+ const result = tEitherResult.get();
+
+ // Check if we should redirect
+ const shouldRedirect = result.fold(
+ () => false,
+ (data) => data.redirect !== undefined,
+ );
+
+ if (shouldRedirect) {
+ const redirectUrl = result.right().get().redirect!;
+ return new PenguenoResponse(r, '', {
+ status: 303,
+ statusText: 'See Other',
+ headers: { Location: redirectUrl },
+ });
+ }
+
+ // Return JSON response for non-redirect cases
+ return new JsonResponse(r, result, {
+ status: result.fold(
+ ({ status }) => status,
+ () => 200,
+ ),
+ });
+ }),
+ )
+ .get();
+ };
+ }
+}
+
+export interface IListRoutesActivity {
+ listRoutes: IActivity;
+}
+
+export class ListRoutesActivityImpl implements IListRoutesActivity {
+ constructor(private readonly storage: Storage) {}
+
+ private trace(r: ITraceable<PenguenoRequest, ServerTrace>) {
+ return r.flatMap(TraceUtil.withClassTrace(this)).flatMap(TraceUtil.withMetricTrace(listRoutesMetric));
+ }
+
+ public listRoutes(r: ITraceable<PenguenoRequest, ServerTrace>) {
+ type ListRoutesResult = {
+ routes: Array<{
+ name: string;
+ contentType: ContentType;
+ hcaptchaProtected: boolean;
+ ntfyEnabled: boolean;
+ requireToken: boolean;
+ }>;
+ };
+
+ return this.trace(r)
+ .map((tReq) => {
+ void tReq.get();
+
+ const routes = this.storage.listRoutes();
+ const sanitized = routes.map(({ name, contentType, hcaptchaProtected, ntfy, requireToken }) => ({
+ name,
+ contentType,
+ hcaptchaProtected,
+ ntfyEnabled: ntfy?.enabled || false,
+ requireToken: requireToken || false,
+ }));
+ return Either.right<PenguenoError, ListRoutesResult>({ routes: sanitized });
+ })
+ .peek(
+ TraceUtil.traceResultingEither<PenguenoError, ListRoutesResult, LogMetricTraceSupplier>(
+ listRoutesMetric,
+ ),
+ )
+ .map(
+ async (tEitherResult) =>
+ new JsonResponse(r, tEitherResult.get(), {
+ status: 200,
+ }),
+ )
+ .get();
+ }
+}
+
+export interface ITokenGenerateActivity {
+ generateToken: (routeName: string) => IActivity;
+}
+
+export class TokenGenerateActivityImpl implements ITokenGenerateActivity {
+ constructor(
+ private readonly storage: Storage,
+ private readonly signer: TokenSigner,
+ ) {}
+
+ private trace(r: ITraceable<PenguenoRequest, ServerTrace>) {
+ return r.flatMap(TraceUtil.withClassTrace(this)).flatMap(TraceUtil.withMetricTrace(tokenGenerateMetric));
+ }
+
+ public generateToken(routeName: string) {
+ return (r: ITraceable<PenguenoRequest, ServerTrace>) => {
+ type TokenResult = { token: string; expiresAt: number };
+
+ return this.trace(r)
+ .map((tReq) => {
+ const route = this.storage.getRoute(routeName);
+ if (!route) {
+ tReq.trace.traceScope(LogLevel.WARN).trace(`Route not found: ${routeName}`);
+ return Either.left<PenguenoError, TokenResult>(new PenguenoError('Route not found', 404));
+ }
+
+ const token = this.signer.generate(routeName);
+ const expiresAt = Date.now() + 30 * 1000; // 30 seconds
+
+ return Either.right<PenguenoError, TokenResult>({ token, expiresAt });
+ })
+ .peek(
+ TraceUtil.traceResultingEither<PenguenoError, TokenResult, LogMetricTraceSupplier>(
+ tokenGenerateMetric,
+ ),
+ )
+ .map(
+ async (tEitherResult) =>
+ new JsonResponse(r, tEitherResult.get(), {
+ status: tEitherResult.get().fold(
+ ({ status }) => status,
+ () => 200,
+ ),
+ }),
+ )
+ .get();
+ };
+ }
+}
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..cbc946a
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,64 @@
+#!/usr/bin/env node
+
+import { argv, Either, getEnv, type IEither, HonoProxy } from '@emprespresso/pengueno';
+import { PosthookServer } from './server/index.js';
+import { Storage } from './storage/index.js';
+import { TokenSigner } from './token/index.js';
+
+const main = async (_argv = process.argv.slice(2)): Promise<IEither<Error, void>> => {
+ const argsResult = argv(
+ ['--port', '--host', '--data-dir', '--token-secret'],
+ {
+ '--port': { absent: 9000, present: (port) => parseInt(port) },
+ '--host': { absent: '0.0.0.0', present: (host) => host },
+ '--data-dir': { absent: './data', present: (dir) => dir },
+ '--token-secret': { absent: undefined, present: (secret) => secret },
+ },
+ _argv,
+ );
+
+ return argsResult
+ .mapRight((args) => ({
+ port: args['--port'],
+ host: args['--host'],
+ dataDir: args['--data-dir'],
+ tokenSecret: args['--token-secret'],
+ }))
+ .flatMapAsync(async (config) => {
+ // Initialize storage
+ const storage = new Storage(config.dataDir);
+ const initResult = await storage.init();
+
+ if (initResult.left().present()) {
+ return Either.left(initResult.left().get());
+ }
+
+ // Initialize token signer (use env var or command line arg or generate random)
+ const envSecret = getEnv('POSTHOOK_TOKEN_SECRET');
+ const secret = config.tokenSecret ?? (envSecret.present() ? envSecret.get() : undefined);
+ const signer = new TokenSigner(secret);
+
+ if (config.tokenSecret === undefined && !envSecret.present()) {
+ console.log('No token secret provided; generated a random one (will not persist across restarts).');
+ console.log('Set POSTHOOK_TOKEN_SECRET or pass --token-secret to use a persistent secret.');
+ }
+
+ console.log(`Storage initialized at: ${config.dataDir}`);
+ console.log(`Starting server on ${config.host}:${config.port}`);
+
+ // Create and start server
+ const server = new PosthookServer(storage, signer);
+ const hono = new HonoProxy(server);
+
+ return hono.serve(config.port, config.host);
+ });
+};
+
+if (process.argv[1] === import.meta.filename) {
+ await main().then((eitherDone) =>
+ eitherDone.mapLeft((err) => {
+ console.error('error:', err);
+ process.exit(1);
+ }),
+ );
+}
diff --git a/src/integrations/hcaptcha.ts b/src/integrations/hcaptcha.ts
new file mode 100644
index 0000000..78ff356
--- /dev/null
+++ b/src/integrations/hcaptcha.ts
@@ -0,0 +1,32 @@
+import { Either, type IEither } from '@emprespresso/pengueno';
+
+export interface HCaptchaResponse {
+ success: boolean;
+ challenge_ts?: string;
+ hostname?: string;
+ 'error-codes'?: string[];
+}
+
+export async function verifyHCaptcha(token: string, secret: string): Promise<IEither<Error, boolean>> {
+ try {
+ const response = await fetch('https://hcaptcha.com/siteverify', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ body: new URLSearchParams({
+ secret,
+ response: token,
+ }),
+ });
+
+ if (!response.ok) {
+ return Either.left(new Error(`hCaptcha verification failed: ${response.statusText}`));
+ }
+
+ const result = (await response.json()) as HCaptchaResponse;
+ return Either.right(result.success);
+ } catch (err) {
+ return Either.left(err instanceof Error ? err : new Error(String(err)));
+ }
+}
diff --git a/src/integrations/ntfy.ts b/src/integrations/ntfy.ts
new file mode 100644
index 0000000..cf815ed
--- /dev/null
+++ b/src/integrations/ntfy.ts
@@ -0,0 +1,40 @@
+import { Either, type IEither } from '@emprespresso/pengueno';
+import type { NtfyConfig, StoredRequest } from '../types/index.js';
+
+export interface NtfyNotification {
+ topic: string;
+ title: string;
+ message: string;
+ tags?: string[];
+ priority?: number;
+}
+
+export async function sendNtfyNotification(config: NtfyConfig, request: StoredRequest): Promise<IEither<Error, void>> {
+ if (!config.enabled || !config.server || !config.topic) {
+ return Either.right(<void>undefined);
+ }
+
+ try {
+ const url = `${config.server}/${config.topic}`;
+ const title = `Webhook received: ${request.routeName}`;
+ const message = `Method: ${request.method}\nTimestamp: ${new Date(request.timestamp).toISOString()}\nUUID: ${request.uuid}`;
+
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ Title: title,
+ Tags: 'webhook,posthook',
+ Priority: '3',
+ },
+ body: message,
+ });
+
+ if (!response.ok) {
+ return Either.left(new Error(`ntfy notification failed: ${response.statusText}`));
+ }
+
+ return Either.right(<void>undefined);
+ } catch (err) {
+ return Either.left(err instanceof Error ? err : new Error(String(err)));
+ }
+}
diff --git a/src/server/index.ts b/src/server/index.ts
new file mode 100644
index 0000000..0747680
--- /dev/null
+++ b/src/server/index.ts
@@ -0,0 +1,84 @@
+import {
+ Either,
+ FourOhFourActivityImpl,
+ HealthCheckActivityImpl,
+ type HealthChecker,
+ HealthCheckOutput,
+ type IFourOhFourActivity,
+ type IHealthCheckActivity,
+ type ITraceable,
+ PenguenoRequest,
+ Server,
+ type ServerTrace,
+} from '@emprespresso/pengueno';
+import { Storage } from '../storage/index.js';
+import {
+ ListRoutesActivityImpl,
+ RegisterRouteActivityImpl,
+ TokenGenerateActivityImpl,
+ WebhookActivityImpl,
+ type IListRoutesActivity,
+ type IRegisterRouteActivity,
+ type ITokenGenerateActivity,
+ type IWebhookActivity,
+} from '../activity/index.js';
+import { TokenSigner } from '../token/index.js';
+
+const defaultHealthCheck: HealthChecker = async (input) => {
+ void input.get();
+ return Either.right(HealthCheckOutput.YAASSSLAYQUEEN);
+};
+
+export class PosthookServer implements Server {
+ constructor(
+ storage: Storage,
+ signer: TokenSigner,
+ healthCheck: HealthChecker = defaultHealthCheck,
+ private readonly healthCheckActivity: IHealthCheckActivity = new HealthCheckActivityImpl(healthCheck),
+ private readonly registerRouteActivity: IRegisterRouteActivity = new RegisterRouteActivityImpl(storage),
+ private readonly webhookActivity: IWebhookActivity = new WebhookActivityImpl(storage, signer),
+ private readonly tokenGenerateActivity: ITokenGenerateActivity = new TokenGenerateActivityImpl(storage, signer),
+ private readonly listRoutesActivity: IListRoutesActivity = new ListRoutesActivityImpl(storage),
+ private readonly fourOhFourActivity: IFourOhFourActivity = new FourOhFourActivityImpl(),
+ ) {}
+
+ public serve(req: ITraceable<PenguenoRequest, ServerTrace>) {
+ const url = new URL(req.get().req.url);
+ const { pathname } = url;
+
+ // === Public Routes (/) ===
+
+ // Health check endpoint
+ if (pathname === '/health') {
+ return this.healthCheckActivity.checkHealth(req);
+ }
+
+ // Token generation endpoint - /hook/{routeName}/token
+ const tokenMatch = pathname.match(/^\/hook\/([^/]+)\/token$/);
+ if (tokenMatch && req.get().req.method === 'GET') {
+ const routeName = tokenMatch[1];
+ return this.tokenGenerateActivity.generateToken(routeName)(req);
+ }
+
+ // Dynamic webhook endpoints - /hook/{routeName}
+ const hookMatch = pathname.match(/^\/hook\/([^/]+)$/);
+ if (hookMatch && req.get().req.method === 'POST') {
+ const routeName = hookMatch[1];
+ return this.webhookActivity.processWebhook(routeName)(req);
+ }
+
+ // === Admin Routes (/admin) - Put behind OAuth proxy ===
+
+ // Admin endpoints for route management
+ if (pathname === '/admin/routes' && req.get().req.method === 'POST') {
+ return this.registerRouteActivity.registerRoute(req);
+ }
+
+ if (pathname === '/admin/routes' && req.get().req.method === 'GET') {
+ return this.listRoutesActivity.listRoutes(req);
+ }
+
+ // 404 for everything else
+ return this.fourOhFourActivity.fourOhFour(req);
+ }
+}
diff --git a/src/storage/index.ts b/src/storage/index.ts
new file mode 100644
index 0000000..2c8ffb2
--- /dev/null
+++ b/src/storage/index.ts
@@ -0,0 +1,114 @@
+import { randomUUID } from 'crypto';
+import { mkdir, writeFile, readFile } from 'fs/promises';
+import { join } from 'path';
+import { isSafeRouteName, type RouteConfig, type StoredRequest } from '../types/index.js';
+import { Either, type IEither } from '@emprespresso/pengueno';
+
+export class Storage {
+ private routes: Map<string, RouteConfig> = new Map();
+
+ constructor(private readonly dataDir: string = './data') {}
+
+ async init(): Promise<IEither<Error, void>> {
+ try {
+ await mkdir(this.dataDir, { recursive: true });
+ await this.loadRoutes();
+ return Either.right(<void>undefined);
+ } catch (err) {
+ return Either.left(err instanceof Error ? err : new Error(String(err)));
+ }
+ }
+
+ private async loadRoutes(): Promise<void> {
+ try {
+ const routesPath = join(this.dataDir, 'routes.json');
+ const data = await readFile(routesPath, 'utf-8');
+ const routes = JSON.parse(data) as RouteConfig[];
+ for (const route of routes) {
+ if (!isSafeRouteName(route.name)) {
+ continue;
+ }
+ this.routes.set(route.name, route);
+ }
+ } catch {
+ // routes file doesn't exist yet, that's ok
+ }
+ }
+
+ private async saveRoutes(): Promise<IEither<Error, void>> {
+ try {
+ const routesPath = join(this.dataDir, 'routes.json');
+ const routes = Array.from(this.routes.values());
+ await writeFile(routesPath, JSON.stringify(routes, null, 2));
+ return Either.right(<void>undefined);
+ } catch (err) {
+ return Either.left(err instanceof Error ? err : new Error(String(err)));
+ }
+ }
+
+ async registerRoute(config: RouteConfig): Promise<IEither<Error, void>> {
+ if (!isSafeRouteName(config.name)) {
+ return Either.left(new Error('Invalid route name'));
+ }
+
+ this.routes.set(config.name, config);
+ const routeDir = join(this.dataDir, config.name);
+ try {
+ await mkdir(routeDir, { recursive: true });
+ } catch (err) {
+ return Either.left(err instanceof Error ? err : new Error(String(err)));
+ }
+ return this.saveRoutes();
+ }
+
+ getRoute(name: string): RouteConfig | undefined {
+ if (!isSafeRouteName(name)) return undefined;
+ return this.routes.get(name);
+ }
+
+ listRoutes(): RouteConfig[] {
+ return Array.from(this.routes.values());
+ }
+
+ async deleteRoute(name: string): Promise<IEither<Error, void>> {
+ if (!isSafeRouteName(name)) {
+ return Either.left(new Error('Invalid route name'));
+ }
+ this.routes.delete(name);
+ return this.saveRoutes();
+ }
+
+ async storeRequest(
+ routeName: string,
+ method: string,
+ headers: Record<string, string>,
+ body: unknown,
+ files?: StoredRequest['files'],
+ ): Promise<IEither<Error, StoredRequest>> {
+ if (!isSafeRouteName(routeName)) {
+ return Either.left(new Error('Invalid route name'));
+ }
+
+ const timestamp = Date.now();
+ const uuid = randomUUID();
+ const filename = `${timestamp}_${uuid}.json`;
+
+ const stored: StoredRequest = {
+ timestamp,
+ uuid,
+ routeName,
+ method,
+ headers,
+ body,
+ files,
+ };
+
+ const filepath = join(this.dataDir, routeName, filename);
+ try {
+ await writeFile(filepath, JSON.stringify(stored, null, 2));
+ return Either.right(stored);
+ } catch (err) {
+ return Either.left(err instanceof Error ? err : new Error(String(err)));
+ }
+ }
+}
diff --git a/src/token/index.ts b/src/token/index.ts
new file mode 100644
index 0000000..7251714
--- /dev/null
+++ b/src/token/index.ts
@@ -0,0 +1,76 @@
+import { createHmac, randomBytes } from 'crypto';
+import { Either, type IEither } from '@emprespresso/pengueno';
+
+export interface TokenPayload {
+ routeName: string;
+ timestamp: number;
+}
+
+export class TokenSigner {
+ private readonly secret: string;
+ private readonly ttlSeconds: number;
+
+ constructor(secret?: string, ttlSeconds: number = 30) {
+ this.secret = secret || randomBytes(32).toString('hex');
+ this.ttlSeconds = ttlSeconds;
+ }
+
+ generate(routeName: string): string {
+ const timestamp = Date.now();
+ const payload = JSON.stringify({ routeName, timestamp });
+ const signature = this.sign(payload);
+ const token = Buffer.from(`${payload}.${signature}`).toString('base64url');
+ return token;
+ }
+
+ validate(token: string, expectedRoute: string): IEither<Error, TokenPayload> {
+ try {
+ const decoded = Buffer.from(token, 'base64url').toString('utf-8');
+ const lastDotIndex = decoded.lastIndexOf('.');
+
+ if (lastDotIndex === -1) {
+ return Either.left(new Error('Invalid token format'));
+ }
+
+ const payload = decoded.substring(0, lastDotIndex);
+ const signature = decoded.substring(lastDotIndex + 1);
+
+ // Verify signature
+ const expectedSignature = this.sign(payload);
+ if (signature !== expectedSignature) {
+ return Either.left(new Error('Invalid token signature'));
+ }
+
+ // Parse payload
+ const parsed: TokenPayload = JSON.parse(payload);
+
+ // Check route name
+ if (parsed.routeName !== expectedRoute) {
+ return Either.left(new Error('Token route mismatch'));
+ }
+
+ // Check expiration
+ const now = Date.now();
+ const age = (now - parsed.timestamp) / 1000;
+ if (age > this.ttlSeconds) {
+ return Either.left(new Error('Token expired'));
+ }
+
+ if (age < 0) {
+ return Either.left(new Error('Token from future'));
+ }
+
+ return Either.right(parsed);
+ } catch (err) {
+ return Either.left(err instanceof Error ? err : new Error(String(err)));
+ }
+ }
+
+ private sign(payload: string): string {
+ return createHmac('sha256', this.secret).update(payload).digest('hex');
+ }
+
+ getSecret(): string {
+ return this.secret;
+ }
+}
diff --git a/src/types/index.ts b/src/types/index.ts
new file mode 100644
index 0000000..fbfc70d
--- /dev/null
+++ b/src/types/index.ts
@@ -0,0 +1,78 @@
+export enum ContentType {
+ JSON = 'json',
+ FORM = 'form',
+ MULTIPART = 'multipart',
+ TEXT = 'text',
+ RAW = 'raw',
+}
+
+export interface NtfyConfig {
+ enabled: boolean;
+ server?: string;
+ topic?: string;
+}
+
+export interface RouteConfig {
+ name: string;
+ contentType: ContentType;
+ hcaptchaProtected: boolean;
+ hcaptchaSecret?: string;
+ ntfy?: NtfyConfig;
+ requireToken?: boolean;
+}
+
+export interface StoredRequest {
+ timestamp: number;
+ uuid: string;
+ routeName: string;
+ method: string;
+ headers: Record<string, string>;
+ body: unknown;
+ files?: Array<{
+ filename: string;
+ contentType: string;
+ size: number;
+ path: string;
+ }>;
+}
+
+const ROUTE_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,63}$/i;
+
+export function isSafeRouteName(name: unknown): name is string {
+ if (typeof name !== 'string') return false;
+ if (name !== name.trim()) return false;
+ if (name === '.' || name === '..') return false;
+ if (name.includes('/') || name.includes('\\')) return false;
+ return ROUTE_NAME_PATTERN.test(name);
+}
+
+export function isRouteConfig(obj: unknown): obj is RouteConfig {
+ if (typeof obj !== 'object' || obj === null) return false;
+ const r = obj as Record<string, unknown>;
+
+ const validBasic =
+ isSafeRouteName(r.name) &&
+ typeof r.contentType === 'string' &&
+ Object.values(ContentType).includes(r.contentType as ContentType) &&
+ typeof r.hcaptchaProtected === 'boolean' &&
+ (r.hcaptchaProtected === false || typeof r.hcaptchaSecret === 'string');
+
+ if (!validBasic) return false;
+
+ // Validate ntfy config if present
+ if (r.ntfy !== undefined) {
+ if (typeof r.ntfy !== 'object' || r.ntfy === null) return false;
+ const ntfy = r.ntfy as Record<string, unknown>;
+ if (typeof ntfy.enabled !== 'boolean') return false;
+ if (ntfy.enabled && (typeof ntfy.server !== 'string' || typeof ntfy.topic !== 'string')) {
+ return false;
+ }
+ }
+
+ // Validate requireToken if present
+ if (r.requireToken !== undefined && typeof r.requireToken !== 'boolean') {
+ return false;
+ }
+
+ return true;
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..0203457
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ES2022",
+ "lib": ["ES2022"],
+ "moduleResolution": "node",
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "declaration": true,
+ "declarationMap": true,
+ "sourceMap": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src/**/*.ts"],
+ "exclude": ["node_modules", "dist"]
+}