@frequencyads/auth 0.1.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.
Files changed (49) hide show
  1. package/dist/chunk-JIENWB3K.mjs +89 -0
  2. package/dist/chunk-NS2JRZGO.mjs +38 -0
  3. package/dist/chunk-OKP757OV.mjs +131 -0
  4. package/dist/chunk-OUUVIDG6.mjs +63 -0
  5. package/dist/chunk-P4OKC4U7.mjs +41 -0
  6. package/dist/chunk-VBLFQXCD.mjs +406 -0
  7. package/dist/chunk-VQCPN62H.mjs +134 -0
  8. package/dist/chunk-XJFMS3SM.mjs +21 -0
  9. package/dist/components/auth-provider.d.mts +24 -0
  10. package/dist/components/auth-provider.d.ts +24 -0
  11. package/dist/components/auth-provider.js +107 -0
  12. package/dist/components/auth-provider.mjs +11 -0
  13. package/dist/components/login.d.mts +24 -0
  14. package/dist/components/login.d.ts +24 -0
  15. package/dist/components/login.js +430 -0
  16. package/dist/components/login.mjs +9 -0
  17. package/dist/components/reset-password.d.mts +11 -0
  18. package/dist/components/reset-password.d.ts +11 -0
  19. package/dist/components/reset-password.js +283 -0
  20. package/dist/components/reset-password.mjs +10 -0
  21. package/dist/components/sign-out-button.d.mts +11 -0
  22. package/dist/components/sign-out-button.d.ts +11 -0
  23. package/dist/components/sign-out-button.js +90 -0
  24. package/dist/components/sign-out-button.mjs +11 -0
  25. package/dist/components/user-menu.d.mts +5 -0
  26. package/dist/components/user-menu.d.ts +5 -0
  27. package/dist/components/user-menu.js +107 -0
  28. package/dist/components/user-menu.mjs +11 -0
  29. package/dist/components/verify-code.d.mts +20 -0
  30. package/dist/components/verify-code.d.ts +20 -0
  31. package/dist/components/verify-code.js +155 -0
  32. package/dist/components/verify-code.mjs +9 -0
  33. package/dist/index.d.mts +44 -0
  34. package/dist/index.d.ts +44 -0
  35. package/dist/index.js +1006 -0
  36. package/dist/index.mjs +159 -0
  37. package/dist/middleware.d.mts +29 -0
  38. package/dist/middleware.d.ts +29 -0
  39. package/dist/middleware.js +114 -0
  40. package/dist/middleware.mjs +83 -0
  41. package/dist/proxy.d.mts +9 -0
  42. package/dist/proxy.d.ts +9 -0
  43. package/dist/proxy.js +71 -0
  44. package/dist/proxy.mjs +41 -0
  45. package/dist/request.d.mts +14 -0
  46. package/dist/request.d.ts +14 -0
  47. package/dist/request.js +46 -0
  48. package/dist/request.mjs +8 -0
  49. package/package.json +101 -0
