@gello/auth 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js DELETED
@@ -1,2266 +0,0 @@
1
- var He = Object.defineProperty;
2
- var je = (e, t, r) => t in e ? He(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
3
- var O = (e, t, r) => je(e, typeof t != "symbol" ? t + "" : t, r);
4
- import { Brand as E, Data as h, Context as y, Layer as p, Effect as o, Option as m, Duration as U, pipe as te } from "effect";
5
- import { HttpServerRequest as J, HttpServerResponse as x } from "@effect/platform";
6
- import { jsx as d, jsxs as u, Fragment as ze } from "react/jsx-runtime";
7
- import * as q from "react";
8
- import { Html as Be, Head as We, Body as qe, Container as Je, Section as M, Link as P, Img as Ve, Text as $, Hr as ke, Heading as Ge, Button as Ye } from "@react-email/components";
9
- import { render as we } from "@react-email/render";
10
- const Te = E.nominal(), Ke = E.nominal(), Q = E.nominal(), Xe = E.nominal(), v = {
11
- /**
12
- * Generate a new TokenId
13
- */
14
- generateId: () => Te(crypto.randomUUID()),
15
- /**
16
- * Generate a random plain text token
17
- */
18
- generatePlainText: () => {
19
- const e = new Uint8Array(32);
20
- crypto.getRandomValues(e);
21
- const t = Array.from(e).map((r) => r.toString(16).padStart(2, "0")).join("");
22
- return Ke(t);
23
- },
24
- /**
25
- * Check if token has a specific scope
26
- */
27
- hasScope: (e, t) => e.scopes.includes("*") ? !0 : e.scopes.includes(t),
28
- /**
29
- * Check if token has all specified scopes
30
- */
31
- hasAllScopes: (e, t) => t.every((r) => v.hasScope(e, r)),
32
- /**
33
- * Check if token has any of the specified scopes
34
- */
35
- hasAnyScope: (e, t) => t.some((r) => v.hasScope(e, r)),
36
- /**
37
- * Check if token is expired
38
- */
39
- isExpired: (e) => e.expiresAt ? /* @__PURE__ */ new Date() > e.expiresAt : !1
40
- }, cr = {
41
- authenticated: (e) => ({
42
- _tag: "Authenticated",
43
- user: e
44
- }),
45
- guest: () => ({
46
- _tag: "Guest"
47
- }),
48
- isAuthenticated: (e) => e._tag === "Authenticated",
49
- isGuest: (e) => e._tag === "Guest"
50
- };
51
- class lr extends h.TaggedError("AuthError") {
52
- }
53
- class A extends h.TaggedError("AuthenticationError") {
54
- }
55
- class re extends h.TaggedError("TokenNotFoundError") {
56
- }
57
- class Qe extends h.TaggedError("TokenExpiredError") {
58
- }
59
- class Ze extends h.TaggedError("InsufficientScopeError") {
60
- }
61
- class et extends h.TaggedError("UserNotFoundError") {
62
- }
63
- class dr extends h.TaggedError("HashingError") {
64
- }
65
- class ur extends h.TaggedError("InvalidPasswordError") {
66
- }
67
- class hr extends h.TaggedError("RateLimitError") {
68
- }
69
- class ve extends y.Tag("@gello/auth/TokenStore")() {
70
- }
71
- class xe extends y.Tag("@gello/auth/PasswordHasher")() {
72
- }
73
- class be extends y.Tag("@gello/auth/TokenHasher")() {
74
- }
75
- class Se extends y.Tag("@gello/auth/UserProvider")() {
76
- }
77
- class C extends y.Tag("@gello/auth/TokenService")() {
78
- }
79
- const tt = p.effect(
80
- C,
81
- o.gen(function* () {
82
- const e = yield* ve, t = yield* be;
83
- return {
84
- createToken: (n, s, i = ["*"], a) => o.gen(function* () {
85
- const l = v.generatePlainText(), c = Q(t.hash(l)), g = {
86
- id: v.generateId(),
87
- userId: n,
88
- name: s,
89
- token: c,
90
- scopes: i,
91
- expiresAt: a,
92
- createdAt: /* @__PURE__ */ new Date()
93
- };
94
- return {
95
- accessToken: yield* e.create(g),
96
- plainTextToken: l
97
- };
98
- }),
99
- verifyToken: (n) => o.gen(function* () {
100
- const s = Q(t.hash(n)), i = yield* e.findByToken(s);
101
- if (m.isNone(i))
102
- return yield* o.fail(
103
- new A({
104
- message: "Invalid token",
105
- reason: "invalid_token"
106
- })
107
- );
108
- const a = i.value;
109
- return v.isExpired(a) ? yield* o.fail(
110
- new Qe({
111
- message: "Token has expired",
112
- tokenId: a.id,
113
- expiredAt: a.expiresAt
114
- })
115
- ) : (yield* e.updateLastUsed(a.id, /* @__PURE__ */ new Date()).pipe(o.catchAll(() => o.void)), a);
116
- }),
117
- getUserTokens: (n) => e.findByUser(n),
118
- revokeToken: (n) => e.delete(n),
119
- revokeAllTokens: (n) => e.deleteByUser(n),
120
- pruneExpiredTokens: () => e.deleteExpired()
121
- };
122
- })
123
- );
124
- class Ae extends y.Tag("@gello/auth/Auth")() {
125
- }
126
- const rt = p.effect(
127
- Ae,
128
- o.gen(function* () {
129
- const e = yield* Se, t = yield* xe, r = yield* C;
130
- return {
131
- attempt: (s, i) => o.gen(function* () {
132
- const a = yield* e.findByEmail(s);
133
- if (m.isNone(a))
134
- return yield* o.fail(
135
- new A({
136
- message: "Invalid credentials",
137
- reason: "invalid_credentials"
138
- })
139
- );
140
- const l = a.value;
141
- return (yield* t.verify(i, l.password).pipe(
142
- o.mapError(
143
- () => new A({
144
- message: "Invalid credentials",
145
- reason: "invalid_credentials"
146
- })
147
- )
148
- )) ? l : yield* o.fail(
149
- new A({
150
- message: "Invalid credentials",
151
- reason: "invalid_credentials"
152
- })
153
- );
154
- }),
155
- authenticateWithToken: (s) => o.gen(function* () {
156
- const i = yield* r.verifyToken(s).pipe(
157
- o.mapError(
158
- (l) => new A({
159
- message: l.message,
160
- reason: l._tag === "TokenExpiredError" ? "expired_token" : "invalid_token"
161
- })
162
- )
163
- ), a = yield* e.findById(i.userId);
164
- return m.isNone(a) ? yield* o.fail(
165
- new A({
166
- message: "User not found",
167
- reason: "invalid_token"
168
- })
169
- ) : {
170
- id: i.userId,
171
- token: i
172
- };
173
- }),
174
- getUser: (s) => o.gen(function* () {
175
- const i = yield* e.findById(s);
176
- return m.isNone(i) ? yield* o.fail(
177
- new et({
178
- message: "User not found",
179
- userId: s
180
- })
181
- ) : i.value;
182
- }),
183
- createToken: (s, i, a, l) => r.createToken(s, i, a, l),
184
- getTokens: (s) => r.getUserTokens(s),
185
- revokeToken: (s) => r.revokeToken(s).pipe(
186
- o.catchAll(() => o.void)
187
- ),
188
- revokeAllTokens: (s) => r.revokeAllTokens(s),
189
- hashPassword: (s) => t.hash(s).pipe(
190
- o.catchAll(() => o.succeed(""))
191
- ),
192
- needsRehash: (s) => t.needsRehash(s)
193
- };
194
- })
195
- );
196
- function fr(e) {
197
- return {
198
- ...e,
199
- createToken(t, r, n) {
200
- return o.gen(function* () {
201
- return yield* (yield* C).createToken(e.id, t, r, n);
202
- });
203
- },
204
- tokens() {
205
- return o.gen(function* () {
206
- return yield* (yield* C).getUserTokens(e.id);
207
- });
208
- },
209
- revokeToken(t) {
210
- return o.gen(function* () {
211
- return yield* (yield* C).revokeToken(t).pipe(
212
- o.catchAll(() => o.void)
213
- );
214
- });
215
- },
216
- revokeAllTokens() {
217
- return o.gen(function* () {
218
- return yield* (yield* C).revokeAllTokens(e.id);
219
- });
220
- }
221
- };
222
- }
223
- function gr(e) {
224
- return typeof e == "object" && e !== null && "id" in e && "createToken" in e && "tokens" in e;
225
- }
226
- class w extends y.Tag("@gello/auth/AuthenticatedUser")() {
227
- }
228
- const nt = (e) => {
229
- if (!e) return null;
230
- const t = e.match(/^Bearer\s+(.+)$/i);
231
- return t ? t[1] : null;
232
- }, ne = (e = {}) => ({
233
- name: "authenticate",
234
- apply: (t) => o.gen(function* () {
235
- const r = yield* J.HttpServerRequest, n = yield* Ae, s = r.headers.authorization, i = nt(s);
236
- if (!i)
237
- return e.optional ? yield* t : x.json(
238
- { error: "Authentication required" },
239
- { status: 401 }
240
- );
241
- const a = yield* n.authenticateWithToken(i).pipe(
242
- o.either
243
- );
244
- if (a._tag === "Left") {
245
- if (e.optional)
246
- return yield* t;
247
- const c = a.left;
248
- return x.json(
249
- { error: c.message },
250
- { status: 401 }
251
- );
252
- }
253
- const l = a.right;
254
- return yield* t.pipe(
255
- o.provideService(w, l)
256
- );
257
- })
258
- });
259
- ne.optional = () => ({
260
- ...ne({ optional: !0 }),
261
- name: "authenticate.optional"
262
- });
263
- const mr = () => o.flatMap(
264
- o.either(w),
265
- (e) => e._tag === "Right" ? o.succeed(e.right) : o.fail(
266
- new A({
267
- message: "Not authenticated",
268
- reason: "missing_token"
269
- })
270
- )
271
- ), pr = () => o.map(o.either(w), (e) => e._tag === "Right"), yr = (...e) => ({
272
- name: "tokenScopes",
273
- apply: (t) => o.gen(function* () {
274
- const r = yield* w;
275
- return r.token ? v.hasAllScopes(r.token, e) ? yield* t : x.json(
276
- {
277
- error: "Insufficient scope",
278
- required: e,
279
- provided: r.token.scopes
280
- },
281
- { status: 403 }
282
- ) : yield* t;
283
- })
284
- }), kr = (...e) => ({
285
- name: "tokenScope",
286
- apply: (t) => o.gen(function* () {
287
- const r = yield* w;
288
- return r.token ? v.hasAnyScope(r.token, e) ? yield* t : x.json(
289
- {
290
- error: "Insufficient scope",
291
- required: `One of: ${e.join(", ")}`,
292
- provided: r.token.scopes
293
- },
294
- { status: 403 }
295
- ) : yield* t;
296
- })
297
- }), wr = (e) => o.gen(function* () {
298
- const t = yield* w;
299
- return t.token ? v.hasScope(t.token, e) : !0;
300
- }), Tr = (e) => o.gen(function* () {
301
- const t = yield* w;
302
- if (t.token && !v.hasScope(t.token, e))
303
- return yield* o.fail(
304
- new Ze({
305
- message: `Token lacks required scope: ${e}`,
306
- required: [e],
307
- provided: t.token.scopes
308
- })
309
- );
310
- }), Ee = E.nominal(), Ue = E.nominal(), L = {
311
- /**
312
- * Generate a new SessionId
313
- */
314
- generateId: () => Ee(crypto.randomUUID()),
315
- /**
316
- * Generate a CSRF token
317
- */
318
- generateCsrfToken: () => {
319
- const e = new Uint8Array(32);
320
- return crypto.getRandomValues(e), Ue(
321
- Array.from(e).map((t) => t.toString(16).padStart(2, "0")).join("")
322
- );
323
- },
324
- /**
325
- * Create a new session
326
- */
327
- make: (e, t) => {
328
- const r = /* @__PURE__ */ new Date(), n = (t == null ? void 0 : t.lifetime) ?? U.hours(2), s = new Date(r.getTime() + U.toMillis(n));
329
- return {
330
- id: L.generateId(),
331
- userId: e,
332
- data: (t == null ? void 0 : t.data) ?? {},
333
- ipAddress: t == null ? void 0 : t.ipAddress,
334
- userAgent: t == null ? void 0 : t.userAgent,
335
- lastActivity: r,
336
- createdAt: r,
337
- expiresAt: s
338
- };
339
- },
340
- /**
341
- * Check if session is expired
342
- */
343
- isExpired: (e) => /* @__PURE__ */ new Date() > e.expiresAt,
344
- /**
345
- * Extend session expiration
346
- */
347
- touch: (e, t) => {
348
- const r = /* @__PURE__ */ new Date();
349
- return {
350
- ...e,
351
- lastActivity: r,
352
- expiresAt: new Date(r.getTime() + U.toMillis(t))
353
- };
354
- }
355
- }, Z = {
356
- cookieName: "gello_session",
357
- lifetime: U.hours(2),
358
- path: "/",
359
- secure: !0,
360
- httpOnly: !0,
361
- sameSite: "lax"
362
- };
363
- class vr extends h.TaggedError("SessionError") {
364
- }
365
- class se extends h.TaggedError("SessionNotFoundError") {
366
- }
367
- class xr extends h.TaggedError("SessionExpiredError") {
368
- }
369
- class st extends h.TaggedError("CsrfMismatchError") {
370
- }
371
- class T extends h.TaggedError("JwtError") {
372
- }
373
- class F extends y.Tag("@gello/auth/SessionStore")() {
374
- }
375
- const ot = () => {
376
- const e = /* @__PURE__ */ new Map();
377
- return {
378
- get: (t) => o.sync(() => {
379
- const r = e.get(t);
380
- return r ? /* @__PURE__ */ new Date() > r.expiresAt ? (e.delete(t), m.none()) : m.some(r) : m.none();
381
- }),
382
- put: (t) => o.sync(() => {
383
- e.set(t.id, t);
384
- }),
385
- destroy: (t) => o.sync(() => {
386
- if (!e.has(t))
387
- throw new se({
388
- message: "Session not found",
389
- sessionId: t
390
- });
391
- e.delete(t);
392
- }),
393
- destroyByUser: (t) => o.sync(() => {
394
- let r = 0;
395
- for (const [n, s] of e)
396
- s.userId === t && (e.delete(n), r++);
397
- return r;
398
- }),
399
- touch: (t, r) => o.sync(() => {
400
- const n = e.get(t);
401
- if (!n)
402
- throw new se({
403
- message: "Session not found",
404
- sessionId: t
405
- });
406
- const s = /* @__PURE__ */ new Date();
407
- e.set(t, {
408
- ...n,
409
- lastActivity: s,
410
- expiresAt: new Date(s.getTime() + U.toMillis(r))
411
- });
412
- }),
413
- gc: (t) => o.sync(() => {
414
- const r = /* @__PURE__ */ new Date(), n = new Date(r.getTime() - U.toMillis(t));
415
- let s = 0;
416
- for (const [i, a] of e)
417
- (a.expiresAt < r || a.lastActivity < n) && (e.delete(i), s++);
418
- return s;
419
- })
420
- };
421
- }, it = p.succeed(
422
- F,
423
- ot()
424
- );
425
- class at extends y.Tag("@gello/auth/JwtService")() {
426
- }
427
- const oe = (e) => Buffer.from(e).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""), ie = (e) => {
428
- const t = e.replace(/-/g, "+").replace(/_/g, "/"), r = t.length % 4, n = r ? t + "=".repeat(4 - r) : t;
429
- return Buffer.from(n, "base64").toString("utf-8");
430
- }, ae = async (e, t) => {
431
- const r = new TextEncoder(), n = await crypto.subtle.importKey(
432
- "raw",
433
- r.encode(t),
434
- { name: "HMAC", hash: "SHA-256" },
435
- !1,
436
- ["sign"]
437
- ), s = await crypto.subtle.sign("HMAC", n, r.encode(e));
438
- return Buffer.from(s).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
439
- }, ct = (e) => ({
440
- sign: (t, r = 3600) => o.tryPromise({
441
- try: async () => {
442
- const n = Math.floor(Date.now() / 1e3), s = {
443
- ...t,
444
- iat: n,
445
- exp: n + r
446
- }, i = oe(JSON.stringify({ alg: "HS256", typ: "JWT" })), a = oe(JSON.stringify(s)), l = await ae(`${i}.${a}`, e);
447
- return `${i}.${a}.${l}`;
448
- },
449
- catch: (n) => new T({
450
- message: "Failed to sign JWT",
451
- reason: "malformed",
452
- cause: n
453
- })
454
- }),
455
- verify: (t) => o.tryPromise({
456
- try: async () => {
457
- const r = t.split(".");
458
- if (r.length !== 3)
459
- throw new T({
460
- message: "Invalid JWT format",
461
- reason: "malformed"
462
- });
463
- const [n, s, i] = r, a = await ae(`${n}.${s}`, e);
464
- if (i !== a)
465
- throw new T({
466
- message: "Invalid JWT signature",
467
- reason: "invalid"
468
- });
469
- const l = JSON.parse(ie(s)), c = Math.floor(Date.now() / 1e3);
470
- if (l.exp && l.exp < c)
471
- throw new T({
472
- message: "JWT has expired",
473
- reason: "expired"
474
- });
475
- return l;
476
- },
477
- catch: (r) => r instanceof T ? r : new T({
478
- message: "Failed to verify JWT",
479
- reason: "malformed",
480
- cause: r
481
- })
482
- }),
483
- decode: (t) => o.try({
484
- try: () => {
485
- const r = t.split(".");
486
- if (r.length !== 3)
487
- throw new T({
488
- message: "Invalid JWT format",
489
- reason: "malformed"
490
- });
491
- return JSON.parse(ie(r[1]));
492
- },
493
- catch: (r) => r instanceof T ? r : new T({
494
- message: "Failed to decode JWT",
495
- reason: "malformed",
496
- cause: r
497
- })
498
- })
499
- }), br = (e) => p.succeed(at, ct(e));
500
- class V extends y.Tag("@gello/auth/CurrentSession")() {
501
- }
502
- const lt = (e) => {
503
- const t = /* @__PURE__ */ new Map();
504
- return e && e.split(";").forEach((r) => {
505
- const [n, ...s] = r.trim().split("=");
506
- n && t.set(n, s.join("="));
507
- }), t;
508
- }, ce = (e = {}) => {
509
- const t = { ...Z, ...e };
510
- return {
511
- name: "session",
512
- apply: (r) => o.gen(function* () {
513
- const n = yield* J.HttpServerRequest, s = yield* F, a = lt(n.headers.cookie).get(t.cookieName);
514
- let l = null;
515
- if (a) {
516
- const c = yield* s.get(Ee(a));
517
- if (m.isSome(c)) {
518
- const g = c.value;
519
- L.isExpired(g) || (yield* s.touch(g.id, t.lifetime).pipe(
520
- o.catchAll(() => o.void)
521
- ), l = L.touch(g, t.lifetime));
522
- }
523
- }
524
- return !l && !e.optional ? x.json(
525
- { error: "Session required" },
526
- { status: 401 }
527
- ) : l ? yield* r.pipe(
528
- o.provideService(V, l)
529
- ) : yield* r;
530
- })
531
- };
532
- };
533
- ce.optional = () => ({
534
- ...ce({ optional: !0 }),
535
- name: "session.optional"
536
- });
537
- const Sr = (e, t = Z, r = {}) => o.gen(function* () {
538
- const n = yield* F, s = yield* J.HttpServerRequest, i = L.make(e.id, {
539
- data: r,
540
- ipAddress: s.headers["x-forwarded-for"] ?? s.headers["x-real-ip"],
541
- userAgent: s.headers["user-agent"],
542
- lifetime: t.lifetime
543
- });
544
- yield* n.put(i);
545
- const a = [
546
- `${t.cookieName}=${i.id}`,
547
- `Path=${t.path}`,
548
- `Max-Age=${Math.floor(U.toSeconds(t.lifetime))}`,
549
- t.httpOnly ? "HttpOnly" : "",
550
- t.secure ? "Secure" : "",
551
- `SameSite=${t.sameSite}`,
552
- t.domain ? `Domain=${t.domain}` : ""
553
- ].filter(Boolean);
554
- return {
555
- session: i,
556
- cookie: a.join("; ")
557
- };
558
- }), Ar = (e = Z) => o.gen(function* () {
559
- const t = yield* V;
560
- return yield* (yield* F).destroy(t.id).pipe(o.catchAll(() => o.void)), [
561
- `${e.cookieName}=`,
562
- `Path=${e.path}`,
563
- "Max-Age=0",
564
- e.httpOnly ? "HttpOnly" : "",
565
- e.secure ? "Secure" : "",
566
- `SameSite=${e.sameSite}`
567
- ].filter(Boolean).join("; ");
568
- }), Er = (e) => o.gen(function* () {
569
- return (yield* V).data[e];
570
- }), Ur = (e, t) => o.gen(function* () {
571
- const r = yield* V, n = yield* F, s = {
572
- ...r,
573
- data: { ...r.data, [e]: t }
574
- };
575
- yield* n.put(s);
576
- });
577
- class dt extends y.Tag("@gello/auth/CsrfToken")() {
578
- }
579
- const $e = {
580
- cookieName: "XSRF-TOKEN",
581
- headerName: "X-XSRF-TOKEN",
582
- protectedMethods: ["POST", "PUT", "PATCH", "DELETE"],
583
- path: "/",
584
- secure: !0,
585
- sameSite: "lax"
586
- }, ut = (e) => {
587
- const t = /* @__PURE__ */ new Map();
588
- return e && e.split(";").forEach((r) => {
589
- const [n, ...s] = r.trim().split("=");
590
- n && t.set(n, s.join("="));
591
- }), t;
592
- }, $r = (e = {}) => {
593
- const t = { ...$e, ...e };
594
- return {
595
- name: "csrf",
596
- apply: (r) => o.gen(function* () {
597
- const n = yield* J.HttpServerRequest, s = n.method.toUpperCase();
598
- if (!t.protectedMethods.includes(s))
599
- return yield* r;
600
- const a = ut(n.headers.cookie).get(t.cookieName), l = n.headers[t.headerName.toLowerCase()];
601
- return !a || !l ? x.json(
602
- { error: "CSRF token missing" },
603
- { status: 419 }
604
- ) : a !== l ? x.json(
605
- { error: "CSRF token mismatch" },
606
- { status: 419 }
607
- ) : yield* r.pipe(
608
- o.provideService(dt, Ue(a))
609
- );
610
- })
611
- };
612
- }, Mr = (e = {}) => {
613
- const t = { ...$e, ...e };
614
- return o.sync(() => {
615
- const r = L.generateCsrfToken();
616
- return [
617
- `${t.cookieName}=${r}`,
618
- `Path=${t.path}`,
619
- // Not HttpOnly so JS can read it
620
- t.secure ? "Secure" : "",
621
- `SameSite=${t.sameSite}`
622
- ].filter(Boolean).join("; ");
623
- });
624
- }, Ir = (e, t) => o.gen(function* () {
625
- if (e !== t)
626
- return yield* o.fail(
627
- new st({
628
- message: "CSRF token mismatch"
629
- })
630
- );
631
- }), N = (e) => typeof e == "string" ? e : e.constructor.name, le = (e, t) => {
632
- const r = Array.isArray(e) ? e : [e];
633
- return r.includes(t) || r.includes("manage");
634
- }, de = (e, t) => {
635
- const r = Array.isArray(e) ? e : [e], n = N(t);
636
- return r.some((s) => s === "all" ? !0 : typeof s == "string" ? s === n : s === t);
637
- }, ue = (e, t) => !e || typeof t == "string" ? !0 : Object.entries(e).every(([r, n]) => t[r] === n), ht = (e) => {
638
- const t = (s, i) => {
639
- const a = e.filter(
640
- (g) => le(g.action, s) && de(g.subject, i) && ue(g.conditions, i)
641
- );
642
- if (a.length === 0) return !1;
643
- const l = a.some((g) => g.inverted), c = a.some((g) => !g.inverted);
644
- return l ? !1 : c;
645
- };
646
- return {
647
- rules: e,
648
- can: t,
649
- cannot: (s, i) => !t(s, i),
650
- relevantRuleFor: (s, i) => e.find(
651
- (a) => le(a.action, s) && de(a.subject, i) && ue(a.conditions, i)
652
- )
653
- };
654
- };
655
- class Pr extends h.TaggedError("AuthorizationError") {
656
- }
657
- class Me extends h.TaggedError("ForbiddenError") {
658
- }
659
- function Cr(e, t) {
660
- const r = [];
661
- return t({
662
- user: e,
663
- can: (s, i, a) => {
664
- r.push({
665
- action: Array.isArray(s) ? s : [s],
666
- subject: Array.isArray(i) ? i : [i],
667
- conditions: a,
668
- inverted: !1
669
- });
670
- },
671
- cannot: (s, i, a, l) => {
672
- r.push({
673
- action: Array.isArray(s) ? s : [s],
674
- subject: Array.isArray(i) ? i : [i],
675
- conditions: a,
676
- inverted: !0,
677
- reason: l
678
- });
679
- }
680
- }), ht(r);
681
- }
682
- const Nr = {
683
- /**
684
- * CRUD abilities for a resource
685
- */
686
- crud: (e) => ["create", "read", "update", "delete"],
687
- /**
688
- * Full management (includes all actions)
689
- */
690
- manage: "manage",
691
- /**
692
- * All subjects wildcard
693
- */
694
- all: "all"
695
- };
696
- class b extends y.Tag("@gello/auth/Abilities")() {
697
- }
698
- const Dr = (e, t) => o.gen(function* () {
699
- return (yield* b).can(e, t);
700
- }), Rr = (e, t) => o.gen(function* () {
701
- return (yield* b).cannot(e, t);
702
- }), ft = (e, t) => o.gen(function* () {
703
- const r = yield* b;
704
- if (!r.can(e, t)) {
705
- const s = r.relevantRuleFor(e, t);
706
- return yield* o.fail(
707
- new Me({
708
- message: (s == null ? void 0 : s.reason) ?? `You are not authorized to ${e} this ${N(t)}`,
709
- action: e,
710
- subject: N(t),
711
- rule: s
712
- })
713
- );
714
- }
715
- }), _r = (e, t) => o.gen(function* () {
716
- for (const r of e)
717
- yield* ft(r, t);
718
- }), Or = (e, t) => o.gen(function* () {
719
- const r = yield* b;
720
- if (!e.some((s) => r.can(s, t)))
721
- return yield* o.fail(
722
- new Me({
723
- message: `You are not authorized to perform any of [${e.join(", ")}] on this ${N(t)}`,
724
- action: e[0],
725
- subject: N(t)
726
- })
727
- );
728
- }), Lr = (e) => p.succeed(b, e), gt = (e, t, r = {}) => ({
729
- name: "authorize",
730
- apply: (n) => o.gen(function* () {
731
- const s = yield* b, i = t ? yield* t().pipe(o.catchAll(() => o.succeed(e))) : e;
732
- if (!s.can(e, i)) {
733
- const l = N(i), c = r.message ?? `You are not authorized to ${e} ${l}`, g = r.status ?? 403;
734
- return x.json({ error: c }, { status: g });
735
- }
736
- return yield* n;
737
- })
738
- }), Fr = (e = {}) => ({
739
- ...gt("manage", () => o.succeed("all"), e),
740
- name: "requireAdmin"
741
- }), Hr = (e, t, r = {}) => ({
742
- name: "requireAny",
743
- apply: (n) => o.gen(function* () {
744
- const s = yield* b, i = t ? yield* t().pipe(o.catchAll(() => o.succeed(e[0]))) : e[0];
745
- if (!e.some((l) => s.can(l, i))) {
746
- const l = r.message ?? "You are not authorized to perform this action", c = r.status ?? 403;
747
- return x.json({ error: l }, { status: c });
748
- }
749
- return yield* n;
750
- })
751
- }), Ie = {
752
- make: (e, t) => ({
753
- id: t.id,
754
- email: t.email ?? null,
755
- name: t.name ?? null,
756
- firstName: t.firstName ?? null,
757
- lastName: t.lastName ?? null,
758
- avatar: t.avatar ?? null,
759
- nickname: t.nickname ?? null,
760
- provider: e,
761
- raw: t.raw ?? {}
762
- })
763
- }, he = {
764
- make: (e) => ({
765
- accessToken: e.accessToken,
766
- refreshToken: e.refreshToken ?? null,
767
- expiresAt: e.expiresAt ?? (e.expiresIn ? new Date(Date.now() + e.expiresIn * 1e3) : null),
768
- tokenType: e.tokenType ?? "Bearer",
769
- scopes: typeof e.scope == "string" ? e.scope.split(" ") : e.scope ?? []
770
- }),
771
- /**
772
- * Check if token is expired
773
- */
774
- isExpired: (e) => e.expiresAt ? /* @__PURE__ */ new Date() > e.expiresAt : !1,
775
- /**
776
- * Check if token can be refreshed
777
- */
778
- canRefresh: (e) => e.refreshToken !== null
779
- };
780
- class jr extends h.TaggedError("OAuthError") {
781
- }
782
- class zr extends h.TaggedError("OAuthConfigError") {
783
- }
784
- class mt extends h.TaggedError("OAuthStateMismatchError") {
785
- }
786
- class I extends h.TaggedError("OAuthTokenError") {
787
- }
788
- class K extends h.TaggedError("OAuthUserError") {
789
- }
790
- class fe extends h.TaggedError("OAuthProviderNotFoundError") {
791
- }
792
- class Pe {
793
- constructor(t) {
794
- O(this, "config");
795
- this.config = t;
796
- }
797
- /**
798
- * Build the authorization URL
799
- */
800
- getAuthorizationUrl(t, r) {
801
- const n = [.../* @__PURE__ */ new Set([...this.defaultScopes, ...t])], s = new URLSearchParams({
802
- client_id: this.config.clientId,
803
- redirect_uri: this.config.redirectUri,
804
- response_type: "code",
805
- scope: n.join(" "),
806
- state: r
807
- });
808
- return `${this.authorizationUrl}?${s.toString()}`;
809
- }
810
- /**
811
- * Exchange code for access token
812
- */
813
- getAccessToken(t) {
814
- return o.tryPromise({
815
- try: async () => {
816
- const r = await fetch(this.tokenUrl, {
817
- method: "POST",
818
- headers: {
819
- "Content-Type": "application/x-www-form-urlencoded",
820
- Accept: "application/json"
821
- },
822
- body: new URLSearchParams({
823
- client_id: this.config.clientId,
824
- client_secret: this.config.clientSecret,
825
- code: t,
826
- redirect_uri: this.config.redirectUri,
827
- grant_type: "authorization_code"
828
- })
829
- });
830
- if (!r.ok) {
831
- const s = await r.json().catch(() => ({}));
832
- throw new I({
833
- message: "Failed to exchange code for token",
834
- provider: this.name,
835
- error: s.error,
836
- errorDescription: s.error_description
837
- });
838
- }
839
- const n = await r.json();
840
- return he.make({
841
- accessToken: n.access_token,
842
- refreshToken: n.refresh_token,
843
- expiresIn: n.expires_in,
844
- tokenType: n.token_type,
845
- scope: n.scope
846
- });
847
- },
848
- catch: (r) => r instanceof I ? r : new I({
849
- message: "Failed to exchange code for token",
850
- provider: this.name,
851
- error: String(r)
852
- })
853
- });
854
- }
855
- /**
856
- * Refresh access token
857
- */
858
- refreshToken(t) {
859
- return o.tryPromise({
860
- try: async () => {
861
- const r = await fetch(this.tokenUrl, {
862
- method: "POST",
863
- headers: {
864
- "Content-Type": "application/x-www-form-urlencoded",
865
- Accept: "application/json"
866
- },
867
- body: new URLSearchParams({
868
- client_id: this.config.clientId,
869
- client_secret: this.config.clientSecret,
870
- refresh_token: t,
871
- grant_type: "refresh_token"
872
- })
873
- });
874
- if (!r.ok) {
875
- const s = await r.json().catch(() => ({}));
876
- throw new I({
877
- message: "Failed to refresh token",
878
- provider: this.name,
879
- error: s.error,
880
- errorDescription: s.error_description
881
- });
882
- }
883
- const n = await r.json();
884
- return he.make({
885
- accessToken: n.access_token,
886
- refreshToken: n.refresh_token ?? t,
887
- expiresIn: n.expires_in,
888
- tokenType: n.token_type,
889
- scope: n.scope
890
- });
891
- },
892
- catch: (r) => r instanceof I ? r : new I({
893
- message: "Failed to refresh token",
894
- provider: this.name,
895
- error: String(r)
896
- })
897
- });
898
- }
899
- /**
900
- * Get user information
901
- */
902
- getUser(t) {
903
- return o.tryPromise({
904
- try: async () => {
905
- const r = await fetch(this.userInfoUrl, {
906
- headers: {
907
- Authorization: `${t.tokenType} ${t.accessToken}`,
908
- Accept: "application/json"
909
- }
910
- });
911
- if (!r.ok)
912
- throw new K({
913
- message: "Failed to fetch user info",
914
- provider: this.name
915
- });
916
- const n = await r.json();
917
- return this.parseUser(n);
918
- },
919
- catch: (r) => r instanceof K ? r : new K({
920
- message: "Failed to fetch user info",
921
- provider: this.name,
922
- cause: r
923
- })
924
- });
925
- }
926
- /**
927
- * Create a builder for fluent API
928
- */
929
- builder() {
930
- let t = [], r = !1, n = null;
931
- const s = this, i = {
932
- scopes: (a) => (t = a, i),
933
- stateless: () => (r = !0, i),
934
- redirect: () => o.sync(() => (n = crypto.randomUUID(), s.getAuthorizationUrl(t, n))),
935
- user: (a, l) => o.gen(function* () {
936
- if (!r && n && l !== n)
937
- return yield* o.fail(
938
- new mt({
939
- message: "OAuth state mismatch",
940
- provider: s.name
941
- })
942
- );
943
- const c = yield* s.getAccessToken(a);
944
- return { user: yield* s.getUser(c), token: c };
945
- })
946
- };
947
- return i;
948
- }
949
- }
950
- class Ce extends Pe {
951
- constructor() {
952
- super(...arguments);
953
- O(this, "name", "github");
954
- }
955
- get authorizationUrl() {
956
- return "https://github.com/login/oauth/authorize";
957
- }
958
- get tokenUrl() {
959
- return "https://github.com/login/oauth/access_token";
960
- }
961
- get userInfoUrl() {
962
- return "https://api.github.com/user";
963
- }
964
- get defaultScopes() {
965
- return ["user:email"];
966
- }
967
- parseUser(r) {
968
- return Ie.make("github", {
969
- id: String(r.id),
970
- email: r.email,
971
- name: r.name,
972
- nickname: r.login,
973
- avatar: r.avatar_url,
974
- raw: r
975
- });
976
- }
977
- }
978
- const Br = (e) => new Ce(e);
979
- class Ne extends Pe {
980
- constructor() {
981
- super(...arguments);
982
- O(this, "name", "google");
983
- }
984
- get authorizationUrl() {
985
- return "https://accounts.google.com/o/oauth2/v2/auth";
986
- }
987
- get tokenUrl() {
988
- return "https://oauth2.googleapis.com/token";
989
- }
990
- get userInfoUrl() {
991
- return "https://www.googleapis.com/oauth2/v2/userinfo";
992
- }
993
- get defaultScopes() {
994
- return ["openid", "email", "profile"];
995
- }
996
- parseUser(r) {
997
- return Ie.make("google", {
998
- id: r.id,
999
- email: r.email,
1000
- name: r.name,
1001
- firstName: r.given_name,
1002
- lastName: r.family_name,
1003
- avatar: r.picture,
1004
- raw: r
1005
- });
1006
- }
1007
- /**
1008
- * Override to add Google-specific parameters
1009
- */
1010
- getAuthorizationUrl(r, n) {
1011
- const s = [.../* @__PURE__ */ new Set([...this.defaultScopes, ...r])], i = new URLSearchParams({
1012
- client_id: this.config.clientId,
1013
- redirect_uri: this.config.redirectUri,
1014
- response_type: "code",
1015
- scope: s.join(" "),
1016
- state: n,
1017
- access_type: "offline",
1018
- // Get refresh token
1019
- prompt: "consent"
1020
- // Force consent screen
1021
- });
1022
- return `${this.authorizationUrl}?${i.toString()}`;
1023
- }
1024
- }
1025
- const Wr = (e) => new Ne(e);
1026
- class W extends y.Tag("@gello/auth/Social")() {
1027
- }
1028
- const pt = {
1029
- github: (e) => new Ce(e),
1030
- google: (e) => new Ne(e)
1031
- }, yt = (e, t = {}) => {
1032
- const r = { ...pt, ...t }, n = /* @__PURE__ */ new Map(), s = (i) => {
1033
- let a = n.get(i);
1034
- if (a) return a;
1035
- const l = e.providers[i];
1036
- if (!l)
1037
- throw new fe({
1038
- message: `OAuth provider "${i}" is not configured`,
1039
- provider: i
1040
- });
1041
- const c = r[i];
1042
- if (!c)
1043
- throw new fe({
1044
- message: `OAuth provider "${i}" is not supported`,
1045
- provider: i
1046
- });
1047
- return a = c(l), n.set(i, a), a;
1048
- };
1049
- return {
1050
- driver: (i) => {
1051
- const a = s(i);
1052
- if ("builder" in a && typeof a.builder == "function")
1053
- return a.builder();
1054
- throw new Error(`Provider "${i}" does not support the builder pattern`);
1055
- },
1056
- hasProvider: (i) => i in e.providers && i in r,
1057
- providers: () => Object.keys(e.providers).filter((i) => i in r)
1058
- };
1059
- }, qr = (e, t) => p.succeed(W, yt(e, t)), Jr = {
1060
- driver: (e) => o.gen(function* () {
1061
- return (yield* W).driver(e);
1062
- }),
1063
- hasProvider: (e) => o.gen(function* () {
1064
- return (yield* W).hasProvider(e);
1065
- }),
1066
- providers: () => o.gen(function* () {
1067
- return (yield* W).providers();
1068
- })
1069
- }, R = {
1070
- brand: {
1071
- name: "My App",
1072
- logoWidth: 120
1073
- },
1074
- colors: {
1075
- primary: "#3b82f6",
1076
- // Blue 500
1077
- secondary: "#64748b",
1078
- // Slate 500
1079
- background: "#ffffff",
1080
- surface: "#f8fafc",
1081
- // Slate 50
1082
- text: "#1e293b",
1083
- // Slate 800
1084
- muted: "#94a3b8",
1085
- // Slate 400
1086
- border: "#e2e8f0",
1087
- // Slate 200
1088
- success: "#22c55e",
1089
- // Green 500
1090
- warning: "#f59e0b",
1091
- // Amber 500
1092
- error: "#ef4444"
1093
- // Red 500
1094
- },
1095
- fonts: {
1096
- heading: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif",
1097
- body: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif",
1098
- mono: "ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace"
1099
- },
1100
- layout: {
1101
- maxWidth: 600,
1102
- padding: 24,
1103
- borderRadius: 8
1104
- }
1105
- }, De = q.createContext(R);
1106
- function S() {
1107
- return q.useContext(De);
1108
- }
1109
- function kt({ theme: e, children: t }) {
1110
- return /* @__PURE__ */ d(De.Provider, { value: e, children: t });
1111
- }
1112
- function H({ theme: e, preview: t, children: r }) {
1113
- return /* @__PURE__ */ d(kt, { theme: e, children: /* @__PURE__ */ u(Be, { children: [
1114
- /* @__PURE__ */ d(We, {}),
1115
- t && /* @__PURE__ */ d("span", { style: { display: "none" }, children: t }),
1116
- /* @__PURE__ */ d(qe, { style: vt(e), children: /* @__PURE__ */ u(Je, { style: xt(e), children: [
1117
- /* @__PURE__ */ d(wt, {}),
1118
- /* @__PURE__ */ d(M, { style: At(e), children: r }),
1119
- /* @__PURE__ */ d(Tt, {})
1120
- ] }) })
1121
- ] }) });
1122
- }
1123
- function wt() {
1124
- const e = S();
1125
- return /* @__PURE__ */ d(M, { style: bt(e), children: e.brand.logo ? /* @__PURE__ */ d(P, { href: e.brand.website, children: /* @__PURE__ */ d(
1126
- Ve,
1127
- {
1128
- src: e.brand.logo,
1129
- width: e.brand.logoWidth ?? 120,
1130
- alt: e.brand.name,
1131
- style: { margin: "0 auto" }
1132
- }
1133
- ) }) : /* @__PURE__ */ d($, { style: St(e), children: e.brand.name }) });
1134
- }
1135
- function Tt() {
1136
- const e = S(), t = e.footer;
1137
- return t ? /* @__PURE__ */ u(M, { style: Et(e), children: [
1138
- /* @__PURE__ */ d(ke, { style: Ut(e) }),
1139
- t.company && /* @__PURE__ */ d($, { style: ge(e), children: t.company }),
1140
- t.address && /* @__PURE__ */ d($, { style: ge(e), children: t.address }),
1141
- t.socialLinks && /* @__PURE__ */ u(M, { style: { textAlign: "center", marginTop: "16px" }, children: [
1142
- t.socialLinks.twitter && /* @__PURE__ */ d(P, { href: t.socialLinks.twitter, style: B(e), children: "Twitter" }),
1143
- t.socialLinks.facebook && /* @__PURE__ */ d(P, { href: t.socialLinks.facebook, style: B(e), children: "Facebook" }),
1144
- t.socialLinks.linkedin && /* @__PURE__ */ d(P, { href: t.socialLinks.linkedin, style: B(e), children: "LinkedIn" }),
1145
- t.socialLinks.github && /* @__PURE__ */ d(P, { href: t.socialLinks.github, style: B(e), children: "GitHub" })
1146
- ] }),
1147
- t.unsubscribeUrl && /* @__PURE__ */ d($, { style: $t(e), children: /* @__PURE__ */ d(P, { href: t.unsubscribeUrl, style: { color: e.colors.muted }, children: "Unsubscribe" }) })
1148
- ] }) : null;
1149
- }
1150
- function vt(e) {
1151
- return {
1152
- backgroundColor: e.colors.surface,
1153
- fontFamily: e.fonts.body,
1154
- margin: 0,
1155
- padding: "40px 0"
1156
- };
1157
- }
1158
- function xt(e) {
1159
- return {
1160
- maxWidth: `${e.layout.maxWidth}px`,
1161
- margin: "0 auto",
1162
- backgroundColor: e.colors.background,
1163
- borderRadius: `${e.layout.borderRadius}px`,
1164
- overflow: "hidden"
1165
- };
1166
- }
1167
- function bt(e) {
1168
- return {
1169
- padding: `${e.layout.padding}px`,
1170
- textAlign: "center",
1171
- borderBottom: `1px solid ${e.colors.border}`
1172
- };
1173
- }
1174
- function St(e) {
1175
- return {
1176
- fontSize: "24px",
1177
- fontWeight: "bold",
1178
- color: e.colors.text,
1179
- fontFamily: e.fonts.heading,
1180
- margin: 0
1181
- };
1182
- }
1183
- function At(e) {
1184
- return {
1185
- padding: `${e.layout.padding}px`
1186
- };
1187
- }
1188
- function Et(e) {
1189
- return {
1190
- padding: `${e.layout.padding}px`,
1191
- textAlign: "center"
1192
- };
1193
- }
1194
- function ge(e) {
1195
- return {
1196
- fontSize: "12px",
1197
- color: e.colors.muted,
1198
- margin: "4px 0",
1199
- lineHeight: "1.5"
1200
- };
1201
- }
1202
- function Ut(e) {
1203
- return {
1204
- borderColor: e.colors.border,
1205
- borderTop: "none",
1206
- marginBottom: "16px"
1207
- };
1208
- }
1209
- function B(e) {
1210
- return {
1211
- color: e.colors.muted,
1212
- fontSize: "12px",
1213
- marginRight: "16px",
1214
- textDecoration: "none"
1215
- };
1216
- }
1217
- function $t(e) {
1218
- return {
1219
- fontSize: "11px",
1220
- color: e.colors.muted,
1221
- marginTop: "16px"
1222
- };
1223
- }
1224
- function j({ children: e, padding: t = !0, style: r }) {
1225
- const n = S();
1226
- return /* @__PURE__ */ d(
1227
- M,
1228
- {
1229
- style: {
1230
- padding: t ? `${n.layout.padding / 2}px 0` : void 0,
1231
- ...r
1232
- },
1233
- children: e
1234
- }
1235
- );
1236
- }
1237
- function Mt({ children: e, style: t }) {
1238
- const r = S();
1239
- return /* @__PURE__ */ d(
1240
- M,
1241
- {
1242
- style: {
1243
- backgroundColor: r.colors.surface,
1244
- borderRadius: `${r.layout.borderRadius}px`,
1245
- padding: `${r.layout.padding}px`,
1246
- border: `1px solid ${r.colors.border}`,
1247
- margin: "16px 0",
1248
- ...t
1249
- },
1250
- children: e
1251
- }
1252
- );
1253
- }
1254
- function me({ style: e }) {
1255
- const t = S();
1256
- return /* @__PURE__ */ d(
1257
- ke,
1258
- {
1259
- style: {
1260
- borderColor: t.colors.border,
1261
- borderTop: "none",
1262
- margin: "24px 0",
1263
- ...e
1264
- }
1265
- }
1266
- );
1267
- }
1268
- const It = {
1269
- h1: 28,
1270
- h2: 24,
1271
- h3: 20,
1272
- h4: 18,
1273
- h5: 16,
1274
- h6: 14
1275
- }, Pt = {
1276
- h1: "0 0 16px 0",
1277
- h2: "24px 0 12px 0",
1278
- h3: "20px 0 10px 0",
1279
- h4: "16px 0 8px 0",
1280
- h5: "12px 0 6px 0",
1281
- h6: "8px 0 4px 0"
1282
- };
1283
- function D({ as: e = "h1", children: t, style: r }) {
1284
- const n = S();
1285
- return /* @__PURE__ */ d(
1286
- Ge,
1287
- {
1288
- as: e,
1289
- style: {
1290
- fontFamily: n.fonts.heading,
1291
- fontSize: `${It[e]}px`,
1292
- fontWeight: "600",
1293
- color: n.colors.text,
1294
- margin: Pt[e],
1295
- lineHeight: "1.3",
1296
- ...r
1297
- },
1298
- children: t
1299
- }
1300
- );
1301
- }
1302
- function f({
1303
- children: e,
1304
- muted: t = !1,
1305
- small: r = !1,
1306
- center: n = !1,
1307
- style: s
1308
- }) {
1309
- const i = S();
1310
- return /* @__PURE__ */ d(
1311
- $,
1312
- {
1313
- style: {
1314
- fontFamily: i.fonts.body,
1315
- fontSize: r ? "14px" : "16px",
1316
- color: t ? i.colors.muted : i.colors.text,
1317
- lineHeight: "1.6",
1318
- margin: "0 0 16px 0",
1319
- textAlign: n ? "center" : void 0,
1320
- ...s
1321
- },
1322
- children: e
1323
- }
1324
- );
1325
- }
1326
- function z({
1327
- href: e,
1328
- children: t,
1329
- variant: r = "primary",
1330
- size: n = "md",
1331
- fullWidth: s = !1,
1332
- style: i
1333
- }) {
1334
- const a = S(), l = {
1335
- sm: { padding: "8px 16px", fontSize: "14px" },
1336
- md: { padding: "12px 24px", fontSize: "16px" },
1337
- lg: { padding: "16px 32px", fontSize: "18px" }
1338
- }, c = {
1339
- primary: {
1340
- backgroundColor: a.colors.primary,
1341
- color: "#ffffff",
1342
- border: "none"
1343
- },
1344
- secondary: {
1345
- backgroundColor: a.colors.secondary,
1346
- color: "#ffffff",
1347
- border: "none"
1348
- },
1349
- outline: {
1350
- backgroundColor: "transparent",
1351
- color: a.colors.primary,
1352
- border: `2px solid ${a.colors.primary}`
1353
- }
1354
- };
1355
- return /* @__PURE__ */ d(
1356
- Ye,
1357
- {
1358
- href: e,
1359
- style: {
1360
- display: s ? "block" : "inline-block",
1361
- width: s ? "100%" : void 0,
1362
- textAlign: "center",
1363
- fontFamily: a.fonts.body,
1364
- fontWeight: "600",
1365
- textDecoration: "none",
1366
- borderRadius: `${a.layout.borderRadius}px`,
1367
- ...l[n],
1368
- ...c[r],
1369
- ...i
1370
- },
1371
- children: t
1372
- }
1373
- );
1374
- }
1375
- function G({
1376
- type: e = "info",
1377
- title: t,
1378
- children: r,
1379
- style: n
1380
- }) {
1381
- const s = S(), a = {
1382
- info: {
1383
- bg: "#eff6ff",
1384
- border: "#3b82f6",
1385
- title: "#1e40af",
1386
- text: "#1e3a5f"
1387
- },
1388
- success: {
1389
- bg: "#f0fdf4",
1390
- border: "#22c55e",
1391
- title: "#166534",
1392
- text: "#14532d"
1393
- },
1394
- warning: {
1395
- bg: "#fffbeb",
1396
- border: "#f59e0b",
1397
- title: "#92400e",
1398
- text: "#78350f"
1399
- },
1400
- error: {
1401
- bg: "#fef2f2",
1402
- border: "#ef4444",
1403
- title: "#991b1b",
1404
- text: "#7f1d1d"
1405
- }
1406
- }[e];
1407
- return /* @__PURE__ */ u(
1408
- M,
1409
- {
1410
- style: {
1411
- backgroundColor: a.bg,
1412
- borderLeft: `4px solid ${a.border}`,
1413
- borderRadius: `${s.layout.borderRadius}px`,
1414
- padding: "16px",
1415
- margin: "16px 0",
1416
- ...n
1417
- },
1418
- children: [
1419
- t && /* @__PURE__ */ d(
1420
- $,
1421
- {
1422
- style: {
1423
- fontFamily: s.fonts.heading,
1424
- fontSize: "14px",
1425
- fontWeight: "600",
1426
- color: a.title,
1427
- margin: "0 0 8px 0"
1428
- },
1429
- children: t
1430
- }
1431
- ),
1432
- /* @__PURE__ */ d(
1433
- $,
1434
- {
1435
- style: {
1436
- fontFamily: s.fonts.body,
1437
- fontSize: "14px",
1438
- color: a.text,
1439
- margin: 0,
1440
- lineHeight: "1.5"
1441
- },
1442
- children: r
1443
- }
1444
- )
1445
- ]
1446
- }
1447
- );
1448
- }
1449
- const Ct = E.nominal(), Nt = E.nominal(), k = {
1450
- make: (e, t) => ({
1451
- email: Nt(e),
1452
- name: t
1453
- }),
1454
- /**
1455
- * Format address as string: "Name <email>" or just "email"
1456
- */
1457
- format: (e) => e.name ? `"${e.name}" <${e.email}>` : e.email,
1458
- /**
1459
- * Parse string like "Name <email>" into Address
1460
- */
1461
- parse: (e) => {
1462
- var r;
1463
- const t = e.match(/^(?:"?([^"]*)"?\s)?<?([^>]+@[^>]+)>?$/);
1464
- return t ? k.make(t[2].trim(), (r = t[1]) == null ? void 0 : r.trim()) : null;
1465
- }
1466
- }, ee = {
1467
- /**
1468
- * Generate a new MessageId
1469
- */
1470
- generateId: () => Ct(crypto.randomUUID()),
1471
- /**
1472
- * Create a new message with defaults
1473
- */
1474
- make: (e, t, r) => ({
1475
- id: ee.generateId(),
1476
- envelope: e,
1477
- content: t,
1478
- attachments: (r == null ? void 0 : r.attachments) ?? [],
1479
- headers: (r == null ? void 0 : r.headers) ?? /* @__PURE__ */ new Map(),
1480
- priority: (r == null ? void 0 : r.priority) ?? "normal",
1481
- tags: r == null ? void 0 : r.tags,
1482
- metadata: r == null ? void 0 : r.metadata,
1483
- createdAt: /* @__PURE__ */ new Date()
1484
- })
1485
- };
1486
- class Vr extends h.TaggedError("MailError") {
1487
- }
1488
- class Gr extends h.TaggedError("MailConnectionError") {
1489
- }
1490
- class Yr extends h.TaggedError("MailValidationError") {
1491
- }
1492
- class Kr extends h.TaggedError("MailDeliveryError") {
1493
- }
1494
- class Re extends h.TaggedError("TemplateError") {
1495
- }
1496
- class pe extends h.TaggedError("TemplateNotFoundError") {
1497
- }
1498
- class Xr extends h.TaggedError("AttachmentError") {
1499
- }
1500
- class Qr extends h.TaggedError("MailConfigError") {
1501
- }
1502
- class Y {
1503
- constructor() {
1504
- O(this, "state", {
1505
- to: [],
1506
- cc: [],
1507
- bcc: [],
1508
- attachments: [],
1509
- headers: /* @__PURE__ */ new Map(),
1510
- priority: "normal",
1511
- tags: [],
1512
- metadata: {}
1513
- });
1514
- }
1515
- /**
1516
- * Build the final message
1517
- */
1518
- build() {
1519
- return o.gen(this, function* () {
1520
- const t = yield* this.getContent(this.state.data), r = {
1521
- from: this.state.from ?? k.make("noreply@example.com"),
1522
- to: this.state.to,
1523
- cc: this.state.cc.length > 0 ? this.state.cc : void 0,
1524
- bcc: this.state.bcc.length > 0 ? this.state.bcc : void 0,
1525
- replyTo: this.state.replyTo
1526
- };
1527
- return ee.make(r, t, {
1528
- attachments: this.state.attachments,
1529
- headers: this.state.headers,
1530
- priority: this.state.priority,
1531
- tags: this.state.tags.length > 0 ? this.state.tags : void 0,
1532
- metadata: Object.keys(this.state.metadata).length > 0 ? this.state.metadata : void 0
1533
- });
1534
- });
1535
- }
1536
- to(t) {
1537
- const r = Array.isArray(t) ? t : [t];
1538
- return this.state.to.push(...r.map(this.normalizeAddress)), this;
1539
- }
1540
- cc(t) {
1541
- const r = Array.isArray(t) ? t : [t];
1542
- return this.state.cc.push(...r.map(this.normalizeAddress)), this;
1543
- }
1544
- bcc(t) {
1545
- const r = Array.isArray(t) ? t : [t];
1546
- return this.state.bcc.push(...r.map(this.normalizeAddress)), this;
1547
- }
1548
- from(t, r) {
1549
- return this.state.from = typeof t == "string" ? k.make(t, r) : t, this;
1550
- }
1551
- replyTo(t, r) {
1552
- return this.state.replyTo = typeof t == "string" ? k.make(t, r) : t, this;
1553
- }
1554
- subject(t) {
1555
- return this.state.subject = t, this;
1556
- }
1557
- with(t) {
1558
- return this.state.data = t, this;
1559
- }
1560
- attach(t) {
1561
- return this.state.attachments.push(t), this;
1562
- }
1563
- header(t, r) {
1564
- return this.state.headers.set(t, r), this;
1565
- }
1566
- priority(t) {
1567
- return this.state.priority = t, this;
1568
- }
1569
- tag(t) {
1570
- return this.state.tags.push(t), this;
1571
- }
1572
- metadata(t, r) {
1573
- return this.state.metadata[t] = r, this;
1574
- }
1575
- /**
1576
- * Get the template data
1577
- */
1578
- getData() {
1579
- return this.state.data;
1580
- }
1581
- /**
1582
- * Get subject from state or abstract method
1583
- */
1584
- getSubjectText() {
1585
- return this.state.subject ?? this.getSubject();
1586
- }
1587
- normalizeAddress(t) {
1588
- return typeof t == "string" ? k.parse(t) ?? k.make(t) : t;
1589
- }
1590
- }
1591
- class Dt extends y.Tag("@gello/MailDriver")() {
1592
- }
1593
- class _e extends y.Tag("@gello/TemplateEngine")() {
1594
- }
1595
- class Rt extends y.Tag("@gello/Mail")() {
1596
- }
1597
- const _t = o.gen(function* () {
1598
- const e = yield* Dt, t = yield* o.serviceOption(_e), r = (i) => i.template ? te(
1599
- t,
1600
- m.match({
1601
- onNone: () => (
1602
- // No template engine, return content as-is
1603
- o.succeed(i)
1604
- ),
1605
- onSome: (a) => te(
1606
- a.render(i.template.name, i.template.data),
1607
- o.map(({ html: l, text: c }) => ({
1608
- ...i,
1609
- html: l ?? i.html,
1610
- text: c ?? i.text
1611
- }))
1612
- )
1613
- })
1614
- ) : o.succeed(i), n = (i) => (Array.isArray(i) ? i : [i]).map(
1615
- (l) => typeof l == "string" ? k.parse(l) ?? k.make(l) : l
1616
- ), s = {
1617
- send: (i) => o.gen(function* () {
1618
- const a = yield* i.build(), l = yield* r(a.content), c = { ...a, content: l }, g = i.beforeSend ? yield* i.beforeSend(c) : c, _ = yield* e.send(g);
1619
- return i.afterSend && (yield* i.afterSend(_)), _;
1620
- }),
1621
- sendRaw: (i, a, l, c) => o.gen(function* () {
1622
- const g = n(i), _ = typeof l == "string" ? { text: l } : l, Le = {
1623
- from: (c == null ? void 0 : c.from) != null ? typeof c.from == "string" ? k.parse(c.from) ?? k.make(c.from) : c.from : k.make("noreply@example.com"),
1624
- to: g,
1625
- cc: c != null && c.cc ? n(c.cc) : void 0,
1626
- bcc: c != null && c.bcc ? n(c.bcc) : void 0,
1627
- replyTo: (c == null ? void 0 : c.replyTo) != null ? typeof c.replyTo == "string" ? k.parse(c.replyTo) ?? k.make(c.replyTo) : c.replyTo : void 0
1628
- }, Fe = ee.make(
1629
- Le,
1630
- { subject: a, ..._ },
1631
- {
1632
- attachments: c == null ? void 0 : c.attachments,
1633
- headers: c != null && c.headers ? new Map(Object.entries(c.headers)) : void 0,
1634
- priority: c == null ? void 0 : c.priority,
1635
- tags: c == null ? void 0 : c.tags
1636
- }
1637
- );
1638
- return yield* e.send(Fe);
1639
- }),
1640
- driver: () => e,
1641
- mailer: (i) => s
1642
- };
1643
- return s;
1644
- });
1645
- p.effect(Rt, _t);
1646
- const X = /* @__PURE__ */ new Map(), Ot = (e) => o.tryPromise({
1647
- try: () => we(e, { pretty: !0 }),
1648
- catch: (t) => new Re({
1649
- message: `Failed to render HTML: ${t}`,
1650
- cause: t
1651
- })
1652
- }), Lt = (e) => o.tryPromise({
1653
- try: () => we(e, { plainText: !0 }),
1654
- catch: (t) => new Re({
1655
- message: `Failed to render text: ${t}`,
1656
- cause: t
1657
- })
1658
- }), ye = (e) => o.gen(function* () {
1659
- const t = yield* Ot(e), r = yield* Lt(e);
1660
- return { html: t, text: r };
1661
- }), Ft = () => ({
1662
- name: "react-email",
1663
- render: (e, t) => o.gen(function* () {
1664
- const r = X.get(e);
1665
- if (!r)
1666
- return yield* o.fail(
1667
- new pe({
1668
- message: `Template "${e}" not found`,
1669
- template: e
1670
- })
1671
- );
1672
- const n = q.createElement(r, t);
1673
- return yield* ye(n);
1674
- }),
1675
- compile: (e) => o.gen(function* () {
1676
- const t = X.get(e);
1677
- return t ? {
1678
- render: (r) => {
1679
- const n = q.createElement(t, r);
1680
- return ye(n);
1681
- }
1682
- } : yield* o.fail(
1683
- new pe({
1684
- message: `Template "${e}" not found`,
1685
- template: e
1686
- })
1687
- );
1688
- }),
1689
- exists: (e) => o.succeed(X.has(e))
1690
- });
1691
- p.succeed(
1692
- _e,
1693
- Ft()
1694
- );
1695
- const Zr = ({
1696
- userName: e,
1697
- verificationUrl: t,
1698
- expiresIn: r = "60 minutes",
1699
- appName: n = "Our App",
1700
- theme: s = R
1701
- }) => /* @__PURE__ */ d(H, { theme: s, preview: `Verify your email address for ${n}`, children: /* @__PURE__ */ u(j, { children: [
1702
- /* @__PURE__ */ d(D, { as: "h1", children: "Verify Your Email Address" }),
1703
- /* @__PURE__ */ u(f, { children: [
1704
- "Hi ",
1705
- e,
1706
- ","
1707
- ] }),
1708
- /* @__PURE__ */ u(f, { children: [
1709
- "Thank you for signing up for ",
1710
- n,
1711
- "! Please verify your email address by clicking the button below."
1712
- ] }),
1713
- /* @__PURE__ */ d(z, { href: t, children: "Verify Email Address" }),
1714
- /* @__PURE__ */ u(f, { muted: !0, children: [
1715
- "This verification link will expire in ",
1716
- r,
1717
- ". If you didn't create an account, you can safely ignore this email."
1718
- ] }),
1719
- /* @__PURE__ */ u(G, { type: "info", children: [
1720
- "If the button above doesn't work, copy and paste this URL into your browser: ",
1721
- t
1722
- ] })
1723
- ] }) }), en = ({
1724
- userName: e,
1725
- resetUrl: t,
1726
- expiresIn: r = "60 minutes",
1727
- appName: n = "Our App",
1728
- ipAddress: s,
1729
- theme: i = R
1730
- }) => /* @__PURE__ */ d(H, { theme: i, preview: `Reset your password for ${n}`, children: /* @__PURE__ */ u(j, { children: [
1731
- /* @__PURE__ */ d(D, { as: "h1", children: "Reset Your Password" }),
1732
- /* @__PURE__ */ u(f, { children: [
1733
- "Hi ",
1734
- e,
1735
- ","
1736
- ] }),
1737
- /* @__PURE__ */ u(f, { children: [
1738
- "We received a request to reset your password for your ",
1739
- n,
1740
- " ",
1741
- "account. Click the button below to set a new password."
1742
- ] }),
1743
- /* @__PURE__ */ d(z, { href: t, children: "Reset Password" }),
1744
- /* @__PURE__ */ u(f, { muted: !0, children: [
1745
- "This password reset link will expire in ",
1746
- r,
1747
- "."
1748
- ] }),
1749
- s && /* @__PURE__ */ u(f, { muted: !0, children: [
1750
- "This request was made from IP address: ",
1751
- s
1752
- ] }),
1753
- /* @__PURE__ */ d(G, { type: "warning", children: "If you didn't request a password reset, please ignore this email or contact support if you believe your account has been compromised." }),
1754
- /* @__PURE__ */ u(f, { muted: !0, children: [
1755
- "If the button above doesn't work, copy and paste this URL into your browser: ",
1756
- t
1757
- ] })
1758
- ] }) }), tn = ({
1759
- userName: e,
1760
- loginUrl: t,
1761
- appName: r = "Our App",
1762
- features: n = [],
1763
- theme: s = R
1764
- }) => /* @__PURE__ */ d(H, { theme: s, preview: `Welcome to ${r}!`, children: /* @__PURE__ */ u(j, { children: [
1765
- /* @__PURE__ */ u(D, { as: "h1", children: [
1766
- "Welcome to ",
1767
- r,
1768
- "!"
1769
- ] }),
1770
- /* @__PURE__ */ u(f, { children: [
1771
- "Hi ",
1772
- e,
1773
- ","
1774
- ] }),
1775
- /* @__PURE__ */ u(f, { children: [
1776
- "Thank you for joining ",
1777
- r,
1778
- "! We're excited to have you on board. Your account is now ready to use."
1779
- ] }),
1780
- /* @__PURE__ */ d(z, { href: t, children: "Get Started" }),
1781
- n.length > 0 && /* @__PURE__ */ u(ze, { children: [
1782
- /* @__PURE__ */ d(me, {}),
1783
- /* @__PURE__ */ d(D, { as: "h2", children: "What you can do:" }),
1784
- /* @__PURE__ */ d("ul", { children: n.map((i, a) => /* @__PURE__ */ d("li", { children: /* @__PURE__ */ d(f, { children: i }) }, a)) })
1785
- ] }),
1786
- /* @__PURE__ */ d(me, {}),
1787
- /* @__PURE__ */ d(f, { muted: !0, children: "If you have any questions, feel free to reply to this email. We're here to help!" })
1788
- ] }) }), rn = ({
1789
- userName: e,
1790
- loginTime: t,
1791
- ipAddress: r,
1792
- location: n,
1793
- device: s,
1794
- browser: i,
1795
- securityUrl: a,
1796
- appName: l = "Our App",
1797
- theme: c = R
1798
- }) => /* @__PURE__ */ d(H, { theme: c, preview: `New login to your ${l} account`, children: /* @__PURE__ */ u(j, { children: [
1799
- /* @__PURE__ */ d(D, { as: "h1", children: "New Login Detected" }),
1800
- /* @__PURE__ */ u(f, { children: [
1801
- "Hi ",
1802
- e,
1803
- ","
1804
- ] }),
1805
- /* @__PURE__ */ u(f, { children: [
1806
- "We detected a new login to your ",
1807
- l,
1808
- " account. If this was you, you can safely ignore this email."
1809
- ] }),
1810
- /* @__PURE__ */ u(Mt, { children: [
1811
- /* @__PURE__ */ u(f, { children: [
1812
- /* @__PURE__ */ d("strong", { children: "Time:" }),
1813
- " ",
1814
- t
1815
- ] }),
1816
- /* @__PURE__ */ u(f, { children: [
1817
- /* @__PURE__ */ d("strong", { children: "IP Address:" }),
1818
- " ",
1819
- r
1820
- ] }),
1821
- n && /* @__PURE__ */ u(f, { children: [
1822
- /* @__PURE__ */ d("strong", { children: "Location:" }),
1823
- " ",
1824
- n
1825
- ] }),
1826
- s && /* @__PURE__ */ u(f, { children: [
1827
- /* @__PURE__ */ d("strong", { children: "Device:" }),
1828
- " ",
1829
- s
1830
- ] }),
1831
- i && /* @__PURE__ */ u(f, { children: [
1832
- /* @__PURE__ */ d("strong", { children: "Browser:" }),
1833
- " ",
1834
- i
1835
- ] })
1836
- ] }),
1837
- /* @__PURE__ */ d(G, { type: "warning", children: "If you didn't sign in, your account may have been compromised. Please change your password immediately and review your account security." }),
1838
- /* @__PURE__ */ d(z, { href: a, children: "Review Account Security" }),
1839
- /* @__PURE__ */ d(f, { muted: !0, children: "For your security, we send these notifications whenever there's a new login to your account." })
1840
- ] }) }), nn = ({
1841
- userName: e,
1842
- changedAt: t,
1843
- ipAddress: r,
1844
- securityUrl: n,
1845
- appName: s = "Our App",
1846
- theme: i = R
1847
- }) => /* @__PURE__ */ d(H, { theme: i, preview: `Your ${s} password was changed`, children: /* @__PURE__ */ u(j, { children: [
1848
- /* @__PURE__ */ d(D, { as: "h1", children: "Password Changed" }),
1849
- /* @__PURE__ */ u(f, { children: [
1850
- "Hi ",
1851
- e,
1852
- ","
1853
- ] }),
1854
- /* @__PURE__ */ u(f, { children: [
1855
- "Your password for your ",
1856
- s,
1857
- " account was successfully changed on",
1858
- " ",
1859
- t,
1860
- "."
1861
- ] }),
1862
- r && /* @__PURE__ */ u(f, { muted: !0, children: [
1863
- "This change was made from IP address: ",
1864
- r
1865
- ] }),
1866
- /* @__PURE__ */ d(G, { type: "warning", children: "If you didn't make this change, your account may have been compromised. Please reset your password immediately and review your account security." }),
1867
- /* @__PURE__ */ d(z, { href: n, children: "Review Account Security" }),
1868
- /* @__PURE__ */ d(f, { muted: !0, children: "For your security, we send these notifications whenever your password is changed." })
1869
- ] }) });
1870
- class Ht extends Y {
1871
- getSubject() {
1872
- return `Verify your email address for ${this.getData().appName ?? "Our App"}`;
1873
- }
1874
- getContent() {
1875
- const t = this.getData();
1876
- return o.succeed({
1877
- subject: this.getSubject(),
1878
- template: {
1879
- name: "auth/verify-email",
1880
- data: {
1881
- userName: t.userName,
1882
- verificationUrl: t.verificationUrl,
1883
- expiresIn: t.expiresIn ?? "60 minutes",
1884
- appName: t.appName ?? "Our App"
1885
- }
1886
- }
1887
- });
1888
- }
1889
- }
1890
- const sn = (e) => new Ht().to(e.email).with(e);
1891
- class jt extends Y {
1892
- getSubject() {
1893
- return `Reset your password for ${this.getData().appName ?? "Our App"}`;
1894
- }
1895
- getContent() {
1896
- const t = this.getData();
1897
- return o.succeed({
1898
- subject: this.getSubject(),
1899
- template: {
1900
- name: "auth/reset-password",
1901
- data: {
1902
- userName: t.userName,
1903
- resetUrl: t.resetUrl,
1904
- expiresIn: t.expiresIn ?? "60 minutes",
1905
- appName: t.appName ?? "Our App",
1906
- ipAddress: t.ipAddress
1907
- }
1908
- }
1909
- });
1910
- }
1911
- }
1912
- const on = (e) => new jt().to(e.email).with(e);
1913
- class zt extends Y {
1914
- getSubject() {
1915
- return `Welcome to ${this.getData().appName ?? "Our App"}!`;
1916
- }
1917
- getContent() {
1918
- const t = this.getData();
1919
- return o.succeed({
1920
- subject: this.getSubject(),
1921
- template: {
1922
- name: "auth/welcome",
1923
- data: {
1924
- userName: t.userName,
1925
- loginUrl: t.loginUrl,
1926
- appName: t.appName ?? "Our App",
1927
- features: t.features ?? []
1928
- }
1929
- }
1930
- });
1931
- }
1932
- }
1933
- const an = (e) => new zt().to(e.email).with(e);
1934
- class Bt extends Y {
1935
- getSubject() {
1936
- return `New login to your ${this.getData().appName ?? "Our App"} account`;
1937
- }
1938
- getContent() {
1939
- const t = this.getData();
1940
- return o.succeed({
1941
- subject: this.getSubject(),
1942
- template: {
1943
- name: "auth/new-login",
1944
- data: {
1945
- userName: t.userName,
1946
- loginTime: t.loginTime,
1947
- ipAddress: t.ipAddress,
1948
- location: t.location,
1949
- device: t.device,
1950
- browser: t.browser,
1951
- securityUrl: t.securityUrl,
1952
- appName: t.appName ?? "Our App"
1953
- }
1954
- }
1955
- });
1956
- }
1957
- }
1958
- const cn = (e) => new Bt().to(e.email).with(e), Wt = () => {
1959
- const e = /* @__PURE__ */ new Map();
1960
- return {
1961
- create: (t) => o.sync(() => (e.set(t.id, t), t)),
1962
- findByToken: (t) => o.sync(() => {
1963
- for (const r of e.values())
1964
- if (r.token === t)
1965
- return m.some(r);
1966
- return m.none();
1967
- }),
1968
- findById: (t) => o.sync(() => {
1969
- const r = e.get(t);
1970
- return r ? m.some(r) : m.none();
1971
- }),
1972
- findByUser: (t) => o.sync(() => Array.from(e.values()).filter((r) => r.userId === t)),
1973
- updateLastUsed: (t, r) => o.sync(() => {
1974
- const n = e.get(t);
1975
- if (!n)
1976
- throw new re({
1977
- message: "Token not found",
1978
- tokenId: t
1979
- });
1980
- e.set(t, { ...n, lastUsedAt: r });
1981
- }),
1982
- delete: (t) => o.sync(() => {
1983
- if (!e.has(t))
1984
- throw new re({
1985
- message: "Token not found",
1986
- tokenId: t
1987
- });
1988
- e.delete(t);
1989
- }),
1990
- deleteByUser: (t) => o.sync(() => {
1991
- let r = 0;
1992
- for (const [n, s] of e)
1993
- s.userId === t && (e.delete(n), r++);
1994
- return r;
1995
- }),
1996
- deleteExpired: () => o.sync(() => {
1997
- const t = /* @__PURE__ */ new Date();
1998
- let r = 0;
1999
- for (const [n, s] of e)
2000
- s.expiresAt && s.expiresAt < t && (e.delete(n), r++);
2001
- return r;
2002
- })
2003
- };
2004
- }, qt = p.succeed(
2005
- ve,
2006
- Wt()
2007
- ), Jt = () => ({
2008
- hash: (e) => o.sync(() => `mock:${Buffer.from(e).toString("base64")}`),
2009
- verify: (e, t) => o.sync(() => {
2010
- if (!t.startsWith("mock:"))
2011
- return !1;
2012
- const r = Buffer.from(t.slice(5), "base64").toString("utf-8");
2013
- return e === r;
2014
- }),
2015
- needsRehash: (e) => !e.startsWith("mock:")
2016
- }), Vt = p.succeed(
2017
- xe,
2018
- Jt()
2019
- ), Gt = () => ({
2020
- hash: (e) => `hash:${Buffer.from(e).toString("base64")}`,
2021
- verify: (e, t) => {
2022
- if (!t.startsWith("hash:"))
2023
- return !1;
2024
- const r = Buffer.from(t.slice(5), "base64").toString("utf-8");
2025
- return e === r;
2026
- }
2027
- }), Yt = p.succeed(
2028
- be,
2029
- Gt()
2030
- ), Kt = (e = []) => {
2031
- const t = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map();
2032
- for (const n of e)
2033
- t.set(n.id, n), r.set(n.email.toLowerCase(), n);
2034
- return {
2035
- findById: (n) => o.sync(() => {
2036
- const s = t.get(n);
2037
- return s ? m.some(s) : m.none();
2038
- }),
2039
- findByEmail: (n) => o.sync(() => {
2040
- const s = r.get(n.toLowerCase());
2041
- return s ? m.some(s) : m.none();
2042
- }),
2043
- findByCredentials: (n) => o.sync(() => {
2044
- for (const s of t.values()) {
2045
- const i = s;
2046
- if (Object.entries(n).every(
2047
- ([l, c]) => i[l] === c
2048
- ))
2049
- return m.some(s);
2050
- }
2051
- return m.none();
2052
- })
2053
- };
2054
- }, Xt = (e = []) => p.succeed(Se, Kt(e)), ln = (e) => ({
2055
- id: Xe(crypto.randomUUID()),
2056
- password: "mock:dGVzdA==",
2057
- // "test" encoded
2058
- ...e
2059
- }), Qt = (e, t = {}) => {
2060
- const r = t.scopes ?? ["*"], n = t.tokenName ?? "test-token", s = {
2061
- id: Te(crypto.randomUUID()),
2062
- userId: e,
2063
- name: n,
2064
- token: Q("test-hashed-token"),
2065
- scopes: r,
2066
- createdAt: /* @__PURE__ */ new Date()
2067
- };
2068
- return {
2069
- id: e,
2070
- token: s
2071
- };
2072
- }, Oe = (e, t = {}) => {
2073
- const r = Qt(e, t);
2074
- return p.succeed(w, r);
2075
- }, Zt = (e, t, r) => r.pipe(o.provide(Oe(e, t))), dn = {
2076
- /**
2077
- * Run an effect as an authenticated user
2078
- */
2079
- actingAs: (e, t, r = {}) => Zt(e, r, t),
2080
- /**
2081
- * Create a layer for authenticated user
2082
- */
2083
- actingAsLayer: Oe
2084
- }, un = () => o.gen(function* () {
2085
- const e = yield* o.either(w);
2086
- return e._tag === "Left" ? yield* o.fail(
2087
- new A({
2088
- message: "Expected to be authenticated, but was not",
2089
- reason: "missing_token"
2090
- })
2091
- ) : e.right;
2092
- }), hn = () => o.gen(function* () {
2093
- if ((yield* o.either(w))._tag === "Right")
2094
- return yield* o.fail(
2095
- new Error("Expected to be guest, but was authenticated")
2096
- );
2097
- }), fn = (e, t) => o.gen(function* () {
2098
- if (!(yield* b).can(e, t))
2099
- return yield* o.fail(
2100
- new Error(`Expected to be able to ${e} ${String(t)}, but cannot`)
2101
- );
2102
- }), gn = (e, t) => o.gen(function* () {
2103
- if ((yield* b).can(e, t))
2104
- return yield* o.fail(
2105
- new Error(`Expected NOT to be able to ${e} ${String(t)}, but can`)
2106
- );
2107
- }), mn = (e) => o.gen(function* () {
2108
- const t = yield* w;
2109
- if (!t.token)
2110
- return yield* o.fail(
2111
- new Error("No token present to check scope")
2112
- );
2113
- if (!(t.token.scopes.includes("*") || t.token.scopes.includes(e)))
2114
- return yield* o.fail(
2115
- new Error(`Expected token to have scope "${e}", but it doesn't`)
2116
- );
2117
- }), pn = (e) => o.gen(function* () {
2118
- const t = yield* w;
2119
- if (!t.token)
2120
- return;
2121
- if (t.token.scopes.includes("*") || t.token.scopes.includes(e))
2122
- return yield* o.fail(
2123
- new Error(`Expected token NOT to have scope "${e}", but it does`)
2124
- );
2125
- }), er = (e = []) => p.mergeAll(
2126
- qt,
2127
- Vt,
2128
- Yt,
2129
- Xt(e)
2130
- ).pipe(
2131
- p.provideMerge(tt),
2132
- p.provideMerge(rt)
2133
- ), tr = it, yn = (e = []) => p.mergeAll(er(e), tr);
2134
- export {
2135
- Lr as AbilitiesLive,
2136
- b as AbilitiesTag,
2137
- Pe as AbstractProvider,
2138
- dn as Auth,
2139
- lr as AuthError,
2140
- cr as AuthGuard,
2141
- rt as AuthServiceLive,
2142
- Ae as AuthTag,
2143
- w as AuthenticatedUserTag,
2144
- A as AuthenticationError,
2145
- Pr as AuthorizationError,
2146
- Nr as CommonAbilities,
2147
- st as CsrfMismatchError,
2148
- Ue as CsrfToken,
2149
- dt as CsrfTokenTag,
2150
- V as CurrentSessionTag,
2151
- Me as ForbiddenError,
2152
- yn as FullTestAuthLayer,
2153
- Ce as GithubProvider,
2154
- Ne as GoogleProvider,
2155
- Q as HashedToken,
2156
- dr as HashingError,
2157
- Ze as InsufficientScopeError,
2158
- ur as InvalidPasswordError,
2159
- T as JwtError,
2160
- br as JwtServiceLive,
2161
- at as JwtServiceTag,
2162
- it as MemorySessionStoreLive,
2163
- Vt as MockPasswordHasherLive,
2164
- Yt as MockTokenHasherLive,
2165
- qt as MockTokenStoreLive,
2166
- Xt as MockUserProviderLive,
2167
- rn as NewLogin,
2168
- Bt as NewLoginMailable,
2169
- zr as OAuthConfigError,
2170
- jr as OAuthError,
2171
- fe as OAuthProviderNotFoundError,
2172
- mt as OAuthStateMismatchError,
2173
- I as OAuthTokenError,
2174
- K as OAuthUserError,
2175
- nn as PasswordChanged,
2176
- xe as PasswordHasherTag,
2177
- v as PersonalAccessToken,
2178
- Ke as PlainTextToken,
2179
- hr as RateLimitError,
2180
- en as ResetPassword,
2181
- jt as ResetPasswordMailable,
2182
- L as Session,
2183
- vr as SessionError,
2184
- xr as SessionExpiredError,
2185
- Ee as SessionId,
2186
- se as SessionNotFoundError,
2187
- F as SessionStoreTag,
2188
- Jr as Social,
2189
- qr as SocialLive,
2190
- W as SocialTag,
2191
- he as SocialToken,
2192
- Ie as SocialUser,
2193
- er as TestAuthLayer,
2194
- tr as TestSessionLayer,
2195
- Qe as TokenExpiredError,
2196
- be as TokenHasherTag,
2197
- Te as TokenId,
2198
- re as TokenNotFoundError,
2199
- tt as TokenServiceLive,
2200
- C as TokenServiceTag,
2201
- ve as TokenStoreTag,
2202
- Xe as UserId,
2203
- et as UserNotFoundError,
2204
- Se as UserProviderTag,
2205
- Zr as VerifyEmail,
2206
- Ht as VerifyEmailMailable,
2207
- tn as WelcomeEmail,
2208
- zt as WelcomeEmailMailable,
2209
- Zt as actingAs,
2210
- Oe as actingAsLayer,
2211
- un as assertAuthenticated,
2212
- fn as assertCan,
2213
- gn as assertCannot,
2214
- hn as assertGuest,
2215
- mn as assertHasScope,
2216
- pn as assertLacksScope,
2217
- ne as authenticate,
2218
- ft as authorize,
2219
- gt as authorizeAction,
2220
- _r as authorizeAll,
2221
- Or as authorizeAny,
2222
- gt as authorizeMiddleware,
2223
- Dr as can,
2224
- Rr as cannot,
2225
- ht as createAbilities,
2226
- Qt as createAuthenticatedUser,
2227
- Br as createGithubProvider,
2228
- Wr as createGoogleProvider,
2229
- ln as createMockUser,
2230
- $r as csrf,
2231
- mr as currentUser,
2232
- $e as defaultCsrfConfig,
2233
- Z as defaultSessionConfig,
2234
- Cr as defineAbilitiesFor,
2235
- Ar as endSession,
2236
- Mr as generateCsrfCookie,
2237
- Er as getSessionData,
2238
- N as getSubjectType,
2239
- gr as hasApiTokens,
2240
- wr as hasScope,
2241
- pr as isAuthenticated,
2242
- ct as makeJwtService,
2243
- ot as makeMemorySessionStore,
2244
- Jt as makeMockPasswordHasher,
2245
- Gt as makeMockTokenHasher,
2246
- Wt as makeMockTokenStore,
2247
- Kt as makeMockUserProvider,
2248
- yt as makeSocialService,
2249
- le as matchAction,
2250
- ue as matchConditions,
2251
- de as matchSubject,
2252
- cn as newLogin,
2253
- Fr as requireAdmin,
2254
- Hr as requireAny,
2255
- Tr as requireScope,
2256
- on as resetPassword,
2257
- ce as session,
2258
- Ur as setSessionData,
2259
- Sr as startSession,
2260
- kr as tokenScope,
2261
- yr as tokenScopes,
2262
- Ir as verifyCsrfToken,
2263
- sn as verifyEmail,
2264
- an as welcomeEmail,
2265
- fr as withApiTokens
2266
- };