git.iko.soy/purestack-dev/purescript-purestack-server
on 94d927c help sign in
17 files changed+1817−1069
since splitsnapshots
unifiedsplit
index.js+1633 spago.dhall+2−16 src/Bun/Request.js+2−6 src/Bun/Request.purs+2−18 src/Bun/Response.js−23 src/Bun/Response.purs+3−9 src/Bun/Server.js+1−1 src/Bun/Server.purs+1−7 src/Main.purs+5−23 src/PureStack/Cookie.purs−57 src/PureStack/Cookie/Formatter.purs−65 src/PureStack/Cookie/Generator.purs−62 src/PureStack/Cookie/Parser.purs−128 src/PureStack/Cookie/Types.purs−189 src/PureStack/Route.purs−55 src/PureStack/Router.purs+168 src/PureStack/Server.purs−410
index.jsnew file+1633
@@ -0,0 +1,1633 @@
1+(() => {
2+ // output/Bun.Server/foreign.js
3+ function serve(f) {
4+ return function() {
5+ return Bun.serve({
6+ fetch(req) {
7+ return f(req)();
8+ }
9+ });
10+ };
11+ }
12+
13+ // output/Control.Apply/foreign.js
14+ var arrayApply = function(fs) {
15+ return function(xs) {
16+ var l = fs.length;
17+ var k = xs.length;
18+ var result = new Array(l * k);
19+ var n = 0;
20+ for (var i = 0; i < l; i++) {
21+ var f = fs[i];
22+ for (var j = 0; j < k; j++) {
23+ result[n++] = f(xs[j]);
24+ }
25+ }
26+ return result;
27+ };
28+ };
29+
30+ // output/Control.Semigroupoid/index.js
31+ var semigroupoidFn = {
32+ compose: function(f) {
33+ return function(g) {
34+ return function(x) {
35+ return f(g(x));
36+ };
37+ };
38+ }
39+ };
40+
41+ // output/Control.Category/index.js
42+ var identity = function(dict) {
43+ return dict.identity;
44+ };
45+ var categoryFn = {
46+ identity: function(x) {
47+ return x;
48+ },
49+ Semigroupoid0: function() {
50+ return semigroupoidFn;
51+ }
52+ };
53+
54+ // output/Data.Function/index.js
55+ var flip = function(f) {
56+ return function(b) {
57+ return function(a) {
58+ return f(a)(b);
59+ };
60+ };
61+ };
62+ var $$const = function(a) {
63+ return function(v) {
64+ return a;
65+ };
66+ };
67+
68+ // output/Data.Functor/foreign.js
69+ var arrayMap = function(f) {
70+ return function(arr) {
71+ var l = arr.length;
72+ var result = new Array(l);
73+ for (var i = 0; i < l; i++) {
74+ result[i] = f(arr[i]);
75+ }
76+ return result;
77+ };
78+ };
79+
80+ // output/Data.Unit/foreign.js
81+ var unit = void 0;
82+
83+ // output/Type.Proxy/index.js
84+ var $$Proxy = /* @__PURE__ */ function() {
85+ function $$Proxy2() {
86+ }
87+ ;
88+ $$Proxy2.value = new $$Proxy2();
89+ return $$Proxy2;
90+ }();
91+
92+ // output/Data.Functor/index.js
93+ var map = function(dict) {
94+ return dict.map;
95+ };
96+ var $$void = function(dictFunctor) {
97+ return map(dictFunctor)($$const(unit));
98+ };
99+ var functorArray = {
100+ map: arrayMap
101+ };
102+
103+ // output/Control.Apply/index.js
104+ var applyArray = {
105+ apply: arrayApply,
106+ Functor0: function() {
107+ return functorArray;
108+ }
109+ };
110+ var apply = function(dict) {
111+ return dict.apply;
112+ };
113+
114+ // output/Control.Applicative/index.js
115+ var pure = function(dict) {
116+ return dict.pure;
117+ };
118+ var liftA1 = function(dictApplicative) {
119+ var apply3 = apply(dictApplicative.Apply0());
120+ var pure13 = pure(dictApplicative);
121+ return function(f) {
122+ return function(a) {
123+ return apply3(pure13(f))(a);
124+ };
125+ };
126+ };
127+
128+ // output/Data.Argonaut.Core/foreign.js
129+ function id(x) {
130+ return x;
131+ }
132+
133+ // output/Data.Eq/foreign.js
134+ var refEq = function(r1) {
135+ return function(r2) {
136+ return r1 === r2;
137+ };
138+ };
139+ var eqStringImpl = refEq;
140+ var eqArrayImpl = function(f) {
141+ return function(xs) {
142+ return function(ys) {
143+ if (xs.length !== ys.length) return false;
144+ for (var i = 0; i < xs.length; i++) {
145+ if (!f(xs[i])(ys[i])) return false;
146+ }
147+ return true;
148+ };
149+ };
150+ };
151+
152+ // output/Data.Symbol/index.js
153+ var reflectSymbol = function(dict) {
154+ return dict.reflectSymbol;
155+ };
156+
157+ // output/Record.Unsafe/foreign.js
158+ var unsafeGet = function(label) {
159+ return function(rec) {
160+ return rec[label];
161+ };
162+ };
163+ var unsafeDelete = function(label) {
164+ return function(rec) {
165+ var copy = {};
166+ for (var key in rec) {
167+ if (key !== label && {}.hasOwnProperty.call(rec, key)) {
168+ copy[key] = rec[key];
169+ }
170+ }
171+ return copy;
172+ };
173+ };
174+
175+ // output/Data.Eq/index.js
176+ var eqString = {
177+ eq: eqStringImpl
178+ };
179+ var eq = function(dict) {
180+ return dict.eq;
181+ };
182+ var eqArray = function(dictEq) {
183+ return {
184+ eq: eqArrayImpl(eq(dictEq))
185+ };
186+ };
187+
188+ // output/Data.Semigroup/foreign.js
189+ var concatArray = function(xs) {
190+ return function(ys) {
191+ if (xs.length === 0) return ys;
192+ if (ys.length === 0) return xs;
193+ return xs.concat(ys);
194+ };
195+ };
196+
197+ // output/Data.Semigroup/index.js
198+ var semigroupArray = {
199+ append: concatArray
200+ };
201+ var append = function(dict) {
202+ return dict.append;
203+ };
204+
205+ // output/Data.Bounded/foreign.js
206+ var topChar = String.fromCharCode(65535);
207+ var bottomChar = String.fromCharCode(0);
208+ var topNumber = Number.POSITIVE_INFINITY;
209+ var bottomNumber = Number.NEGATIVE_INFINITY;
210+
211+ // output/Data.Maybe/index.js
212+ var Nothing = /* @__PURE__ */ function() {
213+ function Nothing2() {
214+ }
215+ ;
216+ Nothing2.value = new Nothing2();
217+ return Nothing2;
218+ }();
219+ var Just = /* @__PURE__ */ function() {
220+ function Just2(value0) {
221+ this.value0 = value0;
222+ }
223+ ;
224+ Just2.create = function(value0) {
225+ return new Just2(value0);
226+ };
227+ return Just2;
228+ }();
229+ var maybe = function(v) {
230+ return function(v1) {
231+ return function(v2) {
232+ if (v2 instanceof Nothing) {
233+ return v;
234+ }
235+ ;
236+ if (v2 instanceof Just) {
237+ return v1(v2.value0);
238+ }
239+ ;
240+ throw new Error("Failed pattern match at Data.Maybe (line 237, column 1 - line 237, column 51): " + [v.constructor.name, v1.constructor.name, v2.constructor.name]);
241+ };
242+ };
243+ };
244+ var functorMaybe = {
245+ map: function(v) {
246+ return function(v1) {
247+ if (v1 instanceof Just) {
248+ return new Just(v(v1.value0));
249+ }
250+ ;
251+ return Nothing.value;
252+ };
253+ }
254+ };
255+ var map2 = /* @__PURE__ */ map(functorMaybe);
256+ var applyMaybe = {
257+ apply: function(v) {
258+ return function(v1) {
259+ if (v instanceof Just) {
260+ return map2(v.value0)(v1);
261+ }
262+ ;
263+ if (v instanceof Nothing) {
264+ return Nothing.value;
265+ }
266+ ;
267+ throw new Error("Failed pattern match at Data.Maybe (line 67, column 1 - line 69, column 30): " + [v.constructor.name, v1.constructor.name]);
268+ };
269+ },
270+ Functor0: function() {
271+ return functorMaybe;
272+ }
273+ };
274+ var bindMaybe = {
275+ bind: function(v) {
276+ return function(v1) {
277+ if (v instanceof Just) {
278+ return v1(v.value0);
279+ }
280+ ;
281+ if (v instanceof Nothing) {
282+ return Nothing.value;
283+ }
284+ ;
285+ throw new Error("Failed pattern match at Data.Maybe (line 125, column 1 - line 127, column 28): " + [v.constructor.name, v1.constructor.name]);
286+ };
287+ },
288+ Apply0: function() {
289+ return applyMaybe;
290+ }
291+ };
292+ var applicativeMaybe = /* @__PURE__ */ function() {
293+ return {
294+ pure: Just.create,
295+ Apply0: function() {
296+ return applyMaybe;
297+ }
298+ };
299+ }();
300+ var altMaybe = {
301+ alt: function(v) {
302+ return function(v1) {
303+ if (v instanceof Nothing) {
304+ return v1;
305+ }
306+ ;
307+ return v;
308+ };
309+ },
310+ Functor0: function() {
311+ return functorMaybe;
312+ }
313+ };
314+ var plusMaybe = /* @__PURE__ */ function() {
315+ return {
316+ empty: Nothing.value,
317+ Alt0: function() {
318+ return altMaybe;
319+ }
320+ };
321+ }();
322+
323+ // output/Foreign.Object/foreign.js
324+ function _copyST(m) {
325+ return function() {
326+ var r = {};
327+ for (var k in m) {
328+ if (hasOwnProperty.call(m, k)) {
329+ r[k] = m[k];
330+ }
331+ }
332+ return r;
333+ };
334+ }
335+ var empty = {};
336+ function runST(f) {
337+ return f();
338+ }
339+ function toArrayWithKey(f) {
340+ return function(m) {
341+ var r = [];
342+ for (var k in m) {
343+ if (hasOwnProperty.call(m, k)) {
344+ r.push(f(k)(m[k]));
345+ }
346+ }
347+ return r;
348+ };
349+ }
350+ var keys = Object.keys || toArrayWithKey(function(k) {
351+ return function() {
352+ return k;
353+ };
354+ });
355+
356+ // output/Control.Bind/foreign.js
357+ var arrayBind = typeof Array.prototype.flatMap === "function" ? function(arr) {
358+ return function(f) {
359+ return arr.flatMap(f);
360+ };
361+ } : function(arr) {
362+ return function(f) {
363+ var result = [];
364+ var l = arr.length;
365+ for (var i = 0; i < l; i++) {
366+ var xs = f(arr[i]);
367+ var k = xs.length;
368+ for (var j = 0; j < k; j++) {
369+ result.push(xs[j]);
370+ }
371+ }
372+ return result;
373+ };
374+ };
375+
376+ // output/Control.Bind/index.js
377+ var identity2 = /* @__PURE__ */ identity(categoryFn);
378+ var discard = function(dict) {
379+ return dict.discard;
380+ };
381+ var bindArray = {
382+ bind: arrayBind,
383+ Apply0: function() {
384+ return applyArray;
385+ }
386+ };
387+ var bind = function(dict) {
388+ return dict.bind;
389+ };
390+ var bindFlipped = function(dictBind) {
391+ return flip(bind(dictBind));
392+ };
393+ var discardUnit = {
394+ discard: function(dictBind) {
395+ return bind(dictBind);
396+ }
397+ };
398+ var join = function(dictBind) {
399+ var bind1 = bind(dictBind);
400+ return function(m) {
401+ return bind1(m)(identity2);
402+ };
403+ };
404+
405+ // output/Control.Monad.ST.Internal/foreign.js
406+ var map_ = function(f) {
407+ return function(a) {
408+ return function() {
409+ return f(a());
410+ };
411+ };
412+ };
413+ var pure_ = function(a) {
414+ return function() {
415+ return a;
416+ };
417+ };
418+ var bind_ = function(a) {
419+ return function(f) {
420+ return function() {
421+ return f(a())();
422+ };
423+ };
424+ };
425+ function newSTRef(val) {
426+ return function() {
427+ return { value: val };
428+ };
429+ }
430+ var read = function(ref) {
431+ return function() {
432+ return ref.value;
433+ };
434+ };
435+ var modifyImpl = function(f) {
436+ return function(ref) {
437+ return function() {
438+ var t = f(ref.value);
439+ ref.value = t.state;
440+ return t.value;
441+ };
442+ };
443+ };
444+ var write = function(a) {
445+ return function(ref) {
446+ return function() {
447+ return ref.value = a;
448+ };
449+ };
450+ };
451+
452+ // output/Control.Monad/index.js
453+ var ap = function(dictMonad) {
454+ var bind3 = bind(dictMonad.Bind1());
455+ var pure4 = pure(dictMonad.Applicative0());
456+ return function(f) {
457+ return function(a) {
458+ return bind3(f)(function(f$prime) {
459+ return bind3(a)(function(a$prime) {
460+ return pure4(f$prime(a$prime));
461+ });
462+ });
463+ };
464+ };
465+ };
466+
467+ // output/Data.Either/index.js
468+ var Left = /* @__PURE__ */ function() {
469+ function Left2(value0) {
470+ this.value0 = value0;
471+ }
472+ ;
473+ Left2.create = function(value0) {
474+ return new Left2(value0);
475+ };
476+ return Left2;
477+ }();
478+ var Right = /* @__PURE__ */ function() {
479+ function Right2(value0) {
480+ this.value0 = value0;
481+ }
482+ ;
483+ Right2.create = function(value0) {
484+ return new Right2(value0);
485+ };
486+ return Right2;
487+ }();
488+
489+ // output/Data.Monoid/index.js
490+ var mempty = function(dict) {
491+ return dict.mempty;
492+ };
493+
494+ // output/Effect/foreign.js
495+ var pureE = function(a) {
496+ return function() {
497+ return a;
498+ };
499+ };
500+ var bindE = function(a) {
501+ return function(f) {
502+ return function() {
503+ return f(a())();
504+ };
505+ };
506+ };
507+
508+ // output/Effect/index.js
509+ var $runtime_lazy = function(name2, moduleName, init3) {
510+ var state2 = 0;
511+ var val;
512+ return function(lineNumber) {
513+ if (state2 === 2) return val;
514+ if (state2 === 1) throw new ReferenceError(name2 + " was needed before it finished initializing (module " + moduleName + ", line " + lineNumber + ")", moduleName, lineNumber);
515+ state2 = 1;
516+ val = init3();
517+ state2 = 2;
518+ return val;
519+ };
520+ };
521+ var monadEffect = {
522+ Applicative0: function() {
523+ return applicativeEffect;
524+ },
525+ Bind1: function() {
526+ return bindEffect;
527+ }
528+ };
529+ var bindEffect = {
530+ bind: bindE,
531+ Apply0: function() {
532+ return $lazy_applyEffect(0);
533+ }
534+ };
535+ var applicativeEffect = {
536+ pure: pureE,
537+ Apply0: function() {
538+ return $lazy_applyEffect(0);
539+ }
540+ };
541+ var $lazy_functorEffect = /* @__PURE__ */ $runtime_lazy("functorEffect", "Effect", function() {
542+ return {
543+ map: liftA1(applicativeEffect)
544+ };
545+ });
546+ var $lazy_applyEffect = /* @__PURE__ */ $runtime_lazy("applyEffect", "Effect", function() {
547+ return {
548+ apply: ap(monadEffect),
549+ Functor0: function() {
550+ return $lazy_functorEffect(0);
551+ }
552+ };
553+ });
554+
555+ // output/Control.Monad.ST.Internal/index.js
556+ var $runtime_lazy2 = function(name2, moduleName, init3) {
557+ var state2 = 0;
558+ var val;
559+ return function(lineNumber) {
560+ if (state2 === 2) return val;
561+ if (state2 === 1) throw new ReferenceError(name2 + " was needed before it finished initializing (module " + moduleName + ", line " + lineNumber + ")", moduleName, lineNumber);
562+ state2 = 1;
563+ val = init3();
564+ state2 = 2;
565+ return val;
566+ };
567+ };
568+ var modify$prime = modifyImpl;
569+ var modify = function(f) {
570+ return modify$prime(function(s) {
571+ var s$prime = f(s);
572+ return {
573+ state: s$prime,
574+ value: s$prime
575+ };
576+ });
577+ };
578+ var functorST = {
579+ map: map_
580+ };
581+ var monadST = {
582+ Applicative0: function() {
583+ return applicativeST;
584+ },
585+ Bind1: function() {
586+ return bindST;
587+ }
588+ };
589+ var bindST = {
590+ bind: bind_,
591+ Apply0: function() {
592+ return $lazy_applyST(0);
593+ }
594+ };
595+ var applicativeST = {
596+ pure: pure_,
597+ Apply0: function() {
598+ return $lazy_applyST(0);
599+ }
600+ };
601+ var $lazy_applyST = /* @__PURE__ */ $runtime_lazy2("applyST", "Control.Monad.ST.Internal", function() {
602+ return {
603+ apply: ap(monadST),
604+ Functor0: function() {
605+ return functorST;
606+ }
607+ };
608+ });
609+ var applyST = /* @__PURE__ */ $lazy_applyST(47);
610+
611+ // output/Data.Array/foreign.js
612+ var replicateFill = function(count, value) {
613+ if (count < 1) {
614+ return [];
615+ }
616+ var result = new Array(count);
617+ return result.fill(value);
618+ };
619+ var replicatePolyfill = function(count, value) {
620+ var result = [];
621+ var n = 0;
622+ for (var i = 0; i < count; i++) {
623+ result[n++] = value;
624+ }
625+ return result;
626+ };
627+ var replicateImpl = typeof Array.prototype.fill === "function" ? replicateFill : replicatePolyfill;
628+ var length = function(xs) {
629+ return xs.length;
630+ };
631+ var unconsImpl = function(empty4, next2, xs) {
632+ return xs.length === 0 ? empty4({}) : next2(xs[0])(xs.slice(1));
633+ };
634+ var indexImpl = function(just, nothing, xs, i) {
635+ return i < 0 || i >= xs.length ? nothing : just(xs[i]);
636+ };
637+ var filterImpl = function(f, xs) {
638+ return xs.filter(f);
639+ };
640+ var partitionImpl = function(f, xs) {
641+ var yes = [];
642+ var no = [];
643+ for (var i = 0; i < xs.length; i++) {
644+ var x = xs[i];
645+ if (f(x))
646+ yes.push(x);
647+ else
648+ no.push(x);
649+ }
650+ return { yes, no };
651+ };
652+
653+ // output/Data.Array.ST/foreign.js
654+ function newSTArray() {
655+ return [];
656+ }
657+ function unsafeFreezeThawImpl(xs) {
658+ return xs;
659+ }
660+ var unsafeFreezeImpl = unsafeFreezeThawImpl;
661+ var pushImpl = function(a, xs) {
662+ return xs.push(a);
663+ };
664+
665+ // output/Control.Monad.ST.Uncurried/foreign.js
666+ var runSTFn1 = function runSTFn12(fn) {
667+ return function(a) {
668+ return function() {
669+ return fn(a);
670+ };
671+ };
672+ };
673+ var runSTFn2 = function runSTFn22(fn) {
674+ return function(a) {
675+ return function(b) {
676+ return function() {
677+ return fn(a, b);
678+ };
679+ };
680+ };
681+ };
682+
683+ // output/Data.Array.ST/index.js
684+ var unsafeFreeze = /* @__PURE__ */ runSTFn1(unsafeFreezeImpl);
685+ var push = /* @__PURE__ */ runSTFn2(pushImpl);
686+
687+ // output/Data.HeytingAlgebra/foreign.js
688+ var boolConj = function(b1) {
689+ return function(b2) {
690+ return b1 && b2;
691+ };
692+ };
693+ var boolDisj = function(b1) {
694+ return function(b2) {
695+ return b1 || b2;
696+ };
697+ };
698+ var boolNot = function(b) {
699+ return !b;
700+ };
701+
702+ // output/Data.HeytingAlgebra/index.js
703+ var not = function(dict) {
704+ return dict.not;
705+ };
706+ var disj = function(dict) {
707+ return dict.disj;
708+ };
709+ var heytingAlgebraBoolean = {
710+ ff: false,
711+ tt: true,
712+ implies: function(a) {
713+ return function(b) {
714+ return disj(heytingAlgebraBoolean)(not(heytingAlgebraBoolean)(a))(b);
715+ };
716+ },
717+ conj: boolConj,
718+ disj: boolDisj,
719+ not: boolNot
720+ };
721+
722+ // output/Data.Array.ST.Iterator/index.js
723+ var map3 = /* @__PURE__ */ map(functorST);
724+ var not2 = /* @__PURE__ */ not(heytingAlgebraBoolean);
725+ var $$void2 = /* @__PURE__ */ $$void(functorST);
726+ var Iterator = /* @__PURE__ */ function() {
727+ function Iterator2(value0, value1) {
728+ this.value0 = value0;
729+ this.value1 = value1;
730+ }
731+ ;
732+ Iterator2.create = function(value0) {
733+ return function(value1) {
734+ return new Iterator2(value0, value1);
735+ };
736+ };
737+ return Iterator2;
738+ }();
739+ var next = function(v) {
740+ return function __do2() {
741+ var i = read(v.value1)();
742+ modify(function(v1) {
743+ return v1 + 1 | 0;
744+ })(v.value1)();
745+ return v.value0(i);
746+ };
747+ };
748+ var iterator = function(f) {
749+ return map3(Iterator.create(f))(newSTRef(0));
750+ };
751+ var iterate = function(iter) {
752+ return function(f) {
753+ return function __do2() {
754+ var $$break = newSTRef(false)();
755+ while (map3(not2)(read($$break))()) {
756+ (function __do3() {
757+ var mx = next(iter)();
758+ if (mx instanceof Just) {
759+ return f(mx.value0)();
760+ }
761+ ;
762+ if (mx instanceof Nothing) {
763+ return $$void2(write(true)($$break))();
764+ }
765+ ;
766+ throw new Error("Failed pattern match at Data.Array.ST.Iterator (line 42, column 5 - line 44, column 47): " + [mx.constructor.name]);
767+ })();
768+ }
769+ ;
770+ return {};
771+ };
772+ };
773+ };
774+
775+ // output/Data.Foldable/foreign.js
776+ var foldrArray = function(f) {
777+ return function(init3) {
778+ return function(xs) {
779+ var acc = init3;
780+ var len = xs.length;
781+ for (var i = len - 1; i >= 0; i--) {
782+ acc = f(xs[i])(acc);
783+ }
784+ return acc;
785+ };
786+ };
787+ };
788+ var foldlArray = function(f) {
789+ return function(init3) {
790+ return function(xs) {
791+ var acc = init3;
792+ var len = xs.length;
793+ for (var i = 0; i < len; i++) {
794+ acc = f(acc)(xs[i]);
795+ }
796+ return acc;
797+ };
798+ };
799+ };
800+
801+ // output/Control.Plus/index.js
802+ var empty2 = function(dict) {
803+ return dict.empty;
804+ };
805+
806+ // output/Unsafe.Coerce/foreign.js
807+ var unsafeCoerce2 = function(x) {
808+ return x;
809+ };
810+
811+ // output/Safe.Coerce/index.js
812+ var coerce = function() {
813+ return unsafeCoerce2;
814+ };
815+
816+ // output/Data.Newtype/index.js
817+ var coerce2 = /* @__PURE__ */ coerce();
818+ var wrap = function() {
819+ return coerce2;
820+ };
821+
822+ // output/Data.Foldable/index.js
823+ var foldr = function(dict) {
824+ return dict.foldr;
825+ };
826+ var foldl = function(dict) {
827+ return dict.foldl;
828+ };
829+ var foldMapDefaultR = function(dictFoldable) {
830+ var foldr2 = foldr(dictFoldable);
831+ return function(dictMonoid) {
832+ var append3 = append(dictMonoid.Semigroup0());
833+ var mempty2 = mempty(dictMonoid);
834+ return function(f) {
835+ return foldr2(function(x) {
836+ return function(acc) {
837+ return append3(f(x))(acc);
838+ };
839+ })(mempty2);
840+ };
841+ };
842+ };
843+ var foldableArray = {
844+ foldr: foldrArray,
845+ foldl: foldlArray,
846+ foldMap: function(dictMonoid) {
847+ return foldMapDefaultR(foldableArray)(dictMonoid);
848+ }
849+ };
850+
851+ // output/Data.Function.Uncurried/foreign.js
852+ var runFn2 = function(fn) {
853+ return function(a) {
854+ return function(b) {
855+ return fn(a, b);
856+ };
857+ };
858+ };
859+ var runFn3 = function(fn) {
860+ return function(a) {
861+ return function(b) {
862+ return function(c) {
863+ return fn(a, b, c);
864+ };
865+ };
866+ };
867+ };
868+ var runFn4 = function(fn) {
869+ return function(a) {
870+ return function(b) {
871+ return function(c) {
872+ return function(d) {
873+ return fn(a, b, c, d);
874+ };
875+ };
876+ };
877+ };
878+ };
879+
880+ // output/Data.Array/index.js
881+ var uncons = /* @__PURE__ */ function() {
882+ return runFn3(unconsImpl)($$const(Nothing.value))(function(x) {
883+ return function(xs) {
884+ return new Just({
885+ head: x,
886+ tail: xs
887+ });
888+ };
889+ });
890+ }();
891+ var singleton2 = function(a) {
892+ return [a];
893+ };
894+ var partition = /* @__PURE__ */ runFn2(partitionImpl);
895+ var $$null = function(xs) {
896+ return length(xs) === 0;
897+ };
898+ var index = /* @__PURE__ */ function() {
899+ return runFn4(indexImpl)(Just.create)(Nothing.value);
900+ }();
901+ var filter = /* @__PURE__ */ runFn2(filterImpl);
902+ var concatMap = /* @__PURE__ */ flip(/* @__PURE__ */ bind(bindArray));
903+ var mapMaybe = function(f) {
904+ return concatMap(function() {
905+ var $189 = maybe([])(singleton2);
906+ return function($190) {
907+ return $189(f($190));
908+ };
909+ }());
910+ };
911+
912+ // output/Foreign.Object.ST/foreign.js
913+ function poke2(k) {
914+ return function(v) {
915+ return function(m) {
916+ return function() {
917+ m[k] = v;
918+ return m;
919+ };
920+ };
921+ };
922+ }
923+
924+ // output/Foreign.Object/index.js
925+ var thawST = _copyST;
926+ var mutate = function(f) {
927+ return function(m) {
928+ return runST(function __do2() {
929+ var s = thawST(m)();
930+ f(s)();
931+ return s;
932+ });
933+ };
934+ };
935+ var insert = function(k) {
936+ return function(v) {
937+ return mutate(poke2(k)(v));
938+ };
939+ };
940+
941+ // output/Data.Int/foreign.js
942+ var toNumber = function(n) {
943+ return n;
944+ };
945+
946+ // output/Data.String.CodePoints/foreign.js
947+ var hasArrayFrom = typeof Array.from === "function";
948+ var hasStringIterator = typeof Symbol !== "undefined" && Symbol != null && typeof Symbol.iterator !== "undefined" && typeof String.prototype[Symbol.iterator] === "function";
949+ var hasFromCodePoint = typeof String.prototype.fromCodePoint === "function";
950+ var hasCodePointAt = typeof String.prototype.codePointAt === "function";
951+
952+ // output/Data.String.Common/foreign.js
953+ var split = function(sep) {
954+ return function(s) {
955+ return s.split(sep);
956+ };
957+ };
958+
959+ // output/Data.String.Common/index.js
960+ var $$null2 = function(s) {
961+ return s === "";
962+ };
963+
964+ // output/Data.Argonaut.Encode.Encoders/index.js
965+ var encodeNumber = id;
966+ var encodeInt = function($53) {
967+ return id(toNumber($53));
968+ };
969+
970+ // output/Record/index.js
971+ var get = function(dictIsSymbol) {
972+ var reflectSymbol2 = reflectSymbol(dictIsSymbol);
973+ return function() {
974+ return function(l) {
975+ return function(r) {
976+ return unsafeGet(reflectSymbol2(l))(r);
977+ };
978+ };
979+ };
980+ };
981+ var $$delete3 = function(dictIsSymbol) {
982+ var reflectSymbol2 = reflectSymbol(dictIsSymbol);
983+ return function() {
984+ return function() {
985+ return function(l) {
986+ return function(r) {
987+ return unsafeDelete(reflectSymbol2(l))(r);
988+ };
989+ };
990+ };
991+ };
992+ };
993+
994+ // output/Data.Argonaut.Encode.Class/index.js
995+ var gEncodeJsonNil = {
996+ gEncodeJson: function(v) {
997+ return function(v1) {
998+ return empty;
999+ };
1000+ }
1001+ };
1002+ var gEncodeJson = function(dict) {
1003+ return dict.gEncodeJson;
1004+ };
1005+ var encodeRecord = function(dictGEncodeJson) {
1006+ var gEncodeJson1 = gEncodeJson(dictGEncodeJson);
1007+ return function() {
1008+ return {
1009+ encodeJson: function(rec) {
1010+ return id(gEncodeJson1(rec)($$Proxy.value));
1011+ }
1012+ };
1013+ };
1014+ };
1015+ var encodeJsonJNumber = {
1016+ encodeJson: encodeNumber
1017+ };
1018+ var encodeJsonInt = {
1019+ encodeJson: encodeInt
1020+ };
1021+ var encodeJson = function(dict) {
1022+ return dict.encodeJson;
1023+ };
1024+ var gEncodeJsonCons = function(dictEncodeJson) {
1025+ var encodeJson1 = encodeJson(dictEncodeJson);
1026+ return function(dictGEncodeJson) {
1027+ var gEncodeJson1 = gEncodeJson(dictGEncodeJson);
1028+ return function(dictIsSymbol) {
1029+ var reflectSymbol2 = reflectSymbol(dictIsSymbol);
1030+ var get2 = get(dictIsSymbol)();
1031+ return function() {
1032+ return {
1033+ gEncodeJson: function(row) {
1034+ return function(v) {
1035+ return insert(reflectSymbol2($$Proxy.value))(encodeJson1(get2($$Proxy.value)(row)))(gEncodeJson1(row)($$Proxy.value));
1036+ };
1037+ }
1038+ };
1039+ };
1040+ };
1041+ };
1042+ };
1043+
1044+ // output/Effect.Console/foreign.js
1045+ var log2 = function(s) {
1046+ return function() {
1047+ console.log(s);
1048+ };
1049+ };
1050+
1051+ // output/Bun.Request/foreign.js
1052+ function method(req) {
1053+ return req.method;
1054+ }
1055+ function url(req) {
1056+ return req.url;
1057+ }
1058+
1059+ // output/Bun.Response/foreign.js
1060+ function json2(j) {
1061+ return function(options) {
1062+ return Response.json(j, options);
1063+ };
1064+ }
1065+ function string(s) {
1066+ return function(options) {
1067+ return new Response(s, options);
1068+ };
1069+ }
1070+
1071+ // output/Data.URL/foreign.js
1072+ var fromStringImpl2 = (s) => {
1073+ try {
1074+ return new URL(s);
1075+ } catch {
1076+ return null;
1077+ }
1078+ };
1079+ var pathnameImpl = (u) => u.pathname;
1080+
1081+ // output/Data.Compactable/index.js
1082+ var $$void3 = /* @__PURE__ */ $$void(functorST);
1083+ var pure1 = /* @__PURE__ */ pure(applicativeST);
1084+ var apply2 = /* @__PURE__ */ apply(applyST);
1085+ var map4 = /* @__PURE__ */ map(functorST);
1086+ var compactableMaybe = {
1087+ compact: /* @__PURE__ */ join(bindMaybe),
1088+ separate: function(v) {
1089+ if (v instanceof Nothing) {
1090+ return {
1091+ left: Nothing.value,
1092+ right: Nothing.value
1093+ };
1094+ }
1095+ ;
1096+ if (v instanceof Just) {
1097+ if (v.value0 instanceof Left) {
1098+ return {
1099+ left: new Just(v.value0.value0),
1100+ right: Nothing.value
1101+ };
1102+ }
1103+ ;
1104+ if (v.value0 instanceof Right) {
1105+ return {
1106+ left: Nothing.value,
1107+ right: new Just(v.value0.value0)
1108+ };
1109+ }
1110+ ;
1111+ throw new Error("Failed pattern match at Data.Compactable (line 91, column 23 - line 93, column 48): " + [v.value0.constructor.name]);
1112+ }
1113+ ;
1114+ throw new Error("Failed pattern match at Data.Compactable (line 87, column 1 - line 93, column 48): " + [v.constructor.name]);
1115+ }
1116+ };
1117+ var compactableArray = {
1118+ compact: function(xs) {
1119+ return function __do2() {
1120+ var result = newSTArray();
1121+ var iter = iterator(function(v) {
1122+ return index(xs)(v);
1123+ })();
1124+ iterate(iter)(function($108) {
1125+ return $$void3(function(v) {
1126+ if (v instanceof Nothing) {
1127+ return pure1(0);
1128+ }
1129+ ;
1130+ if (v instanceof Just) {
1131+ return push(v.value0)(result);
1132+ }
1133+ ;
1134+ throw new Error("Failed pattern match at Data.Compactable (line 111, column 34 - line 113, column 35): " + [v.constructor.name]);
1135+ }($108));
1136+ })();
1137+ return unsafeFreeze(result)();
1138+ }();
1139+ },
1140+ separate: function(xs) {
1141+ return function __do2() {
1142+ var ls = newSTArray();
1143+ var rs = newSTArray();
1144+ var iter = iterator(function(v) {
1145+ return index(xs)(v);
1146+ })();
1147+ iterate(iter)(function($109) {
1148+ return $$void3(function(v) {
1149+ if (v instanceof Left) {
1150+ return push(v.value0)(ls);
1151+ }
1152+ ;
1153+ if (v instanceof Right) {
1154+ return push(v.value0)(rs);
1155+ }
1156+ ;
1157+ throw new Error("Failed pattern match at Data.Compactable (line 122, column 34 - line 124, column 31): " + [v.constructor.name]);
1158+ }($109));
1159+ })();
1160+ return apply2(map4(function(v) {
1161+ return function(v1) {
1162+ return {
1163+ left: v,
1164+ right: v1
1165+ };
1166+ };
1167+ })(unsafeFreeze(ls)))(unsafeFreeze(rs))();
1168+ }();
1169+ }
1170+ };
1171+
1172+ // output/Data.Filterable/index.js
1173+ var append2 = /* @__PURE__ */ append(semigroupArray);
1174+ var foldl2 = /* @__PURE__ */ foldl(foldableArray);
1175+ var partitionMap = function(dict) {
1176+ return dict.partitionMap;
1177+ };
1178+ var maybeBool = function(p) {
1179+ return function(x) {
1180+ var $66 = p(x);
1181+ if ($66) {
1182+ return new Just(x);
1183+ }
1184+ ;
1185+ return Nothing.value;
1186+ };
1187+ };
1188+ var filterableArray = {
1189+ partitionMap: function(p) {
1190+ var go = function(acc) {
1191+ return function(x) {
1192+ var v = p(x);
1193+ if (v instanceof Left) {
1194+ return {
1195+ right: acc.right,
1196+ left: append2(acc.left)([v.value0])
1197+ };
1198+ }
1199+ ;
1200+ if (v instanceof Right) {
1201+ return {
1202+ left: acc.left,
1203+ right: append2(acc.right)([v.value0])
1204+ };
1205+ }
1206+ ;
1207+ throw new Error("Failed pattern match at Data.Filterable (line 149, column 16 - line 151, column 50): " + [v.constructor.name]);
1208+ };
1209+ };
1210+ return foldl2(go)({
1211+ left: [],
1212+ right: []
1213+ });
1214+ },
1215+ partition,
1216+ filterMap: mapMaybe,
1217+ filter,
1218+ Compactable0: function() {
1219+ return compactableArray;
1220+ },
1221+ Functor1: function() {
1222+ return functorArray;
1223+ }
1224+ };
1225+ var filterMap = function(dict) {
1226+ return dict.filterMap;
1227+ };
1228+ var filterDefault = function(dictFilterable) {
1229+ var $121 = filterMap(dictFilterable);
1230+ return function($122) {
1231+ return $121(maybeBool($122));
1232+ };
1233+ };
1234+ var filter3 = function(dict) {
1235+ return dict.filter;
1236+ };
1237+ var eitherBool = function(p) {
1238+ return function(x) {
1239+ var $84 = p(x);
1240+ if ($84) {
1241+ return new Right(x);
1242+ }
1243+ ;
1244+ return new Left(x);
1245+ };
1246+ };
1247+ var partitionDefault = function(dictFilterable) {
1248+ var partitionMap1 = partitionMap(dictFilterable);
1249+ return function(p) {
1250+ return function(xs) {
1251+ var o = partitionMap1(eitherBool(p))(xs);
1252+ return {
1253+ no: o.left,
1254+ yes: o.right
1255+ };
1256+ };
1257+ };
1258+ };
1259+ var filterableMaybe = {
1260+ partitionMap: function(v) {
1261+ return function(v1) {
1262+ if (v1 instanceof Nothing) {
1263+ return {
1264+ left: Nothing.value,
1265+ right: Nothing.value
1266+ };
1267+ }
1268+ ;
1269+ if (v1 instanceof Just) {
1270+ var v2 = v(v1.value0);
1271+ if (v2 instanceof Left) {
1272+ return {
1273+ left: new Just(v2.value0),
1274+ right: Nothing.value
1275+ };
1276+ }
1277+ ;
1278+ if (v2 instanceof Right) {
1279+ return {
1280+ left: Nothing.value,
1281+ right: new Just(v2.value0)
1282+ };
1283+ }
1284+ ;
1285+ throw new Error("Failed pattern match at Data.Filterable (line 161, column 29 - line 163, column 48): " + [v2.constructor.name]);
1286+ }
1287+ ;
1288+ throw new Error("Failed pattern match at Data.Filterable (line 159, column 1 - line 169, column 29): " + [v.constructor.name, v1.constructor.name]);
1289+ };
1290+ },
1291+ partition: function(p) {
1292+ return partitionDefault(filterableMaybe)(p);
1293+ },
1294+ filterMap: /* @__PURE__ */ bindFlipped(bindMaybe),
1295+ filter: function(p) {
1296+ return filterDefault(filterableMaybe)(p);
1297+ },
1298+ Compactable0: function() {
1299+ return compactableMaybe;
1300+ },
1301+ Functor1: function() {
1302+ return functorMaybe;
1303+ }
1304+ };
1305+
1306+ // output/Data.Nullable/foreign.js
1307+ function nullable(a, r, f) {
1308+ return a == null ? r : f(a);
1309+ }
1310+
1311+ // output/Data.Nullable/index.js
1312+ var toMaybe = function(n) {
1313+ return nullable(n, Nothing.value, Just.create);
1314+ };
1315+
1316+ // output/Data.String.Utils/foreign.js
1317+ function startsWithImpl(searchString, s) {
1318+ return s.startsWith(searchString);
1319+ }
1320+
1321+ // output/Data.String.Utils/index.js
1322+ var startsWith = function(searchString) {
1323+ return function(s) {
1324+ return startsWithImpl(searchString, s);
1325+ };
1326+ };
1327+
1328+ // output/Foreign/foreign.js
1329+ var isArray = Array.isArray || function(value) {
1330+ return Object.prototype.toString.call(value) === "[object Array]";
1331+ };
1332+
1333+ // output/Data.URL/index.js
1334+ var filter4 = /* @__PURE__ */ filter3(filterableMaybe);
1335+ var wrap2 = /* @__PURE__ */ wrap();
1336+ var filter1 = /* @__PURE__ */ filter3(filterableArray);
1337+ var PathEmpty = /* @__PURE__ */ function() {
1338+ function PathEmpty2() {
1339+ }
1340+ ;
1341+ PathEmpty2.value = new PathEmpty2();
1342+ return PathEmpty2;
1343+ }();
1344+ var PathAbsolute = /* @__PURE__ */ function() {
1345+ function PathAbsolute2(value0) {
1346+ this.value0 = value0;
1347+ }
1348+ ;
1349+ PathAbsolute2.create = function(value0) {
1350+ return new PathAbsolute2(value0);
1351+ };
1352+ return PathAbsolute2;
1353+ }();
1354+ var PathRelative = /* @__PURE__ */ function() {
1355+ function PathRelative2(value0) {
1356+ this.value0 = value0;
1357+ }
1358+ ;
1359+ PathRelative2.create = function(value0) {
1360+ return new PathRelative2(value0);
1361+ };
1362+ return PathRelative2;
1363+ }();
1364+ var pathFromString = function(s) {
1365+ var segments = function() {
1366+ var $235 = filter1(function($238) {
1367+ return !$$null2($238);
1368+ });
1369+ var $236 = split(wrap2("/"));
1370+ return function($237) {
1371+ return $235($236($237));
1372+ };
1373+ }();
1374+ return maybe(PathEmpty.value)(function() {
1375+ var $203 = startsWith("/")(s);
1376+ if ($203) {
1377+ return PathAbsolute.create;
1378+ }
1379+ ;
1380+ return PathRelative.create;
1381+ }())(filter4(function($239) {
1382+ return !$$null($239);
1383+ })(new Just(segments(s))));
1384+ };
1385+ var path = function($240) {
1386+ return pathFromString(pathnameImpl($240));
1387+ };
1388+ var fromString2 = function($255) {
1389+ return toMaybe(fromStringImpl2($255));
1390+ };
1391+
1392+ // output/PureStack.Router/index.js
1393+ var bind2 = /* @__PURE__ */ bind(bindMaybe);
1394+ var pure2 = /* @__PURE__ */ pure(applicativeEffect);
1395+ var discard2 = /* @__PURE__ */ discard(discardUnit)(bindMaybe);
1396+ var eq12 = /* @__PURE__ */ eq(/* @__PURE__ */ eqArray(eqString));
1397+ var pure12 = /* @__PURE__ */ pure(applicativeMaybe);
1398+ var toResponseRecord = function(dictEncodeJson) {
1399+ var encodeJson2 = encodeJson(dictEncodeJson);
1400+ return {
1401+ toResponse: function(rec) {
1402+ return function(opts) {
1403+ return json2(encodeJson2(rec))(opts);
1404+ };
1405+ }
1406+ };
1407+ };
1408+ var toResponse = function(dict) {
1409+ return dict.toResponse;
1410+ };
1411+ var runAPI = function(dict) {
1412+ return dict.runAPI;
1413+ };
1414+ var routeFromRequest = function(req) {
1415+ return {
1416+ verb: method(req),
1417+ path: function() {
1418+ var v = fromString2(url(req));
1419+ if (v instanceof Nothing) {
1420+ return [];
1421+ }
1422+ ;
1423+ if (v instanceof Just) {
1424+ var v1 = path(v.value0);
1425+ if (v1 instanceof PathEmpty) {
1426+ return [];
1427+ }
1428+ ;
1429+ if (v1 instanceof PathAbsolute) {
1430+ return v1.value0;
1431+ }
1432+ ;
1433+ if (v1 instanceof PathRelative) {
1434+ return v1.value0;
1435+ }
1436+ ;
1437+ throw new Error("Failed pattern match at PureStack.Router (line 68, column 19 - line 71, column 32): " + [v1.constructor.name]);
1438+ }
1439+ ;
1440+ throw new Error("Failed pattern match at PureStack.Router (line 66, column 11 - line 71, column 32): " + [v.constructor.name]);
1441+ }()
1442+ };
1443+ };
1444+ var run3 = function() {
1445+ return function(dictRunAPI) {
1446+ var runAPI1 = runAPI(dictRunAPI);
1447+ return function(handlers) {
1448+ return function(req) {
1449+ return runAPI1(handlers)(routeFromRequest(req))(req);
1450+ };
1451+ };
1452+ };
1453+ };
1454+ var parseRoute = function(dict) {
1455+ return dict.parseRoute;
1456+ };
1457+ var runAPICons = function(dictParseRoute) {
1458+ var parseRoute1 = parseRoute(dictParseRoute);
1459+ return function() {
1460+ return function(dictRunAPI) {
1461+ var runAPI1 = runAPI(dictRunAPI);
1462+ return function(dictIsSymbol) {
1463+ var $$delete4 = $$delete3(dictIsSymbol)()();
1464+ var get2 = get(dictIsSymbol)();
1465+ return function() {
1466+ return function() {
1467+ return {
1468+ runAPI: function(handlers) {
1469+ return function(v) {
1470+ return function(req) {
1471+ var v1 = parseRoute1({
1472+ path: v.path,
1473+ verb: v.verb
1474+ });
1475+ if (v1 instanceof Nothing) {
1476+ return runAPI1($$delete4($$Proxy.value)(handlers))(v)(req);
1477+ }
1478+ ;
1479+ if (v1 instanceof Just) {
1480+ return v1.value0(get2($$Proxy.value)(handlers))(req);
1481+ }
1482+ ;
1483+ throw new Error("Failed pattern match at PureStack.Router (line 150, column 5 - line 152, column 59): " + [v1.constructor.name]);
1484+ };
1485+ };
1486+ }
1487+ };
1488+ };
1489+ };
1490+ };
1491+ };
1492+ };
1493+ };
1494+ var notFound = /* @__PURE__ */ string("")({
1495+ status: 404,
1496+ statusText: "Not Found",
1497+ headers: []
1498+ });
1499+ var runAPINilRow = {
1500+ runAPI: function(v) {
1501+ return function(v1) {
1502+ return function(v2) {
1503+ return pure2(notFound);
1504+ };
1505+ };
1506+ }
1507+ };
1508+ var assert = function(dictApplicative) {
1509+ var pure22 = pure(dictApplicative);
1510+ return function(dictPlus) {
1511+ var empty4 = empty2(dictPlus);
1512+ return function(v) {
1513+ if (v) {
1514+ return pure22(unit);
1515+ }
1516+ ;
1517+ if (!v) {
1518+ return empty4;
1519+ }
1520+ ;
1521+ throw new Error("Failed pattern match at PureStack.Router (line 130, column 1 - line 130, column 65): " + [v.constructor.name]);
1522+ };
1523+ };
1524+ };
1525+ var assert1 = /* @__PURE__ */ assert(applicativeMaybe)(plusMaybe);
1526+ var parseRoute$div = function(dictParseRoute) {
1527+ var parseRoute1 = parseRoute(dictParseRoute);
1528+ return function(dictIsSymbol) {
1529+ var reflectSymbol2 = reflectSymbol(dictIsSymbol);
1530+ return {
1531+ parseRoute: function(v) {
1532+ return bind2(uncons(v.path))(function(v1) {
1533+ return discard2(assert1(v1.head === reflectSymbol2($$Proxy.value)))(function() {
1534+ return parseRoute1({
1535+ path: v1.tail,
1536+ verb: v.verb
1537+ });
1538+ });
1539+ });
1540+ }
1541+ };
1542+ };
1543+ };
1544+ var parseRouteGETEffect = function(dictToResponse) {
1545+ var toResponse1 = toResponse(dictToResponse);
1546+ return {
1547+ parseRoute: function(v) {
1548+ return discard2(assert1(v.verb === "GET"))(function() {
1549+ return discard2(assert1(eq12(v.path)([])))(function() {
1550+ return pure12(function(handler) {
1551+ return function(_req) {
1552+ return function __do2() {
1553+ var resp = handler();
1554+ return toResponse1(resp)({
1555+ status: 200,
1556+ statusText: "OK",
1557+ headers: []
1558+ });
1559+ };
1560+ };
1561+ });
1562+ });
1563+ });
1564+ }
1565+ };
1566+ };
1567+ var parseRoutePOSTUnitEffect = function(dictToResponse) {
1568+ var toResponse1 = toResponse(dictToResponse);
1569+ return {
1570+ parseRoute: function(v) {
1571+ return discard2(assert1(eq12(v.path)([])))(function() {
1572+ return discard2(assert1(v.verb === "POST"))(function() {
1573+ return pure12(function(handler) {
1574+ return function(req) {
1575+ return function __do2() {
1576+ var resp = handler();
1577+ return toResponse1(resp)({
1578+ status: 200,
1579+ statusText: "OK",
1580+ headers: []
1581+ });
1582+ };
1583+ };
1584+ });
1585+ });
1586+ });
1587+ }
1588+ };
1589+ };
1590+
1591+ // output/Main/index.js
1592+ var gEncodeJsonCons2 = /* @__PURE__ */ gEncodeJsonCons(encodeJsonInt);
1593+ var aIsSymbol = {
1594+ reflectSymbol: function() {
1595+ return "a";
1596+ }
1597+ };
1598+ var fooIsSymbol = {
1599+ reflectSymbol: function() {
1600+ return "foo";
1601+ }
1602+ };
1603+ var barIsSymbol = {
1604+ reflectSymbol: function() {
1605+ return "bar";
1606+ }
1607+ };
1608+ var run4 = /* @__PURE__ */ run3()(/* @__PURE__ */ runAPICons(/* @__PURE__ */ parseRoute$div(/* @__PURE__ */ parseRoute$div(/* @__PURE__ */ parseRoutePOSTUnitEffect(/* @__PURE__ */ toResponseRecord(/* @__PURE__ */ encodeRecord(/* @__PURE__ */ gEncodeJsonCons2(gEncodeJsonNil)(aIsSymbol)())())))({
1609+ reflectSymbol: function() {
1610+ return "qux";
1611+ }
1612+ }))(fooIsSymbol))()(/* @__PURE__ */ runAPICons(/* @__PURE__ */ parseRoute$div(/* @__PURE__ */ parseRoute$div(/* @__PURE__ */ parseRoute$div(/* @__PURE__ */ parseRouteGETEffect(/* @__PURE__ */ toResponseRecord(/* @__PURE__ */ encodeRecord(/* @__PURE__ */ gEncodeJsonCons2(/* @__PURE__ */ gEncodeJsonCons(encodeJsonJNumber)(gEncodeJsonNil)({
1613+ reflectSymbol: function() {
1614+ return "b";
1615+ }
1616+ })())(aIsSymbol)())())))(fooIsSymbol))(barIsSymbol))(fooIsSymbol))()(runAPINilRow)(fooIsSymbol)()())(barIsSymbol)()());
1617+ var pure3 = /* @__PURE__ */ pure(applicativeEffect);
1618+ var main = function __do() {
1619+ log2("\u{1F35D}")();
1620+ return serve(run4({
1621+ foo: pure3({
1622+ a: 1,
1623+ b: 1
1624+ }),
1625+ bar: pure3({
1626+ a: 8
1627+ })
1628+ }))();
1629+ };
1630+
1631+ // <stdin>
1632+ main();
1633+})();
spago.dhall+2−16
@@ -1,32 +1,18 @@
11{ name = "my-project"
22, dependencies =
3− [ "aff"
4− , "aff-promise"
3+ [ "aff-promise"
54 , "argonaut"
65 , "arrays"
76 , "console"
87 , "control"
9− , "datetime"
108 , "effect"
11− , "either"
12− , "foldable-traversable"
13− , "foreign-object"
14− , "formatters"
15− , "integers"
16− , "lists"
179 , "maybe"
18− , "now"
19− , "numbers"
20− , "ordered-collections"
21− , "parsing"
2210 , "prelude"
23− , "profunctor-lenses"
2411 , "record"
2512 , "run"
26− , "strings"
27− , "transformers"
2813 , "tuples"
2914 , "typelevel-prelude"
15+ , "unsafe-coerce"
3016 , "url-immutable"
3117 ]
3218, packages = ./packages.dhall
src/Bun/Request.js+2−6
@@ -1,5 +1,5 @@
1−export function jsonPromise(req) {
2− return req.json()
1+export function json(req) {
2+ return req.json
33}
44
55export function method(req) {
@@ -9,7 +9,3 @@ export function method(req) {
99export function url(req) {
1010 return req.url
1111}
12−
13−export function headers(req) {
14− return Object.fromEntries(req.headers.entries());
15−}
src/Bun/Request.purs+2−18
@@ -1,28 +1,12 @@
1−module Bun.Request
2− ( Request
3− , method
4− , url
5− , json
6− , headers
7− ) where
8−
9−import Prelude
1+module Bun.Request where
102
113import Control.Promise (Promise)
12−import Control.Promise as Promise
134import Data.Argonaut (Json)
14−import Effect.Aff (Aff)
15−import Foreign.Object (Object)
165
176foreign import data Request :: Type
187
19−foreign import jsonPromise :: Request -> Promise Json
20−
21−json :: Request -> Aff Json
22−json = jsonPromise >>> Promise.toAff
8+foreign import json :: Request -> Promise Json
239
2410foreign import method :: Request -> String
2511
2612foreign import url :: Request -> String
27−
28−foreign import headers :: Request -> Object String
src/Bun/Response.js−23
@@ -10,26 +10,3 @@ export function string(s) {
1010 return new Response(s, options)
1111 }
1212}
13−
14−
15−export function stream(s) {
16− return function(options) {
17− return new Response(s, options)
18− }
19−}
20−
21−export function body(resp) {
22− return resp.body
23−}
24−
25−export function status(resp) {
26− return resp.status
27−}
28−
29−export function statusText(resp) {
30− return resp.statusText
31−}
32−
33−export function headers(resp) {
34− return Object.fromEntries(resp.headers.entries());
35−}
src/Bun/Response.purs+3−9
@@ -1,18 +1,12 @@
11module Bun.Response where
22
33import Data.Argonaut (Json)
4−import Foreign.Object (Object)
4+import Data.Tuple.Nested (type (/\))
5+import Effect (Effect)
56
67foreign import data Response :: Type
7−foreign import data ReadableStream :: Type
88
9−type Options = { status :: Int, statusText :: String, headers :: Object String }
9+type Options = { status :: Int, statusText :: String, headers :: Array (String /\ String) }
1010
1111foreign import json :: Json -> Options -> Response
1212foreign import string :: String -> Options -> Response
13−foreign import stream :: ReadableStream -> Options -> Response
14−foreign import body :: Response -> ReadableStream
15−foreign import headers :: Response -> Object String
16−foreign import status :: Response -> Int
17−foreign import statusText :: Response -> String
18−
src/Bun/Server.js+1−1
@@ -1,4 +1,4 @@
1−export function serve_(f) {
1+export function serve(f) {
22 return function() {
33 return Bun.serve({
44 fetch(req) {
src/Bun/Server.purs+1−7
@@ -4,12 +4,6 @@ import Prelude
44
55import Bun.Request (Request)
66import Bun.Response (Response)
7−import Control.Promise (Promise)
8−import Control.Promise as Promise
97import Effect (Effect)
10−import Effect.Aff (Aff)
118
12−foreign import serve_ :: (Request -> Effect (Promise Response)) -> Effect Unit
13−
14−serve :: (Request -> Aff Response) -> Effect Unit
15−serve f = serve_ (\req -> Promise.fromAff (f req))
9+foreign import serve :: (Request -> Effect Response) -> Effect Unit
src/Main.purs+5−23
@@ -3,35 +3,17 @@ module Main where
33import Prelude
44
55import Bun.Server as Bun
6−import Data.Maybe (Maybe)
76import Effect (Effect)
8−import Effect.Aff (Aff)
97import Effect.Console (log)
10−import PureStack.Route (type (/), GET, Headers(..), Middleware, POST)
11−import PureStack.Route as Router
12−import PureStack.Server as Server
13−import Run (AFF, Run(..), runBaseAff)
14−import Type.Row (type (+))
15−
16−type Foo = { a :: String, b :: Maybe Int, c :: Array Number }
8+import PureStack.Router (type (/), GET, POST)
9+import PureStack.Router as Router
1710
1811type API =
19− ( foo :: "foo" / "bar" / Foo / GET Unit { a :: Int, b :: Number, c :: Foo }
20− , bar :: "foo" / Middleware "auth" / "qux" / POST (Headers { foo :: String } Unit) { a :: Int, s :: String }
21− , deep ::
22− "deep" /
23− ( something :: "something" / GET Unit { a :: String }
24− )
12+ ( foo :: "foo" / "bar" / "foo" / GET { a :: Int, b :: Number }
13+ , bar :: "foo" / "qux" / POST Unit { a :: Int }
2514 )
2615
2716main :: Effect Unit
2817main = do
2918 log "🍝"
30− Bun.serve $ Server.run @API identity
31− { handlers:
32− { foo: \x -> pure { a: 1, b: 1.0, c: x }
33− , bar: \i (Headers x _) -> pure { a: 8, s: x.foo }
34− , deep: { something: pure { a: "something" } }
35− }
36− , middlewares: { auth: \req -> pure 1 }
37− }
19+ Bun.serve $ Router.run @API { foo: pure { a: 1, b: 1.0 }, bar: pure { a: 8 } }
src/PureStack/Cookie.pursdeleted−57
@@ -1,57 +0,0 @@
1−-- | This module allows parsing and generating cookie headers. You'll generally use
2−-- | the `Cookie.new` function to create a cookie from a name/value pair and the
3−-- | `Cookie.set*` functions to set attributes on a cookie.
4−-- |
5−-- | `Cookie.stringify` generates the string representation of a cookie, suitable for
6−-- | writing to an HTTP header.
7−-- |
8−-- | `Cookie.parse` parses the string representation of a cookie, returning an
9−-- | `Either ParseError Cookie`.
10−-- |
11−-- | ```purescript
12−-- | import PureStack.Cookie as Cookie
13−-- |
14−-- | > Cookie.stringify $ Cookie.setSecure $ Cookie.new "key" "value"
15−-- | key=value; Secure
16−-- |
17−-- | > Cookie.parse "key=value; Secure"
18−-- | (Right { name: "key", value: "value", secure: true, ... })
19−-- | ```
20−module PureStack.Cookie
21− ( module PureStack.Cookie.Generator
22− , module PureStack.Cookie.Parser
23− , module PureStack.Cookie.Types
24− ) where
25−
26−import PureStack.Cookie.Generator (stringify)
27−import PureStack.Cookie.Parser (parse, parseMany)
28−import PureStack.Cookie.Types
29− ( Cookie
30− , SameSite(..)
31− , _domain
32− , _expires
33− , _httpOnly
34− , _maxAge
35− , _name
36− , _path
37− , _secure
38− , _value
39− , expire
40− , fromFields
41− , getDomain
42− , getExpires
43− , getHttpOnly
44− , getMaxAge
45− , getName
46− , getPath
47− , getSecure
48− , getValue
49− , new
50− , setDomain
51− , setExpires
52− , setHttpOnly
53− , setMaxAge
54− , setPath
55− , setSameSite
56− , setSecure
57− )
src/PureStack/Cookie/Formatter.pursdeleted−65
@@ -1,65 +0,0 @@
1−-- | This module is responsible for formatting and parsing the `Expires`
2−-- | attribute of a `Cookie`.
3−module PureStack.Cookie.Formatter
4− ( domainTag
5− , expiresTag
6− , formatDateTime
7− , httpOnlyTag
8− , maxAgeTag
9− , pathTag
10− , sameSiteTag
11− , secureTag
12− , unformatDateTime
13− ) where
14−
15−import Data.DateTime (DateTime)
16−import Data.Either (Either)
17−import Data.Formatter.DateTime (Formatter, FormatterCommand(..))
18−import Data.Formatter.DateTime as Formatter
19−import Data.List as List
20−
21−domainTag :: String
22−domainTag = "Domain"
23−
24−expiresTag :: String
25−expiresTag = "Expires"
26−
27−httpOnlyTag :: String
28−httpOnlyTag = "HttpOnly"
29−
30−maxAgeTag :: String
31−maxAgeTag = "Max-Age"
32−
33−pathTag :: String
34−pathTag = "Path"
35−
36−secureTag :: String
37−secureTag = "Secure"
38−
39−sameSiteTag :: String
40−sameSiteTag = "SameSite"
41−
42−expiresFormatter :: Formatter
43−expiresFormatter =
44− List.fromFoldable
45− [ DayOfWeekNameShort
46− , Placeholder ", "
47− , DayOfMonthTwoDigits
48− , Placeholder " "
49− , MonthShort
50− , Placeholder " "
51− , YearFull
52− , Placeholder " "
53− , Hours24
54− , Placeholder ":"
55− , MinutesTwoDigits
56− , Placeholder ":"
57− , SecondsTwoDigits
58− , Placeholder " GMT"
59− ]
60−
61−formatDateTime :: DateTime -> String
62−formatDateTime = Formatter.format expiresFormatter
63−
64−unformatDateTime :: String -> Either String DateTime
65−unformatDateTime = Formatter.unformat expiresFormatter
src/PureStack/Cookie/Generator.pursdeleted−62
@@ -1,62 +0,0 @@
1−-- | This module is responsible for generating the string representation
2−-- | of a `Cookie`.
3−module PureStack.Cookie.Generator
4− ( stringify
5− ) where
6−
7−import Prelude
8−import PureStack.Cookie.Formatter
9− ( domainTag
10− , expiresTag
11− , formatDateTime
12− , httpOnlyTag
13− , maxAgeTag
14− , pathTag
15− , sameSiteTag
16− , secureTag
17− )
18−import PureStack.Cookie.Types
19− ( Cookie
20− , getDomain
21− , getExpires
22− , getHttpOnly
23− , getMaxAge
24− , getName
25− , getPath
26− , getSameSite
27− , getSecure
28− , getValue
29− )
30−import Data.Array (catMaybes)
31−import Data.Foldable (intercalate)
32−import Data.Maybe (Maybe(..))
33−
34−-- | Return the `String` representation of a `Cookie`.
35−-- |
36−-- | ```purescript
37−-- | > Generator.stringify $ Cookie.setSecure $ Cookie.new "key" "value"
38−-- | key=value; Secure
39−-- | ```
40−stringify :: Cookie -> String
41−stringify cookie =
42− intercalate "; "
43− $ catMaybes
44− [ attr (getName cookie) $ Just (getValue cookie)
45− , attr domainTag $ getDomain cookie
46− , attr pathTag $ getPath cookie
47− , attr expiresTag $ formatDateTime <$> getExpires cookie
48− , attr maxAgeTag $ show <$> getMaxAge cookie
49− , attr sameSiteTag $ show <$> getSameSite cookie
50− , flag secureTag $ getSecure cookie
51− , flag httpOnlyTag $ getHttpOnly cookie
52− ]
53−
54−attr :: String -> Maybe String -> Maybe String
55−attr name = case _ of
56− Nothing -> Nothing
57− Just value -> Just $ name <> "=" <> value
58−
59−flag :: String -> Boolean -> Maybe String
60−flag name = case _ of
61− false -> Nothing
62− true -> Just name
src/PureStack/Cookie/Parser.pursdeleted−128
@@ -1,128 +0,0 @@
1−-- | This module is responsible for parsing a string into an
2−-- | `Either ParseError Cookie`.
3−module PureStack.Cookie.Parser
4− ( parse
5− , parseMany
6− ) where
7−
8−import Prelude
9−
10−import Control.Alt ((<|>))
11−import Data.Array as Array
12−import Data.Either (Either(..))
13−import Data.Foldable (class Foldable, foldl)
14−import Data.Int as Int
15−import Data.List (List)
16−import Data.Maybe (Maybe(..))
17−import Data.String as String
18−import Parsing (ParseError, Parser, fail, runParser)
19−import Parsing.Combinators (many, sepBy)
20−import Parsing.String (eof, string)
21−import Parsing.String.Basic (noneOf)
22−import PureStack.Cookie.Formatter (domainTag, expiresTag, httpOnlyTag, maxAgeTag, pathTag, sameSiteTag, secureTag, unformatDateTime)
23−import PureStack.Cookie.Types (Cookie, SameSite(..))
24−import PureStack.Cookie.Types as Cookie
25−
26−type Attribute = Cookie -> Cookie
27−
28−dropSeperator :: Parser String Unit
29−dropSeperator = (string "; " $> unit) <|> (pure unit)
30−
31−asString :: forall f. Functor f => Foldable f => f Char -> String
32−asString = String.fromCodePointArray <<< Array.fromFoldable <<< map String.codePointFromChar
33−
34−stringWithout :: Array Char -> Parser String String
35−stringWithout = map asString <<< many <<< noneOf
36−
37−attributeValue :: Parser String String
38−attributeValue = stringWithout [ ';' ]
39−
40−whitespaceChars :: Array Char
41−whitespaceChars = [ ' ', '\n', '\r', '\t' ]
42−
43−parseDomain :: Parser String Attribute
44−parseDomain = do
45− domain <- (string $ domainTag <> "=") *> attributeValue
46− pure $ Cookie.setDomain domain
47−
48−parsePath :: Parser String Attribute
49−parsePath = do
50− path <- (string $ pathTag <> "=") *> attributeValue
51− pure $ Cookie.setPath path
52−
53−parseExpires :: Parser String Attribute
54−parseExpires = do
55− expiresString <- (string $ expiresTag <> "=") *> attributeValue
56− case unformatDateTime expiresString of
57− Left e -> fail e
58− Right expires -> pure $ Cookie.setExpires expires
59−
60−parseMaxAge :: Parser String Attribute
61−parseMaxAge = do
62− maxAgeString <- (string $ maxAgeTag <> "=") *> attributeValue
63− case Int.fromString maxAgeString of
64− Nothing -> fail "invalid integer"
65− Just maxAge -> pure $ Cookie.setMaxAge maxAge
66−
67−parseSecure :: Parser String Attribute
68−parseSecure = (string secureTag) $> Cookie.setSecure
69−
70−parseHttpOnly :: Parser String Attribute
71−parseHttpOnly = (string httpOnlyTag) $> Cookie.setHttpOnly
72−
73−parseSameSite :: Parser String Attribute
74−parseSameSite = do
75− sameSiteString <- (string $ sameSiteTag <> "=") *> attributeValue
76− case sameSiteString of
77− "Strict" -> pure $ Cookie.setSameSite Strict
78− "Lax" -> pure $ Cookie.setSameSite Lax
79− "None" -> pure $ Cookie.setSameSite None
80− val -> fail $ "unknown SiteSite value " <> val
81−
82−parseAttribute :: Parser String Attribute
83−parseAttribute =
84− parseDomain
85− <|> parsePath
86− <|> parseExpires
87− <|> parseMaxAge
88− <|> parseSecure
89− <|> parseHttpOnly
90− <|> parseSameSite
91−
92−parseSimpleCookie :: Parser String Cookie
93−parseSimpleCookie = do
94− name <- stringWithout ([ ';', ',', '=' ] <> whitespaceChars) <* string "="
95− value <- stringWithout ([ ';', ',' ] <> whitespaceChars)
96− pure $ Cookie.new name value
97−
98−parseCookie :: Parser String Cookie
99−parseCookie = do
100− cookie <- parseSimpleCookie <* dropSeperator
101− attributes <- sepBy parseAttribute (string "; ") <* eof
102− pure $ foldl (#) cookie attributes
103−
104−parseCookies :: Parser String (List Cookie)
105−parseCookies = sepBy parseSimpleCookie (string "; ") <* eof
106−
107−-- | Parses a `String` into an `Either ParseError Cookie`. This
108−-- | function is primarily intended to parse the `Set-Cookie`
109−-- | header on the client.
110−-- |
111−-- | ```purescript
112−-- | > Parser.parse "key=value; Secure"
113−-- | (Right { name: "key", value: "value", secure: true, ... })
114−-- | ```
115−parse :: String -> Either ParseError Cookie
116−parse = flip runParser parseCookie
117−
118−-- | Parses a `String` into an `Either ParseError (List Cookie)`.
119−-- | HTTP requests can include multiple cookies in a single
120−-- | `Cookie` header consisting of only name/value pairs. This
121−-- | function can be used to parse this header.
122−-- |
123−-- | ```purescript
124−-- | > parseMany "key1=value1; key2=value2"
125−-- | (Right ({ name: "key1", value: "value1", ... } : { name: "key2", value: "value2", ... } : Nil))
126−-- | ```
127−parseMany :: String -> Either ParseError (List Cookie)
128−parseMany = flip runParser parseCookies
src/PureStack/Cookie/Types.pursdeleted−189
@@ -1,189 +0,0 @@
1−-- | This module contains the `Cookie` type and functions for operating on data within it.
2−module PureStack.Cookie.Types
3− ( Cookie
4− , SameSite(..)
5− , _domain
6− , _expires
7− , _httpOnly
8− , _maxAge
9− , _name
10− , _path
11− , _secure
12− , _value
13− , expire
14− , fromFields
15− , getDomain
16− , getExpires
17− , getHttpOnly
18− , getMaxAge
19− , getName
20− , getPath
21− , getSameSite
22− , getSecure
23− , getValue
24− , new
25− , setDomain
26− , setExpires
27− , setHttpOnly
28− , setMaxAge
29− , setPath
30− , setSameSite
31− , setSecure
32− ) where
33−
34−import Prelude
35−import Data.DateTime (DateTime)
36−import Data.DateTime as DateTime
37−import Data.Either (Either(..))
38−import Data.Lens (Iso', Lens', iso)
39−import Data.Lens as Lens
40−import Data.Lens.Record (prop)
41−import Data.Maybe (Maybe(..))
42−import Data.Time.Duration (Days(..))
43−import Effect.Now (nowDateTime)
44−import Effect (Effect)
45−import Type.Prelude (Proxy(..))
46−
47−-- | Type representing a `Cookie`'s optional `SameSite` attribute.
48−data SameSite
49− = Strict
50− | Lax
51− | None
52−
53−derive instance eqSameSite :: Eq SameSite
54−
55−derive instance ordSameSite :: Ord SameSite
56−
57−instance showSameSite :: Show SameSite where
58− show :: SameSite -> String
59− show Strict = "Strict"
60− show Lax = "Lax"
61− show None = "None"
62−
63−type CookieFields =
64− { name :: String
65− , value :: String
66− , domain :: Maybe String
67− , path :: Maybe String
68− , expires :: Maybe DateTime
69− , maxAge :: Maybe Int
70− , sameSite :: Maybe SameSite
71− , secure :: Boolean
72− , httpOnly :: Boolean
73− }
74−
75−-- | The `Cookie` type
76−newtype Cookie = Cookie CookieFields
77−
78−derive newtype instance eqCookie :: Eq Cookie
79−
80−derive newtype instance ordCookie :: Ord Cookie
81−
82−derive newtype instance showCookie :: Show Cookie
83−
84−-- | The constructor for `Cookie`
85−new :: String -> String -> Cookie
86−new name value =
87− Cookie
88− { name
89− , value
90− , domain: Nothing
91− , path: Nothing
92− , expires: Nothing
93− , maxAge: Nothing
94− , sameSite: Nothing
95− , secure: false
96− , httpOnly: false
97− }
98−
99−fromFields :: CookieFields -> Cookie
100−fromFields = Cookie
101−
102−-- | Expire an existing `Cookie`. This sets the `Expires` attribute of
103−-- | the cookie to yesterday's date.
104−expire :: Cookie -> Effect (Either String Cookie)
105−expire cookie = do
106− now <- nowDateTime
107− let maybeDate = DateTime.adjust (Days $ -1.0) now
108−
109− case maybeDate of
110− Nothing -> pure $ Left "Invalid date"
111− Just yesterday -> pure $ Right $ setExpires yesterday cookie
112−
113−getDomain :: Cookie -> Maybe String
114−getDomain = Lens.view _domain
115−
116−getExpires :: Cookie -> Maybe DateTime
117−getExpires = Lens.view _expires
118−
119−getHttpOnly :: Cookie -> Boolean
120−getHttpOnly = Lens.view _httpOnly
121−
122−getMaxAge :: Cookie -> Maybe Int
123−getMaxAge = Lens.view _maxAge
124−
125−getName :: Cookie -> String
126−getName = Lens.view _name
127−
128−getPath :: Cookie -> Maybe String
129−getPath = Lens.view _path
130−
131−getSameSite :: Cookie -> Maybe SameSite
132−getSameSite = Lens.view _sameSite
133−
134−getSecure :: Cookie -> Boolean
135−getSecure = Lens.view _secure
136−
137−getValue :: Cookie -> String
138−getValue = Lens.view _value
139−
140−setDomain :: String -> Cookie -> Cookie
141−setDomain = Lens.setJust _domain
142−
143−setExpires :: DateTime -> Cookie -> Cookie
144−setExpires = Lens.setJust _expires
145−
146−setHttpOnly :: Cookie -> Cookie
147−setHttpOnly = Lens.set _httpOnly true
148−
149−setMaxAge :: Int -> Cookie -> Cookie
150−setMaxAge = Lens.setJust _maxAge
151−
152−setPath :: String -> Cookie -> Cookie
153−setPath = Lens.setJust _path
154−
155−setSameSite :: SameSite -> Cookie -> Cookie
156−setSameSite = Lens.setJust _sameSite
157−
158−setSecure :: Cookie -> Cookie
159−setSecure = Lens.set _secure true
160−
161−_Cookie :: Iso' Cookie CookieFields
162−_Cookie = iso (\(Cookie fields) -> fields) Cookie
163−
164−_domain :: Lens' Cookie (Maybe String)
165−_domain = _Cookie <<< prop (Proxy :: Proxy "domain")
166−
167−_expires :: Lens' Cookie (Maybe DateTime)
168−_expires = _Cookie <<< prop (Proxy :: Proxy "expires")
169−
170−_httpOnly :: Lens' Cookie Boolean
171−_httpOnly = _Cookie <<< prop (Proxy :: Proxy "httpOnly")
172−
173−_maxAge :: Lens' Cookie (Maybe Int)
174−_maxAge = _Cookie <<< prop (Proxy :: Proxy "maxAge")
175−
176−_name :: Lens' Cookie String
177−_name = _Cookie <<< prop (Proxy :: Proxy "name")
178−
179−_path :: Lens' Cookie (Maybe String)
180−_path = _Cookie <<< prop (Proxy :: Proxy "path")
181−
182−_sameSite :: Lens' Cookie (Maybe SameSite)
183−_sameSite = _Cookie <<< prop (Proxy :: Proxy "sameSite")
184−
185−_secure :: Lens' Cookie Boolean
186−_secure = _Cookie <<< prop (Proxy :: Proxy "secure")
187−
188−_value :: Lens' Cookie String
189−_value = _Cookie <<< prop (Proxy :: Proxy "value")
src/PureStack/Route.pursdeleted−55
@@ -1,55 +0,0 @@
1−module PureStack.Route
2− ( type (/)
3− , Slash
4− , HttpMethod
5− , class MethodName
6− , methodName
7− , GET
8− , POST
9− , PUT
10− , DELETE
11− , PATCH
12− , Headers(..)
13− , Middleware
14− ) where
15−
16−data HttpMethod
17−
18−-- | The `req` can only ever be `Unit`
19−foreign import data GET :: Type -> Type -> HttpMethod
20−foreign import data POST :: Type -> Type -> HttpMethod
21−foreign import data PUT :: Type -> Type -> HttpMethod
22−foreign import data DELETE :: Type -> Type -> HttpMethod
23−foreign import data PATCH :: Type -> Type -> HttpMethod
24−
25−class MethodName :: HttpMethod -> Constraint
26−class MethodName method where
27− methodName :: String
28−
29−instance MethodName (GET req resp) where
30− methodName = "GET"
31−
32−instance MethodName (POST req resp) where
33− methodName = "POST"
34−
35−instance MethodName (PUT req resp) where
36− methodName = "PUT"
37−
38−instance MethodName (DELETE req resp) where
39− methodName = "DELETE"
40−
41−instance MethodName (PATCH req resp) where
42− methodName = "PATCH"
43−
44−data Slash :: forall k1 k2. k1 -> k2 -> Type
45−data Slash x y
46−
47−-- | Operator for separating path pieces when specisying APIs.
48−-- | `Symbol`s are treated as constant path pieces.
49−-- | `Record`s are treated as query parameters. `Array`s are lists, `Maybe`s are optional query parameters.
50−-- | Other types are captured path pieces.
51−infixr 1 type Slash as /
52−
53−data Headers headers r = Headers headers r
54−
55−data Middleware tag
src/PureStack/Router.pursnew file+168
@@ -0,0 +1,168 @@
1+module PureStack.Router
2+ ( run
3+ , type (/)
4+ , class RunAPI
5+ , runAPI
6+ , Slash
7+ , GET
8+ , POST
9+ , PUT
10+ , DELETE
11+ , PATCH
12+ , class ParseRoute
13+ , parseRoute
14+ , class ToResponse
15+ , toResponse
16+ ) where
17+
18+import Prelude
19+import Record
20+
21+import Bun.Request (Request)
22+import Bun.Request as Request
23+import Bun.Response (Response)
24+import Bun.Response as Response
25+import Control.Alternative (class Plus, empty)
26+import Data.Argonaut (class EncodeJson, Json, encodeJson)
27+import Data.Array as Array
28+import Data.Maybe (Maybe(..))
29+import Data.Symbol (class IsSymbol, reflectSymbol)
30+import Data.URL (URL)
31+import Data.URL as URL
32+import Data.Unit (Unit)
33+import Effect (Effect)
34+import Effect.Class (liftEffect)
35+import Prim.Row as Row
36+import Prim.RowList (class RowToList)
37+import Prim.RowList as RowList
38+import Record as Record
39+import Type.Prelude (Proxy(..))
40+
41+data GET :: Type -> Type
42+data GET resp
43+
44+data POST :: Type -> Type -> Type
45+data POST req resp
46+
47+data PUT :: Type -> Type -> Type
48+data PUT req resp
49+
50+data DELETE :: Type -> Type -> Type
51+data DELETE req resp
52+
53+data PATCH :: Type -> Type -> Type
54+data PATCH req resp
55+
56+data Slash :: forall k1 k2. k1 -> k2 -> Type
57+data Slash x y
58+
59+infixr 6 type Slash as /
60+
61+type Route = { path :: Array String, verb :: String }
62+
63+routeFromRequest :: Request -> Route
64+routeFromRequest req =
65+ { verb: Request.method req
66+ , path: case URL.fromString (Request.url req) of
67+ Nothing -> []
68+ Just url -> case URL.path url of
69+ URL.PathEmpty -> []
70+ URL.PathAbsolute p -> p
71+ URL.PathRelative p -> p
72+
73+ }
74+
75+class ParseRoute :: forall k. k -> Type -> Constraint
76+class ParseRoute route handler | route -> handler where
77+ parseRoute :: Route -> Maybe (handler -> Request -> Effect Response)
78+
79+instance (ParseRoute rest handler, IsSymbol path) => ParseRoute (path / rest) handler where
80+ parseRoute { path, verb } = do
81+ { head: h, tail } <- Array.uncons path
82+ assert $ h == (reflectSymbol @path Proxy)
83+ parseRoute @rest { path: tail, verb: verb }
84+
85+else instance (ParseRoute rest handler, ParsePathPiece t) => ParseRoute (t / rest) (t -> handler) where
86+ parseRoute { path, verb } = do
87+ { head: h, tail } <- Array.uncons path
88+ t <- parsePathPiece @t h
89+ parseRoute @rest { path: tail, verb } <#> (\f handler req -> f (handler t) req)
90+
91+else instance ToResponse resp => ParseRoute (GET resp) (Effect resp) where
92+ parseRoute { path, verb } = do
93+ assert $ verb == "GET"
94+ assert $ path == []
95+ pure $ \handler _req -> do
96+ resp <- handler
97+ pure $ toResponse resp { status: 200, statusText: "OK", headers: [] }
98+
99+else instance (ToResponse resp) => ParseRoute (POST Unit resp) (Effect resp) where
100+ parseRoute { path, verb } = do
101+ assert $ path == []
102+ assert $ verb == "POST"
103+ pure $ \handler req -> do
104+ resp <- handler
105+ pure $ toResponse resp { status: 200, statusText: "OK", headers: [] }
106+
107+else instance (FromRequestBody req, ToResponse resp) => ParseRoute (POST req resp) (req -> Effect resp) where
108+ parseRoute { path, verb } = do
109+ assert $ path == []
110+ assert $ verb == "POST"
111+ pure $ \handler req -> do
112+ fromRequestBody req >>= case _ of
113+ Nothing -> pure $ Response.string "" { status: 400, statusText: "Bad Request", headers: [] }
114+ Just r -> do
115+ resp <- handler r
116+ pure $ toResponse resp { status: 200, statusText: "OK", headers: [] }
117+
118+class ToResponse r where
119+ toResponse :: r -> Response.Options -> Response
120+
121+instance EncodeJson (Record row) => ToResponse (Record row) where
122+ toResponse rec opts = Response.json (encodeJson rec) opts
123+
124+class FromRequestBody r where
125+ fromRequestBody :: Request -> Effect (Maybe r)
126+
127+class ParsePathPiece t where
128+ parsePathPiece :: String -> Maybe t
129+
130+assert :: forall m. Applicative m => Plus m => Boolean -> m Unit
131+assert true = pure unit
132+assert false = empty
133+
134+class RunAPI row list handlers | row -> handlers where
135+ runAPI :: Record handlers -> Route -> Request -> Effect Response
136+
137+instance RunAPI row RowList.Nil () where
138+ runAPI _ _ _ = pure notFound
139+
140+instance
141+ ( ParseRoute t handler
142+ , Row.Cons field t tail row
143+ , RunAPI row rest restHandlers
144+ , IsSymbol field
145+ , Row.Cons field handler restHandlers handlers
146+ , Row.Lacks field restHandlers
147+ ) =>
148+ RunAPI row (RowList.Cons field t rest) handlers where
149+ runAPI handlers route@{ path, verb } req =
150+ case parseRoute @t { path, verb } of
151+ Nothing -> runAPI @row @rest @restHandlers (Record.delete (Proxy @field) handlers) route req
152+ Just f -> f (Record.get (Proxy @field) handlers) req
153+
154+notFound :: Response
155+notFound = Response.string "" { status: 404, statusText: "Not Found", headers: [] }
156+
157+internalServerError :: Response
158+internalServerError = Response.string "" { status: 500, statusText: "Internal Server Error", headers: [] }
159+
160+run
161+ :: forall @row list handlers
162+ . RowToList row list
163+ => RunAPI row list handlers
164+ => Record handlers
165+ -> Request
166+ -> Effect Response
167+run handlers req = runAPI @row @list @handlers handlers (routeFromRequest req) req
168+
src/PureStack/Server.pursdeleted−410
@@ -1,410 +0,0 @@
1−module PureStack.Server
2− ( Server
3− , Response(..)
4− , ResponseBody(..)
5− , class ToResponse
6− , toResponse
7− , class FromRequest
8− , fromRequest
9− , run
10− , notFound
11− , internalServerError
12− , badRequest
13− -------------------------------------------------------------------------------------------------
14− , class ServeAPI
15− , serveAPI
16− , Nt(..)
17− , class ServeRoute
18− , serveRoute
19− , class ServeQuery
20− , serveQuery
21− , class ParsePathPiece
22− , parsePathPiece
23− , class FromHeaders
24− , fromHeaders
25− , class FromHeader
26− , fromHeader
27− ) where
28−
29−import Prelude
30−import PureStack.Route
31−
32−import Bun.Request (Request)
33−import Bun.Request as Bun
34−import Bun.Request as Request
35−import Bun.Response as Bun.Response
36−import Control.Alternative (class Plus, empty)
37−import Control.Monad.Except (ExceptT, runExceptT)
38−import Data.Argonaut (class DecodeJson, class EncodeJson, Json, decodeJson, encodeJson)
39−import Data.Array as Array
40−import Data.Either (Either(..), either)
41−import Data.Int as Int
42−import Data.Map (Map)
43−import Data.Map as Map
44−import Data.Maybe (Maybe(..))
45−import Data.Number as Number
46−import Data.String as String
47−import Data.Symbol (class IsSymbol, reflectSymbol)
48−import Data.Traversable (traverse)
49−import Data.URL as URL
50−import Effect.Aff (Aff)
51−import Effect.Aff.Class (liftAff)
52−import Foreign.Object (Object)
53−import Foreign.Object as Object
54−import Prim.Row as Row
55−import Prim.RowList (class RowToList, RowList)
56−import Prim.RowList as RowList
57−import PureStack.Cookie (Cookie)
58−import PureStack.Cookie as Cookie
59−import Record as Record
60−import Record.Builder (Builder)
61−import Record.Builder as Builder
62−import Type.Proxy (Proxy(..))
63−
64−type Route =
65− { path :: Array String
66− , verb :: String
67− , query :: Map String (Array String)
68− , originalRequest :: Bun.Request
69− }
70−
71−routeFromRequest :: Request -> Route
72−routeFromRequest req =
73− let
74− url = URL.fromString $ Request.url req
75− in
76− { verb: Request.method req
77− , path: case url of
78− Nothing -> []
79− Just u -> case URL.path u of
80− URL.PathEmpty -> []
81− URL.PathAbsolute p -> p
82− URL.PathRelative p -> p
83− , query: case url of
84− Nothing -> Map.empty
85− Just u -> URL.query u
86− , originalRequest: req
87− }
88−
89−type Server a = ExceptT Response Aff a
90−
91−newtype Nt m = Nt (forall x. m x -> Server x)
92−
93−class ServeRoute :: forall k. k -> Type -> Row Type -> (Type -> Type) -> Constraint
94−class ServeRoute route handler middlewares m | route middlewares -> handler, handler -> m where
95− serveRoute :: Route -> Maybe (Nt m -> handler -> Record middlewares -> Request -> Server Response)
96−
97−instance (ServeRoute rest handler middlewares m, IsSymbol path) => ServeRoute (path / rest) handler middlewares m where
98− serveRoute route@{ path } = do
99− { head: h, tail } <- Array.uncons path
100− assert $ h == (reflectSymbol @path Proxy)
101− serveRoute @rest route { path = tail }
102−
103−else instance
104− ( ServeRoute rest handler middlewares m
105− , ServeQuery row list
106− , RowToList row list
107− ) =>
108− ServeRoute (Record row / rest) (Record row -> handler) middlewares m where
109− serveRoute route@{ query } = do
110− builder <- serveQuery @row @list query
111− serveRoute @rest route <#> (\f nt handler req -> f nt (handler $ Builder.buildFromScratch builder) req)
112−
113−else instance
114− ( ServeRoute rest handler middlewares m
115− , IsSymbol field
116− , Row.Cons field (Bun.Request -> m x) tail middlewares
117− ) =>
118− ServeRoute (Middleware field / rest) (x -> handler) middlewares m where
119− serveRoute route@{ originalRequest } = do
120− serveRoute @rest route <#>
121− ( \f nt@(Nt ntf) handler middlewares req -> do
122− x <- ntf $ Record.get (Proxy @field) middlewares originalRequest
123− f nt (handler x) middlewares req
124− )
125−
126−else instance (ServeRoute rest handler middlewares m, ParsePathPiece t) => ServeRoute (t / rest) (t -> handler) middlewares m where
127− serveRoute route@{ path } = do
128− { head: h, tail } <- Array.uncons path
129− t <- parsePathPiece @t h
130− serveRoute @rest route { path = tail } <#> (\f nt handler mws req -> f nt (handler t) mws req)
131−
132−else instance MethodName (meth Unit Unit) => ServeRoute (meth Unit Unit) (m Unit) middlewares m where
133− serveRoute { path, verb } = do
134− assert $ verb == methodName @(meth Unit Unit)
135− assert $ path == []
136− pure $ \(Nt nt) handler _middlewares _req -> do
137− nt handler
138− pure $ ok
139−else instance (ToResponse resp, MethodName (meth Unit resp)) => ServeRoute (meth Unit resp) (m resp) middlewares m where
140− serveRoute { path, verb } = do
141− assert $ verb == methodName @(meth Unit resp)
142− assert $ path == []
143− pure $ \(Nt nt) handler _middlewares _req -> do
144− resp <- nt handler
145− pure $ toResponse resp
146−else instance (FromRequest req, MethodName (meth resp Unit)) => ServeRoute (meth resp Unit) (req -> m Unit) middlewares m where
147− serveRoute { path, verb } = do
148− assert $ verb == methodName @(meth resp Unit)
149− assert $ path == []
150− pure $ \(Nt nt) handler _middlewares req -> do
151− liftAff (fromRequest req) >>= case _ of
152− Nothing -> pure $ badRequest
153− Just r -> do
154− nt $ handler r
155− pure $ ok
156−else instance (FromRequest req, ToResponse resp, MethodName (meth req resp)) => ServeRoute (meth req resp) (req -> m resp) middlewares m where
157− serveRoute { path, verb } = do
158− assert $ verb == methodName @(meth req resp)
159− assert $ path == []
160− pure $ \(Nt nt) handler _middlewares req -> do
161− liftAff (fromRequest req) >>= case _ of
162− Nothing -> pure $ badRequest
163− Just r -> do
164− resp <- nt $ handler r
165− pure $ toResponse resp
166−
167−else instance
168− ( ServeAPI routes list handlers middlewares m
169− , RowToList routes list
170− ) =>
171− ServeRoute routes (Record handlers) middlewares m where
172− serveRoute route = pure $ \nt handlers middlewares req ->
173− serveAPI @routes @list nt handlers middlewares route req
174−
175−class ServeQuery :: Row Type -> RowList Type -> Constraint
176−class ServeQuery row list | list -> row where
177− serveQuery :: Map String (Array String) -> Maybe (Builder (Record ()) (Record row))
178−
179−instance ServeQuery () RowList.Nil where
180− serveQuery _ = Just $ identity
181−
182−instance
183− ( ParsePathPiece t
184− , ServeQuery tail rest
185− , IsSymbol field
186− , Row.Cons field (Array t) tail row
187− , Row.Lacks field tail
188− ) =>
189− ServeQuery row (RowList.Cons field (Array t) rest) where
190− serveQuery m = do
191− r <- serveQuery @tail @rest m
192− case Map.lookup (reflectSymbol @field Proxy) m of
193− Nothing -> pure $ Builder.insert (Proxy @field) [] <<< r
194− Just a -> do
195− v <- parsePathPiece @t `traverse` a
196− pure $ Builder.insert (Proxy @field) v <<< r
197−
198−else instance
199− ( ParsePathPiece t
200− , ServeQuery tail rest
201− , IsSymbol field
202− , Row.Cons field (Maybe t) tail row
203− , Row.Lacks field tail
204− ) =>
205− ServeQuery row (RowList.Cons field (Maybe t) rest) where
206− serveQuery m = do
207− r <- serveQuery @tail @rest m
208− case Map.lookup (reflectSymbol @field Proxy) m of
209− Nothing -> pure $ Builder.insert (Proxy @field) Nothing <<< r
210− Just a -> do
211− { head, tail } <- Array.uncons a
212− assert $ tail == []
213− v <- parsePathPiece @t head
214− pure $ Builder.insert (Proxy @field) (Just v) <<< r
215−
216−else instance
217− ( ParsePathPiece t
218− , ServeQuery tail rest
219− , IsSymbol field
220− , Row.Cons field t tail row
221− , Row.Lacks field tail
222− ) =>
223− ServeQuery row (RowList.Cons field t rest) where
224− serveQuery m = do
225− { head, tail } <- Map.lookup (reflectSymbol @field Proxy) m >>= Array.uncons
226− assert $ tail == []
227− v <- parsePathPiece @t head
228− r <- serveQuery @tail @rest m
229− pure $ Builder.insert (Proxy @field) v <<< r
230−
231−data ResponseBody
232− = JsonResponseBody Json
233− | EmptyResponseBody
234− | StringResponseBody String
235−
236−newtype Response = Response { body :: ResponseBody, status :: Int, statusText :: String, headers :: Object String }
237−
238−class ToResponse r where
239− toResponse :: r -> Response
240−
241−instance EncodeJson (Record row) => ToResponse (Record row) where
242− toResponse rec = Response { body: JsonResponseBody $ encodeJson rec, status: 200, statusText: "OK", headers: Object.empty }
243−
244−instance ToResponse Response where
245− toResponse resp = resp
246−
247−class FromRequest r where
248− fromRequest :: Request -> Aff (Maybe r)
249−
250−instance DecodeJson (Record row) => FromRequest (Record row) where
251− fromRequest req = Request.json req <#> \j -> case decodeJson j of
252− Right r -> Just r
253− Left _ -> Nothing
254−
255−instance FromRequest Request where
256− fromRequest req = pure $ Just req
257−
258−instance FromRequest Unit where
259− fromRequest _ = pure $ Just unit
260−
261−instance
262− ( FromRequest req
263− , FromHeader header
264− ) =>
265− FromRequest (Headers (Object header) req) where
266− fromRequest req = do
267− r <- fromRequest req
268− pure $ do
269− headers <- traverse fromHeader (Request.headers req)
270− r' <- r
271− pure $ Headers headers r'
272−
273−instance
274− ( RowToList headers headersList
275− , FromRequest req
276− , FromHeaders headers headersList
277− ) =>
278− FromRequest (Headers (Record headers) req) where
279− fromRequest req = do
280− r <- fromRequest req
281− pure $ do
282− headers <- fromHeaders @headers @headersList (Request.headers req)
283− r' <- r
284− pure $ Headers (Builder.buildFromScratch headers) r'
285−
286−class FromHeader t where
287− fromHeader :: String -> Maybe t
288−
289−instance FromHeader Cookie where
290− fromHeader = Cookie.parse >>> case _ of
291− Left _ -> Nothing
292− Right x -> Just x
293−
294−instance FromHeader String where
295− fromHeader = Just
296−
297−instance FromHeader Int where
298− fromHeader = Int.fromString
299−
300−class FromHeaders :: Row Type -> RowList Type -> Constraint
301−class FromHeaders row list | list -> row where
302− fromHeaders :: Object String -> Maybe (Builder {} (Record row))
303−
304−instance FromHeaders () RowList.Nil where
305− fromHeaders _ = Just $ identity
306−
307−instance
308− ( FromHeader t
309− , IsSymbol field
310− , FromHeaders tail rest
311− , Row.Cons field (Maybe t) tail row
312− , Row.Lacks field tail
313− ) =>
314− FromHeaders row (RowList.Cons field (Maybe t) rest) where
315− fromHeaders headers = do
316− r <- fromHeaders @tail @rest headers
317− case Object.lookup (reflectSymbol @field Proxy) headers of
318− Nothing -> pure $ Builder.insert (Proxy @field) Nothing <<< r
319− Just t -> do
320− v <- fromHeader t
321− pure $ Builder.insert (Proxy @field) (Just v) <<< r
322−
323−else instance
324− ( FromHeader t
325− , IsSymbol field
326− , FromHeaders tail rest
327− , Row.Cons field t tail row
328− , Row.Lacks field tail
329− ) =>
330− FromHeaders row (RowList.Cons field t rest) where
331− fromHeaders headers = do
332− t <- Object.lookup (reflectSymbol @field Proxy) headers >>= fromHeader
333− r <- fromHeaders @tail @rest headers
334− pure $ Builder.insert (Proxy @field) t <<< r
335−
336−class ParsePathPiece t where
337− parsePathPiece :: String -> Maybe t
338−
339−instance ParsePathPiece String where
340− parsePathPiece = Just
341−
342−instance ParsePathPiece Int where
343− parsePathPiece = Int.fromString
344−
345−instance ParsePathPiece Number where
346− parsePathPiece = Number.fromString
347−
348−instance ParsePathPiece Boolean where
349− parsePathPiece s = case String.toLower s of
350− "true" -> Just true
351− "1" -> Just true
352− "false" -> Just false
353− "0" -> Just false
354− _ -> Nothing
355−
356−assert :: forall m. Applicative m => Plus m => Boolean -> m Unit
357−assert true = pure unit
358−assert false = empty
359−
360−class ServeAPI :: Row Type -> RowList Type -> Row Type -> Row Type -> (Type -> Type) -> Constraint
361−class ServeAPI row list handlers middlewares m | row -> handlers, handlers -> m where
362− serveAPI :: Nt m -> Record handlers -> Record middlewares -> Route -> Request -> Server Response
363−
364−instance ServeAPI row RowList.Nil () middlewares m where
365− serveAPI _ _ _ _ _ = pure notFound
366−
367−instance
368− ( ServeRoute t handler middlewares m
369− , Row.Cons field t tail row
370− , ServeAPI row rest restHandlers middlewares m
371− , IsSymbol field
372− , Row.Cons field handler restHandlers handlers
373− , Row.Lacks field restHandlers
374− ) =>
375− ServeAPI row (RowList.Cons field t rest) handlers middlewares m where
376− serveAPI nt handlers middlewares route req =
377− case serveRoute @t route of
378− Nothing -> serveAPI @row @rest @restHandlers @middlewares nt (Record.delete (Proxy @field) handlers) middlewares route req
379− Just f -> f nt (Record.get (Proxy @field) handlers) middlewares req
380−
381−notFound :: Response
382−notFound = Response { body: EmptyResponseBody, status: 404, statusText: "Not Found", headers: Object.empty }
383−
384−internalServerError :: Response
385−internalServerError = Response { body: EmptyResponseBody, status: 500, statusText: "Internal Server Error", headers: Object.empty }
386−
387−badRequest :: Response
388−badRequest = Response { body: EmptyResponseBody, status: 400, statusText: "Bad Request", headers: Object.empty }
389−
390−ok :: Response
391−ok = Response { body: EmptyResponseBody, status: 200, statusText: "OK", headers: Object.empty }
392−
393−-- | The first argument is used to run an arbitrary monad in handlers. To use the 'Server' monad
394−-- | instead you can just pass `identity` as the first argument.
395−run
396− :: forall @row list handlers m middlewares
397− . RowToList row list
398− => ServeAPI row list handlers middlewares m
399− => (forall x. m x -> Server x)
400− -> { handlers :: Record handlers, middlewares :: Record middlewares }
401− -> Request
402− -> Aff Bun.Response.Response
403−run nt { handlers, middlewares } req = do
404− Response { body, headers, status, statusText } <-
405− map (either identity identity) $ runExceptT $ serveAPI @row @list @handlers (Nt nt) handlers middlewares (routeFromRequest req) req
406− let opts = { headers, status, statusText }
407− pure $ case body of
408− EmptyResponseBody -> Bun.Response.string "" opts
409− JsonResponseBody json -> Bun.Response.json json opts
410− StringResponseBody string -> Bun.Response.string string opts