package/dist/index.js ADDED
@@ -0,0 +1,1006 @@
1
+ 'use client';
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __defProps = Object.defineProperties;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __spreadValues = (a, b) => {
13
+ for (var prop in b || (b = {}))
14
+ if (__hasOwnProp.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ if (__getOwnPropSymbols)
17
+ for (var prop of __getOwnPropSymbols(b)) {
18
+ if (__propIsEnum.call(b, prop))
19
+ __defNormalProp(a, prop, b[prop]);
20
+ }
21
+ return a;
22
+ };
23
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
+ var __objRest = (source, exclude) => {
25
+ var target = {};
26
+ for (var prop in source)
27
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
28
+ target[prop] = source[prop];
29
+ if (source != null && __getOwnPropSymbols)
30
+ for (var prop of __getOwnPropSymbols(source)) {
31
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
32
+ target[prop] = source[prop];
33
+ }
34
+ return target;
35
+ };
36
+ var __export = (target, all) => {
37
+ for (var name in all)
38
+ __defProp(target, name, { get: all[name], enumerable: true });
39
+ };
40
+ var __copyProps = (to, from, except, desc) => {
41
+ if (from && typeof from === "object" || typeof from === "function") {
42
+ for (let key of __getOwnPropNames(from))
43
+ if (!__hasOwnProp.call(to, key) && key !== except)
44
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
45
+ }
46
+ return to;
47
+ };
48
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
49
+
50
+ // src/index.ts
51
+ var src_exports = {};
52
+ __export(src_exports, {
53
+ AuthProvider: () => AuthProvider,
54
+ LoginPage: () => LoginPage,
55
+ ResetPasswordForm: () => ResetPasswordForm,
56
+ SignOutButton: () => SignOutButton,
57
+ UserMenu: () => UserMenu,
58
+ VerifyCodeForm: () => VerifyCodeForm,
59
+ createAuthMiddleware: () => createAuthMiddleware,
60
+ defaultMatcher: () => defaultMatcher,
61
+ getSignOutUrl: () => getSignOutUrl,
62
+ updateSession: () => updateSession,
63
+ useAuth: () => useAuth
64
+ });
65
+ module.exports = __toCommonJS(src_exports);
66
+
67
+ // src/lib/proxy.ts
68
+ var import_ssr = require("@supabase/ssr");
69
+ var import_server = require("next/server");
70
+ var import_config = require("@frequencyads/db/config");
71
+ var import_cookies = require("@frequencyads/db/cookies");
72
+
73
+ // src/lib/request.ts
74
+ var isDev = process.env.NODE_ENV === "development";
75
+ function getRequestOrigin(request) {
76
+ var _a;
77
+ if (!isDev) {
78
+ return request.nextUrl.origin;
79
+ }
80
+ const host = (_a = request.headers.get("host")) != null ? _a : request.nextUrl.host;
81
+ return `${request.nextUrl.protocol}//${host}`;
82
+ }
83
+
84
+ // src/lib/proxy.ts
85
+ async function updateSession(request) {
86
+ var _a;
87
+ let supabaseResponse = import_server.NextResponse.next({ request });
88
+ const hostname = new URL(getRequestOrigin(request)).hostname;
89
+ const cookieDomain = (0, import_cookies.deriveCookieDomain)(hostname, (0, import_config.getTrustedDomains)());
90
+ const cookieOptions = cookieDomain ? { domain: cookieDomain } : void 0;
91
+ const supabase = (0, import_ssr.createServerClient)((0, import_config.getSupabaseUrl)(), (0, import_config.getSupabasePublishableKey)(), {
92
+ cookieOptions,
93
+ cookies: {
94
+ getAll() {
95
+ return request.cookies.getAll();
96
+ },
97
+ setAll(cookiesToSet) {
98
+ cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value));
99
+ supabaseResponse = import_server.NextResponse.next({ request });
100
+ cookiesToSet.forEach(
101
+ ({ name, value, options }) => supabaseResponse.cookies.set(name, value, options)
102
+ );
103
+ }
104
+ }
105
+ });
106
+ const { data } = await supabase.auth.getClaims();
107
+ const claims = (_a = data == null ? void 0 : data.claims) != null ? _a : null;
108
+ return { supabaseResponse, claims };
109
+ }
110
+
111
+ // src/components/auth-provider.tsx
112
+ var import_react = require("react");
113
+ var import_client = require("@frequencyads/db/client");
114
+ var import_jsx_runtime = require("react/jsx-runtime");
115
+ var Context = (0, import_react.createContext)(void 0);
116
+ function AuthProvider({ children, loginUrl }) {
117
+ var _a, _b, _c, _d;
118
+ const [supabase] = (0, import_react.useState)(() => (0, import_client.createBrowserClient)());
119
+ const [user, setUser] = (0, import_react.useState)(null);
120
+ const [loading, setLoading] = (0, import_react.useState)(true);
121
+ const userIdRef = (0, import_react.useRef)(null);
122
+ const setUserStable = (0, import_react.useCallback)((newUser) => {
123
+ var _a2;
124
+ const newId = (_a2 = newUser == null ? void 0 : newUser.id) != null ? _a2 : null;
125
+ if (newId !== userIdRef.current) {
126
+ userIdRef.current = newId;
127
+ setUser(newUser);
128
+ }
129
+ }, []);
130
+ (0, import_react.useEffect)(() => {
131
+ if (!supabase) {
132
+ setLoading(false);
133
+ return;
134
+ }
135
+ const {
136
+ data: { subscription }
137
+ } = supabase.auth.onAuthStateChange((_event, session) => {
138
+ var _a2;
139
+ setUserStable((_a2 = session == null ? void 0 : session.user) != null ? _a2 : null);
140
+ setLoading(false);
141
+ });
142
+ async function checkSession() {
143
+ const {
144
+ data: { session }
145
+ } = await supabase.auth.getSession();
146
+ if (!session) {
147
+ await supabase.auth.signOut({ scope: "local" });
148
+ }
149
+ }
150
+ const POLL_MS = 3e4;
151
+ const interval = setInterval(checkSession, POLL_MS);
152
+ const handleVisibilityChange = () => {
153
+ if (document.visibilityState === "visible") {
154
+ checkSession();
155
+ }
156
+ };
157
+ document.addEventListener("visibilitychange", handleVisibilityChange);
158
+ return () => {
159
+ subscription.unsubscribe();
160
+ clearInterval(interval);
161
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
162
+ };
163
+ }, [supabase]);
164
+ (0, import_react.useEffect)(() => {
165
+ if (loading || user) return;
166
+ const url = loginUrl != null ? loginUrl : `${process.env.NEXT_PUBLIC_ACCOUNTS_URL}/login`;
167
+ if (url) {
168
+ window.location.href = `${url}?next=${encodeURIComponent(window.location.href)}`;
169
+ }
170
+ }, [loading, user, loginUrl]);
171
+ const profile = {
172
+ name: (_b = (_a = user == null ? void 0 : user.user_metadata) == null ? void 0 : _a.full_name) != null ? _b : "\u2014",
173
+ email: (_c = user == null ? void 0 : user.email) != null ? _c : "",
174
+ avatarUrl: (_d = user == null ? void 0 : user.user_metadata) == null ? void 0 : _d.avatar_url
175
+ };
176
+ if (loading || !user) return null;
177
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Context.Provider, { value: { supabase, user, profile, loading }, children });
178
+ }
179
+ function useAuth() {
180
+ const context = (0, import_react.useContext)(Context);
181
+ if (context === void 0) {
182
+ throw new Error("useAuth must be used within an AuthProvider");
183
+ }
184
+ return context;
185
+ }
186
+
187
+ // src/components/login/index.tsx
188
+ var import_react4 = require("react");
189
+ var import_core3 = require("@mantine/core");
190
+ var import_icons_react = require("@tabler/icons-react");
191
+
192
+ // src/components/login/email-password-form.tsx
193
+ var import_react2 = require("react");
194
+ var import_core = require("@mantine/core");
195
+ var import_client2 = require("@frequencyads/db/client");
196
+ var import_jsx_runtime2 = require("react/jsx-runtime");
197
+ function EmailPasswordForm({
198
+ isPending,
199
+ startTransition,
200
+ onVerifyNeeded,
201
+ onResetRequest,
202
+ onSuccess
203
+ }) {
204
+ const supabase = (0, import_client2.createBrowserClient)();
205
+ const [step, setStep] = (0, import_react2.useState)("email");
206
+ const [mode, setMode] = (0, import_react2.useState)("signin");
207
+ const [email, setEmail] = (0, import_react2.useState)("");
208
+ const [password, setPassword] = (0, import_react2.useState)("");
209
+ const [confirmPassword, setConfirmPassword] = (0, import_react2.useState)("");
210
+ const [firstName, setFirstName] = (0, import_react2.useState)("");
211
+ const [lastName, setLastName] = (0, import_react2.useState)("");
212
+ const [error, setError] = (0, import_react2.useState)(null);
213
+ const goBack = () => {
214
+ setStep("email");
215
+ setPassword("");
216
+ setConfirmPassword("");
217
+ setError(null);
218
+ };
219
+ const toggleMode = () => {
220
+ setMode((m) => m === "signin" ? "signup" : "signin");
221
+ setStep("email");
222
+ setPassword("");
223
+ setConfirmPassword("");
224
+ setFirstName("");
225
+ setLastName("");
226
+ setError(null);
227
+ };
228
+ const validateEmail = () => {
229
+ const trimmed = email.trim();
230
+ if (!trimmed) {
231
+ setError("Email is required.");
232
+ return false;
233
+ }
234
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) {
235
+ setError("Please enter a valid email address.");
236
+ return false;
237
+ }
238
+ return true;
239
+ };
240
+ const handleContinue = (e) => {
241
+ e.preventDefault();
242
+ setError(null);
243
+ if (validateEmail()) {
244
+ setStep("credentials");
245
+ }
246
+ };
247
+ const handleSignIn = (e) => {
248
+ e.preventDefault();
249
+ setError(null);
250
+ if (!validateEmail()) return;
251
+ if (!password.trim()) {
252
+ setError("Password is required.");
253
+ return;
254
+ }
255
+ startTransition(async () => {
256
+ const { error: signInError } = await supabase.auth.signInWithPassword({
257
+ email: email.trim(),
258
+ password: password.trim()
259
+ });
260
+ if (signInError) {
261
+ if (signInError.message === "Email not confirmed") {
262
+ onVerifyNeeded == null ? void 0 : onVerifyNeeded(email);
263
+ } else {
264
+ setError(signInError.message);
265
+ }
266
+ } else {
267
+ onSuccess == null ? void 0 : onSuccess();
268
+ }
269
+ });
270
+ };
271
+ const handleSignUp = (e) => {
272
+ e.preventDefault();
273
+ setError(null);
274
+ if (!firstName.trim()) {
275
+ setError("First name is required.");
276
+ return;
277
+ }
278
+ if (!lastName.trim()) {
279
+ setError("Last name is required.");
280
+ return;
281
+ }
282
+ if (!password.trim()) {
283
+ setError("Password is required.");
284
+ return;
285
+ }
286
+ if (password.trim().length < 8) {
287
+ setError("Password must be at least 8 characters.");
288
+ return;
289
+ }
290
+ const trimmedPassword = password.trim();
291
+ if (trimmedPassword !== confirmPassword.trim()) {
292
+ setError("Passwords do not match.");
293
+ return;
294
+ }
295
+ startTransition(async () => {
296
+ const fullName = `${firstName.trim()} ${lastName.trim()}`;
297
+ const { data: signUpData, error: signUpError } = await supabase.auth.signUp({
298
+ email: email.trim(),
299
+ password: trimmedPassword,
300
+ options: {
301
+ data: {
302
+ name: fullName,
303
+ full_name: fullName,
304
+ first_name: firstName.trim(),
305
+ last_name: lastName.trim()
306
+ }
307
+ }
308
+ });
309
+ if (signUpError) {
310
+ setError(signUpError.message);
311
+ } else if (signUpData.session) {
312
+ onSuccess == null ? void 0 : onSuccess();
313
+ } else {
314
+ onVerifyNeeded == null ? void 0 : onVerifyNeeded(email);
315
+ }
316
+ });
317
+ };
318
+ if (mode === "signin") {
319
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("form", { onSubmit: handleSignIn, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core.Stack, { children: [
320
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
321
+ import_core.TextInput,
322
+ {
323
+ label: "Email",
324
+ placeholder: "you@frequency.media",
325
+ type: "email",
326
+ value: email,
327
+ onChange: (e) => setEmail(e.currentTarget.value),
328
+ disabled: isPending,
329
+ required: true
330
+ }
331
+ ),
332
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
333
+ import_core.PasswordInput,
334
+ {
335
+ label: "Password",
336
+ placeholder: "Your password",
337
+ value: password,
338
+ onChange: (e) => setPassword(e.currentTarget.value),
339
+ disabled: isPending,
340
+ required: true
341
+ }
342
+ ),
343
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Text, { size: "sm", c: "red", children: error }),
344
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Button, { fullWidth: true, size: "md", type: "submit", loading: isPending, children: "Sign in" }),
345
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core.Group, { justify: "space-between", children: [
346
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
347
+ import_core.Anchor,
348
+ {
349
+ component: "button",
350
+ type: "button",
351
+ size: "sm",
352
+ onClick: toggleMode,
353
+ disabled: isPending,
354
+ children: "Don't have an account?"
355
+ }
356
+ ),
357
+ onResetRequest && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
358
+ import_core.Anchor,
359
+ {
360
+ component: "button",
361
+ type: "button",
362
+ size: "sm",
363
+ onClick: onResetRequest,
364
+ disabled: isPending,
365
+ children: "Forgot password?"
366
+ }
367
+ )
368
+ ] })
369
+ ] }) });
370
+ }
371
+ if (step === "email") {
372
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("form", { onSubmit: handleContinue, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core.Stack, { children: [
373
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
374
+ import_core.TextInput,
375
+ {
376
+ label: "Email",
377
+ placeholder: "you@frequency.media",
378
+ type: "email",
379
+ value: email,
380
+ onChange: (e) => setEmail(e.currentTarget.value),
381
+ required: true
382
+ }
383
+ ),
384
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Text, { size: "sm", c: "red", children: error }),
385
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Button, { fullWidth: true, size: "md", type: "submit", children: "Continue" }),
386
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Anchor, { component: "button", type: "button", size: "sm", onClick: toggleMode, children: "Already have an account?" })
387
+ ] }) });
388
+ }
389
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("form", { onSubmit: handleSignUp, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core.Stack, { children: [
390
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core.Group, { gap: "xs", align: "baseline", children: [
391
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Text, { size: "sm", c: "dimmed", children: email }),
392
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Anchor, { component: "button", type: "button", size: "sm", onClick: goBack, disabled: isPending, children: "Change" })
393
+ ] }),
394
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_core.Group, { grow: true, children: [
395
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
396
+ import_core.TextInput,
397
+ {
398
+ label: "First name",
399
+ placeholder: "Jane",
400
+ value: firstName,
401
+ onChange: (e) => setFirstName(e.currentTarget.value),
402
+ disabled: isPending,
403
+ required: true
404
+ }
405
+ ),
406
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
407
+ import_core.TextInput,
408
+ {
409
+ label: "Last name",
410
+ placeholder: "Doe",
411
+ value: lastName,
412
+ onChange: (e) => setLastName(e.currentTarget.value),
413
+ disabled: isPending,
414
+ required: true
415
+ }
416
+ )
417
+ ] }),
418
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
419
+ import_core.PasswordInput,
420
+ {
421
+ label: "Password",
422
+ placeholder: "At least 8 characters",
423
+ value: password,
424
+ onChange: (e) => setPassword(e.currentTarget.value),
425
+ disabled: isPending,
426
+ required: true
427
+ }
428
+ ),
429
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
430
+ import_core.PasswordInput,
431
+ {
432
+ label: "Confirm password",
433
+ placeholder: "Repeat your password",
434
+ value: confirmPassword,
435
+ onChange: (e) => setConfirmPassword(e.currentTarget.value),
436
+ disabled: isPending,
437
+ required: true
438
+ }
439
+ ),
440
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Text, { size: "sm", c: "red", children: error }),
441
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Button, { fullWidth: true, size: "md", type: "submit", loading: isPending, children: "Create account" }),
442
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
443
+ import_core.Anchor,
444
+ {
445
+ component: "button",
446
+ type: "button",
447
+ size: "sm",
448
+ onClick: toggleMode,
449
+ disabled: isPending,
450
+ children: "Already have an account?"
451
+ }
452
+ )
453
+ ] }) });
454
+ }
455
+
456
+ // src/components/login/google-sign-in.tsx
457
+ var import_react3 = require("react");
458
+ var import_core2 = require("@mantine/core");
459
+ var import_client3 = require("@frequencyads/db/client");
460
+ var import_jsx_runtime3 = require("react/jsx-runtime");
461
+ function GoogleIcon() {
462
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", xmlns: "http://www.w3.org/2000/svg", children: [
463
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
464
+ "path",
465
+ {
466
+ d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.875 2.684-6.615z",
467
+ fill: "#4285F4"
468
+ }
469
+ ),
470
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
471
+ "path",
472
+ {
473
+ d: "M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z",
474
+ fill: "#34A853"
475
+ }
476
+ ),
477
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
478
+ "path",
479
+ {
480
+ d: "M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.997 8.997 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z",
481
+ fill: "#FBBC05"
482
+ }
483
+ ),
484
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
485
+ "path",
486
+ {
487
+ d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z",
488
+ fill: "#EA4335"
489
+ }
490
+ )
491
+ ] });
492
+ }
493
+ function GoogleSignIn({ redirectTo, isPending }) {
494
+ const supabase = (0, import_client3.createBrowserClient)();
495
+ const [loading, setLoading] = (0, import_react3.useState)(false);
496
+ const handleGoogleLogin = async () => {
497
+ setLoading(true);
498
+ await supabase.auth.signInWithOAuth({
499
+ provider: "google",
500
+ options: {
501
+ redirectTo: redirectTo != null ? redirectTo : `${window.location.origin}/auth/callback`,
502
+ queryParams: { prompt: "select_account" }
503
+ }
504
+ });
505
+ };
506
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
507
+ import_core2.Button,
508
+ {
509
+ type: "button",
510
+ fullWidth: true,
511
+ size: "md",
512
+ variant: "default",
513
+ leftSection: loading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core2.Loader, { size: 18 }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GoogleIcon, {}),
514
+ onClick: handleGoogleLogin,
515
+ disabled: isPending || loading,
516
+ styles: {
517
+ root: {
518
+ fontWeight: 500,
519
+ height: 44,
520
+ backgroundColor: "var(--mantine-color-white)",
521
+ color: "var(--mantine-color-gray-9)",
522
+ borderColor: "var(--mantine-color-gray-3)"
523
+ }
524
+ },
525
+ children: "Sign in with Google"
526
+ }
527
+ );
528
+ }
529
+
530
+ // src/components/login/index.tsx
531
+ var import_jsx_runtime4 = require("react/jsx-runtime");
532
+ function LoginPage({
533
+ title = "Sign in",
534
+ description = "Authenticate once. Operate everywhere.",
535
+ info,
536
+ redirectTo,
537
+ header,
538
+ footer,
539
+ onVerifyNeeded,
540
+ onResetRequest,
541
+ onSuccess
542
+ }) {
543
+ const [isPending, startTransition] = (0, import_react4.useTransition)();
544
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core3.Box, { w: "100%", children: [
545
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core3.Box, { maw: 460, children: [
546
+ header && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.Box, { mb: "lg", ta: "center", children: header }),
547
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core3.Title, { order: 3, fw: 600, c: "gray.7", mb: "xs", children: [
548
+ title,
549
+ info && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core3.Box, { component: "span", style: { whiteSpace: "nowrap" }, children: [
550
+ "\xA0",
551
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_core3.HoverCard, { width: 300, shadow: "md", withArrow: true, position: "bottom-start", openDelay: 100, children: [
552
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.HoverCard.Target, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
553
+ import_core3.ActionIcon,
554
+ {
555
+ variant: "subtle",
556
+ color: "gray",
557
+ size: "sm",
558
+ display: "inline-flex",
559
+ style: { verticalAlign: "middle" },
560
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_icons_react.IconInfoCircle, { size: 16 })
561
+ }
562
+ ) }),
563
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.HoverCard.Dropdown, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.Text, { size: "xs", c: "dimmed", lh: 1.6, children: info }) })
564
+ ] })
565
+ ] })
566
+ ] }),
567
+ description && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.Text, { size: "sm", c: "gray.6", mb: "lg", children: description }),
568
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
569
+ EmailPasswordForm,
570
+ {
571
+ isPending,
572
+ startTransition,
573
+ onVerifyNeeded,
574
+ onResetRequest,
575
+ onSuccess
576
+ }
577
+ ),
578
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.Divider, { my: "lg", label: "or continue with", labelPosition: "center", color: "gray.3" }),
579
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GoogleSignIn, { redirectTo, isPending })
580
+ ] }),
581
+ footer && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
582
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.Divider, { my: "lg", color: "gray.3" }),
583
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.Box, { ta: "left", w: "100%", children: footer })
584
+ ] })
585
+ ] });
586
+ }
587
+
588
+ // src/components/sign-out-button.tsx
589
+ var import_core4 = require("@mantine/core");
590
+ var import_icons_react2 = require("@tabler/icons-react");
591
+ var import_jsx_runtime5 = require("react/jsx-runtime");
592
+ function getSignOutUrl(returnTo) {
593
+ const accountsUrl = process.env.NEXT_PUBLIC_ACCOUNTS_URL;
594
+ if (!accountsUrl) return "#";
595
+ const next = returnTo != null ? returnTo : window.location.origin;
596
+ return `${accountsUrl}/logout?next=${encodeURIComponent(next)}`;
597
+ }
598
+ function SignOutButton(_a) {
599
+ var _b = _a, { returnTo } = _b, props = __objRest(_b, ["returnTo"]);
600
+ var _a2;
601
+ const handleClick = () => {
602
+ window.location.href = getSignOutUrl(returnTo);
603
+ };
604
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
605
+ import_core4.Button,
606
+ __spreadProps(__spreadValues({
607
+ onClick: handleClick,
608
+ variant: "light",
609
+ color: "red",
610
+ leftSection: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_icons_react2.IconLogout, { size: 16 }),
611
+ w: "fit-content"
612
+ }, props), {
613
+ children: (_a2 = props.children) != null ? _a2 : "Sign out"
614
+ })
615
+ );
616
+ }
617
+
618
+ // src/components/user-menu.tsx
619
+ var import_core5 = require("@mantine/core");
620
+ var import_icons_react3 = require("@tabler/icons-react");
621
+ var import_react5 = require("react");
622
+ var import_jsx_runtime6 = require("react/jsx-runtime");
623
+ function UserMenu() {
624
+ const { user, profile } = useAuth();
625
+ const [opened, setOpened] = (0, import_react5.useState)(false);
626
+ if (!user) return null;
627
+ const handleLogout = () => {
628
+ window.location.href = getSignOutUrl();
629
+ };
630
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
631
+ import_core5.Menu,
632
+ {
633
+ width: 260,
634
+ position: "bottom-end",
635
+ transitionProps: { transition: "pop-top-right" },
636
+ opened,
637
+ onChange: setOpened,
638
+ children: [
639
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_core5.Menu.Target, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
640
+ import_core5.UnstyledButton,
641
+ {
642
+ style: {
643
+ padding: "var(--mantine-spacing-xs)",
644
+ borderRadius: "var(--mantine-radius-sm)",
645
+ transition: "background-color 100ms ease"
646
+ },
647
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_core5.Group, { gap: 7, children: [
648
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_core5.Avatar, { src: profile.avatarUrl, alt: profile.name, radius: "xl", size: 32 }),
649
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_core5.Text, { fw: 500, size: "sm", lh: 1, mr: 3, children: profile.name }),
650
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_icons_react3.IconChevronDown, { style: { width: (0, import_core5.rem)(12), height: (0, import_core5.rem)(12) }, stroke: 1.5 })
651
+ ] })
652
+ }
653
+ ) }),
654
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_core5.Menu.Dropdown, { children: [
655
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_core5.Menu.Label, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_core5.Text, { size: "xs", c: "dimmed", truncate: true, children: profile.email }) }),
656
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
657
+ import_core5.Menu.Item,
658
+ {
659
+ leftSection: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_icons_react3.IconLogout, { style: { width: (0, import_core5.rem)(16), height: (0, import_core5.rem)(16) }, stroke: 1.5 }),
660
+ onClick: handleLogout,
661
+ children: "Sign out"
662
+ }
663
+ )
664
+ ] })
665
+ ]
666
+ }
667
+ );
668
+ }
669
+
670
+ // src/components/verify-code.tsx
671
+ var import_react6 = require("react");
672
+ var import_core6 = require("@mantine/core");
673
+ var import_client4 = require("@frequencyads/db/client");
674
+ var import_jsx_runtime7 = require("react/jsx-runtime");
675
+ function VerifyCodeForm({
676
+ email,
677
+ type,
678
+ onSuccess,
679
+ onResend,
680
+ onBack,
681
+ backLabel = "Back to sign in",
682
+ header
683
+ }) {
684
+ const [code, setCode] = (0, import_react6.useState)("");
685
+ const [error, setError] = (0, import_react6.useState)(null);
686
+ const [loading, setLoading] = (0, import_react6.useState)(false);
687
+ const [verified, setVerified] = (0, import_react6.useState)(false);
688
+ const [resendCooldown, setResendCooldown] = (0, import_react6.useState)(0);
689
+ (0, import_react6.useEffect)(() => {
690
+ if (resendCooldown <= 0) return;
691
+ const timer = setTimeout(() => setResendCooldown((c) => c - 1), 1e3);
692
+ return () => clearTimeout(timer);
693
+ }, [resendCooldown]);
694
+ const handleVerify = (0, import_react6.useCallback)(
695
+ async (value) => {
696
+ if (value.length !== 6) return;
697
+ setError(null);
698
+ setLoading(true);
699
+ try {
700
+ const supabase = (0, import_client4.createBrowserClient)();
701
+ const { error: verifyError } = await supabase.auth.verifyOtp({
702
+ email,
703
+ token: value,
704
+ type
705
+ });
706
+ if (verifyError) {
707
+ setError("This code is invalid or has expired. Please request a new one.");
708
+ setCode("");
709
+ } else {
710
+ setVerified(true);
711
+ onSuccess();
712
+ }
713
+ } finally {
714
+ setLoading(false);
715
+ }
716
+ },
717
+ [email, type, onSuccess]
718
+ );
719
+ const [resending, setResending] = (0, import_react6.useState)(false);
720
+ const handleResend = async () => {
721
+ setError(null);
722
+ setResending(true);
723
+ try {
724
+ const result = await onResend();
725
+ if (result.error) {
726
+ setError(result.error);
727
+ } else {
728
+ setResendCooldown(60);
729
+ }
730
+ } finally {
731
+ setResending(false);
732
+ }
733
+ };
734
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_core6.Box, { w: "100%", maw: 460, children: [
735
+ header && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_core6.Box, { mb: "lg", style: { textAlign: "center" }, children: header }),
736
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_core6.Title, { order: 3, fw: 600, mb: "xs", c: "gray.7", children: type === "email" ? "Verify your email" : "Enter reset code" }),
737
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_core6.Text, { size: "sm", c: "gray.6", mb: "lg", children: [
738
+ "We sent a 6-digit code to ",
739
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: email })
740
+ ] }),
741
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_core6.Stack, { children: [
742
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
743
+ import_core6.PinInput,
744
+ {
745
+ length: 6,
746
+ type: "number",
747
+ oneTimeCode: true,
748
+ autoFocus: true,
749
+ size: "lg",
750
+ value: code,
751
+ onChange: (value) => {
752
+ setCode(value);
753
+ if (value.length > 0) setError(null);
754
+ },
755
+ onComplete: handleVerify,
756
+ error: !!error,
757
+ disabled: loading || verified,
758
+ styles: { input: { fontWeight: 600, fontSize: 20 } }
759
+ }
760
+ ),
761
+ error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_core6.Text, { size: "sm", c: "red", children: error }),
762
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
763
+ import_core6.Button,
764
+ {
765
+ fullWidth: true,
766
+ size: "md",
767
+ loading: loading || verified,
768
+ onClick: () => handleVerify(code),
769
+ children: "Verify"
770
+ }
771
+ ),
772
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_core6.Text, { size: "sm", c: "gray.6", ta: "center", children: [
773
+ "Didn't receive the code?",
774
+ " ",
775
+ resendCooldown > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_core6.Text, { span: true, c: "gray.5", children: [
776
+ "Resend in ",
777
+ resendCooldown,
778
+ "s"
779
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
780
+ import_core6.Anchor,
781
+ {
782
+ component: "button",
783
+ type: "button",
784
+ size: "sm",
785
+ onClick: handleResend,
786
+ disabled: resending,
787
+ children: resending ? "Sending\u2026" : "Resend code"
788
+ }
789
+ )
790
+ ] }),
791
+ onBack && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_core6.Anchor, { component: "button", type: "button", size: "sm", onClick: onBack, ta: "center", children: backLabel })
792
+ ] })
793
+ ] });
794
+ }
795
+
796
+ // src/components/reset-password.tsx
797
+ var import_react7 = require("react");
798
+ var import_core7 = require("@mantine/core");
799
+ var import_client5 = require("@frequencyads/db/client");
800
+ var import_jsx_runtime8 = require("react/jsx-runtime");
801
+ function ResetPasswordForm({ onComplete, onBackToLogin, header }) {
802
+ const supabase = (0, import_client5.createBrowserClient)();
803
+ const [step, setStep] = (0, import_react7.useState)("email");
804
+ const [email, setEmail] = (0, import_react7.useState)("");
805
+ const [password, setPassword] = (0, import_react7.useState)("");
806
+ const [confirmPassword, setConfirmPassword] = (0, import_react7.useState)("");
807
+ const [error, setError] = (0, import_react7.useState)(null);
808
+ const [loading, setLoading] = (0, import_react7.useState)(false);
809
+ const handleRequestReset = async (e) => {
810
+ e.preventDefault();
811
+ setError(null);
812
+ if (!email.trim()) {
813
+ setError("Email is required.");
814
+ return;
815
+ }
816
+ setLoading(true);
817
+ try {
818
+ const { error: resetError } = await supabase.auth.resetPasswordForEmail(email);
819
+ if (resetError) {
820
+ setError(resetError.message);
821
+ } else {
822
+ setStep("code");
823
+ }
824
+ } finally {
825
+ setLoading(false);
826
+ }
827
+ };
828
+ const handleSetPassword = async (e) => {
829
+ e.preventDefault();
830
+ setError(null);
831
+ if (password.length < 8) {
832
+ setError("Password must be at least 8 characters.");
833
+ return;
834
+ }
835
+ if (password !== confirmPassword) {
836
+ setError("Passwords do not match.");
837
+ return;
838
+ }
839
+ setLoading(true);
840
+ try {
841
+ const { error: updateError } = await supabase.auth.updateUser({ password });
842
+ if (updateError) {
843
+ setError(updateError.message);
844
+ } else {
845
+ onComplete();
846
+ }
847
+ } finally {
848
+ setLoading(false);
849
+ }
850
+ };
851
+ if (step === "code") {
852
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
853
+ VerifyCodeForm,
854
+ {
855
+ email,
856
+ type: "recovery",
857
+ onSuccess: () => setStep("password"),
858
+ onResend: async () => {
859
+ const { error: resendError } = await supabase.auth.resetPasswordForEmail(email);
860
+ return { error: resendError == null ? void 0 : resendError.message };
861
+ },
862
+ onBack: onBackToLogin,
863
+ header
864
+ }
865
+ );
866
+ }
867
+ if (step === "password") {
868
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_core7.Box, { w: "100%", maw: 460, children: [
869
+ header && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Box, { mb: "lg", style: { textAlign: "center" }, children: header }),
870
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Title, { order: 3, fw: 600, mb: "xs", c: "gray.7", children: "Set new password" }),
871
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Text, { size: "sm", c: "gray.6", mb: "lg", children: "Choose a new password for your account." }),
872
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("form", { onSubmit: handleSetPassword, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_core7.Stack, { children: [
873
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
874
+ import_core7.PasswordInput,
875
+ {
876
+ label: "New password",
877
+ placeholder: "At least 8 characters",
878
+ value: password,
879
+ onChange: (e) => setPassword(e.currentTarget.value),
880
+ minLength: 8,
881
+ required: true
882
+ }
883
+ ),
884
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
885
+ import_core7.PasswordInput,
886
+ {
887
+ label: "Confirm password",
888
+ placeholder: "Repeat your password",
889
+ value: confirmPassword,
890
+ onChange: (e) => setConfirmPassword(e.currentTarget.value),
891
+ required: true
892
+ }
893
+ ),
894
+ error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Text, { size: "sm", c: "red", children: error }),
895
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Button, { fullWidth: true, size: "md", type: "submit", loading, children: "Update password" })
896
+ ] }) })
897
+ ] });
898
+ }
899
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_core7.Box, { w: "100%", maw: 460, children: [
900
+ header && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Box, { mb: "lg", style: { textAlign: "center" }, children: header }),
901
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Title, { order: 3, fw: 600, mb: "xs", c: "gray.7", children: "Reset password" }),
902
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Text, { size: "sm", c: "gray.6", mb: "lg", children: "Enter your email and we'll send you a code to reset your password." }),
903
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("form", { onSubmit: handleRequestReset, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_core7.Stack, { children: [
904
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
905
+ import_core7.TextInput,
906
+ {
907
+ label: "Email",
908
+ placeholder: "you@frequency.media",
909
+ type: "email",
910
+ value: email,
911
+ onChange: (e) => setEmail(e.currentTarget.value),
912
+ required: true
913
+ }
914
+ ),
915
+ error && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Text, { size: "sm", c: "red", children: error }),
916
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Button, { fullWidth: true, size: "md", type: "submit", loading, children: "Send reset code" }),
917
+ onBackToLogin && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Text, { size: "sm", c: "gray.6", ta: "center", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core7.Anchor, { component: "button", type: "button", size: "sm", onClick: onBackToLogin, children: "Back to sign in" }) })
918
+ ] }) })
919
+ ] });
920
+ }
921
+
922
+ // src/middleware.ts
923
+ var import_ssr2 = require("@supabase/ssr");
924
+ var import_server2 = require("next/server");
925
+ var import_config2 = require("@frequencyads/db/config");
926
+ var import_cookies2 = require("@frequencyads/db/cookies");
927
+ function getAccountsUrl() {
928
+ const url = process.env.NEXT_PUBLIC_ACCOUNTS_URL;
929
+ if (!url) throw new Error("Missing required env var: NEXT_PUBLIC_ACCOUNTS_URL");
930
+ return url;
931
+ }
932
+ async function getSessionAndClaims(request) {
933
+ var _a;
934
+ let supabaseResponse = import_server2.NextResponse.next({ request });
935
+ const hostname = new URL(getRequestOrigin(request)).hostname;
936
+ const cookieDomain = (0, import_cookies2.deriveCookieDomain)(hostname, (0, import_config2.getTrustedDomains)());
937
+ const cookieOptions = cookieDomain ? { domain: cookieDomain } : void 0;
938
+ const supabase = (0, import_ssr2.createServerClient)((0, import_config2.getSupabaseUrl)(), (0, import_config2.getSupabasePublishableKey)(), {
939
+ cookieOptions,
940
+ cookies: {
941
+ getAll() {
942
+ return request.cookies.getAll();
943
+ },
944
+ setAll(cookiesToSet) {
945
+ cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value));
946
+ supabaseResponse = import_server2.NextResponse.next({ request });
947
+ cookiesToSet.forEach(
948
+ ({ name, value, options }) => supabaseResponse.cookies.set(name, value, options)
949
+ );
950
+ }
951
+ }
952
+ });
953
+ const { data } = await supabase.auth.getClaims();
954
+ const claims = (_a = data == null ? void 0 : data.claims) != null ? _a : null;
955
+ return { supabase, supabaseResponse, claims };
956
+ }
957
+ async function isOrgMember(supabase, userId) {
958
+ const { data } = await supabase.from("perm_organization_member").select("id").eq("user_id", userId).limit(1).maybeSingle();
959
+ return data !== null;
960
+ }
961
+ async function isEmployee(supabase, userId) {
962
+ const { data } = await supabase.from("perm_user_global_role").select("role").eq("user_id", userId).maybeSingle();
963
+ return (data == null ? void 0 : data.role) === "EMPLOYEE" || (data == null ? void 0 : data.role) === "ADMIN";
964
+ }
965
+ function createAuthMiddleware({ access }) {
966
+ return async function middleware(request) {
967
+ const { supabase, supabaseResponse, claims } = await getSessionAndClaims(request);
968
+ const accountsUrl = getAccountsUrl();
969
+ const currentUrl = request.nextUrl.href;
970
+ if (!claims) {
971
+ const loginUrl = `${accountsUrl}/login?next=${encodeURIComponent(currentUrl)}`;
972
+ return import_server2.NextResponse.redirect(loginUrl);
973
+ }
974
+ const userId = claims.sub;
975
+ let authorized = false;
976
+ if (access === "org-member") {
977
+ authorized = await isOrgMember(supabase, userId);
978
+ } else if (access === "employee") {
979
+ authorized = await isEmployee(supabase, userId);
980
+ }
981
+ if (!authorized) {
982
+ const deniedUrl = `${accountsUrl}?error=access_denied&from=${encodeURIComponent(currentUrl)}`;
983
+ return import_server2.NextResponse.redirect(deniedUrl);
984
+ }
985
+ return supabaseResponse;
986
+ };
987
+ }
988
+ var defaultMatcher = {
989
+ matcher: [
990
+ "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico)$).*)"
991
+ ]
992
+ };
993
+ // Annotate the CommonJS export names for ESM import in node:
994
+ 0 && (module.exports = {
995
+ AuthProvider,
996
+ LoginPage,
997
+ ResetPasswordForm,
998
+ SignOutButton,
999
+ UserMenu,
1000
+ VerifyCodeForm,
1001
+ createAuthMiddleware,
1002
+ defaultMatcher,
1003
+ getSignOutUrl,
1004
+ updateSession,
1005
+ useAuth
1006
+ });