@m5kdev/backend 0.1.1 → 0.1.3

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 (113) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/src/lib/posthog.js +7 -0
  4. package/dist/src/lib/sentry.js +9 -0
  5. package/dist/src/modules/access/access.repository.js +32 -0
  6. package/dist/src/modules/access/access.service.js +51 -0
  7. package/dist/src/modules/access/access.test.js +182 -0
  8. package/dist/src/modules/access/access.utils.js +20 -0
  9. package/dist/src/modules/ai/ai.db.js +39 -0
  10. package/dist/src/modules/ai/ai.prompt.js +30 -0
  11. package/dist/src/modules/ai/ai.repository.js +26 -0
  12. package/dist/src/modules/ai/ai.router.js +132 -0
  13. package/dist/src/modules/ai/ai.service.js +207 -0
  14. package/dist/src/modules/ai/ai.trpc.d.ts +5 -5
  15. package/dist/src/modules/ai/ai.trpc.js +20 -0
  16. package/dist/src/modules/ai/ideogram/ideogram.constants.js +167 -0
  17. package/dist/src/modules/ai/ideogram/ideogram.dto.js +49 -0
  18. package/dist/src/modules/ai/ideogram/ideogram.prompt.js +860 -0
  19. package/dist/src/modules/ai/ideogram/ideogram.repository.js +46 -0
  20. package/dist/src/modules/ai/ideogram/ideogram.service.js +11 -0
  21. package/dist/src/modules/auth/auth.db.js +215 -0
  22. package/dist/src/modules/auth/auth.dto.js +38 -0
  23. package/dist/src/modules/auth/auth.lib.d.ts +4 -4
  24. package/dist/src/modules/auth/auth.lib.js +284 -0
  25. package/dist/src/modules/auth/auth.middleware.js +52 -0
  26. package/dist/src/modules/auth/auth.repository.js +541 -0
  27. package/dist/src/modules/auth/auth.service.js +201 -0
  28. package/dist/src/modules/auth/auth.trpc.d.ts +18 -18
  29. package/dist/src/modules/auth/auth.trpc.js +157 -0
  30. package/dist/src/modules/auth/auth.utils.js +97 -0
  31. package/dist/src/modules/base/base.abstract.js +53 -0
  32. package/dist/src/modules/base/base.dto.js +112 -0
  33. package/dist/src/modules/base/base.grants.js +123 -0
  34. package/dist/src/modules/base/base.grants.test.js +668 -0
  35. package/dist/src/modules/base/base.repository.js +307 -0
  36. package/dist/src/modules/base/base.service.js +109 -0
  37. package/dist/src/modules/base/base.types.js +2 -0
  38. package/dist/src/modules/billing/billing.db.js +29 -0
  39. package/dist/src/modules/billing/billing.repository.js +235 -0
  40. package/dist/src/modules/billing/billing.router.js +56 -0
  41. package/dist/src/modules/billing/billing.service.js +147 -0
  42. package/dist/src/modules/billing/billing.trpc.d.ts +5 -5
  43. package/dist/src/modules/billing/billing.trpc.js +17 -0
  44. package/dist/src/modules/clay/clay.repository.js +26 -0
  45. package/dist/src/modules/clay/clay.service.js +24 -0
  46. package/dist/src/modules/connect/connect.db.js +30 -0
  47. package/dist/src/modules/connect/connect.dto.js +36 -0
  48. package/dist/src/modules/connect/connect.linkedin.js +53 -0
  49. package/dist/src/modules/connect/connect.oauth.js +198 -0
  50. package/dist/src/modules/connect/connect.repository.d.ts +7 -7
  51. package/dist/src/modules/connect/connect.repository.js +54 -0
  52. package/dist/src/modules/connect/connect.router.js +54 -0
  53. package/dist/src/modules/connect/connect.service.d.ts +14 -14
  54. package/dist/src/modules/connect/connect.service.js +114 -0
  55. package/dist/src/modules/connect/connect.trpc.d.ts +10 -10
  56. package/dist/src/modules/connect/connect.trpc.js +21 -0
  57. package/dist/src/modules/connect/connect.types.js +2 -0
  58. package/dist/src/modules/crypto/crypto.db.js +17 -0
  59. package/dist/src/modules/crypto/crypto.repository.js +10 -0
  60. package/dist/src/modules/crypto/crypto.service.js +52 -0
  61. package/dist/src/modules/email/email.service.js +107 -0
  62. package/dist/src/modules/file/file.repository.js +79 -0
  63. package/dist/src/modules/file/file.router.js +99 -0
  64. package/dist/src/modules/file/file.service.js +150 -0
  65. package/dist/src/modules/recurrence/recurrence.db.js +66 -0
  66. package/dist/src/modules/recurrence/recurrence.repository.js +39 -0
  67. package/dist/src/modules/recurrence/recurrence.service.js +70 -0
  68. package/dist/src/modules/recurrence/recurrence.trpc.d.ts +15 -15
  69. package/dist/src/modules/recurrence/recurrence.trpc.js +65 -0
  70. package/dist/src/modules/social/social.dto.js +18 -0
  71. package/dist/src/modules/social/social.linkedin.js +427 -0
  72. package/dist/src/modules/social/social.linkedin.test.js +235 -0
  73. package/dist/src/modules/social/social.service.js +76 -0
  74. package/dist/src/modules/social/social.types.js +2 -0
  75. package/dist/src/modules/tag/tag.db.js +42 -0
  76. package/dist/src/modules/tag/tag.dto.js +9 -0
  77. package/dist/src/modules/tag/tag.repository.js +154 -0
  78. package/dist/src/modules/tag/tag.service.js +31 -0
  79. package/dist/src/modules/tag/tag.trpc.d.ts +5 -5
  80. package/dist/src/modules/tag/tag.trpc.js +47 -0
  81. package/dist/src/modules/utils/applyPagination.js +16 -0
  82. package/dist/src/modules/utils/applySorting.js +18 -0
  83. package/dist/src/modules/utils/getConditionsFromFilters.js +200 -0
  84. package/dist/src/modules/video/video.service.js +84 -0
  85. package/dist/src/modules/webhook/webhook.constants.js +10 -0
  86. package/dist/src/modules/webhook/webhook.db.js +17 -0
  87. package/dist/src/modules/webhook/webhook.dto.js +7 -0
  88. package/dist/src/modules/webhook/webhook.repository.js +56 -0
  89. package/dist/src/modules/webhook/webhook.router.js +30 -0
  90. package/dist/src/modules/webhook/webhook.service.js +68 -0
  91. package/dist/src/modules/workflow/workflow.db.js +30 -0
  92. package/dist/src/modules/workflow/workflow.repository.js +105 -0
  93. package/dist/src/modules/workflow/workflow.service.js +37 -0
  94. package/dist/src/modules/workflow/workflow.trpc.d.ts +5 -5
  95. package/dist/src/modules/workflow/workflow.trpc.js +21 -0
  96. package/dist/src/modules/workflow/workflow.types.js +2 -0
  97. package/dist/src/modules/workflow/workflow.utils.js +173 -0
  98. package/dist/src/test/stubs/utils.js +5 -0
  99. package/dist/src/trpc/context.d.ts +5 -5
  100. package/dist/src/trpc/context.js +17 -0
  101. package/dist/src/trpc/index.js +6 -0
  102. package/dist/src/trpc/procedures.d.ts +56 -56
  103. package/dist/src/trpc/procedures.js +32 -0
  104. package/dist/src/trpc/utils.js +20 -0
  105. package/dist/src/types.d.ts +33 -33
  106. package/dist/src/types.js +13 -0
  107. package/dist/src/utils/errors.js +104 -0
  108. package/dist/src/utils/logger.js +11 -0
  109. package/dist/src/utils/posthog.js +31 -0
  110. package/dist/src/utils/types.js +2 -0
  111. package/dist/tsconfig.tsbuildinfo +1 -1
  112. package/package.json +3 -3
  113. package/tsconfig.json +2 -0
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAuthMiddleware = createAuthMiddleware;
4
+ exports.createRoleAuthMiddleware = createRoleAuthMiddleware;
5
+ const tslib_1 = require("tslib");
6
+ const node_1 = require("better-auth/node");
7
+ const auth = tslib_1.__importStar(require("#modules/auth/auth.db"));
8
+ const posthog_1 = require("#utils/posthog");
9
+ const { users, sessions } = auth;
10
+ function createAuthMiddleware(auth) {
11
+ return (req, res, next) => {
12
+ auth.api
13
+ .getSession({
14
+ headers: (0, node_1.fromNodeHeaders)(req.headers),
15
+ })
16
+ .then((data) => {
17
+ if (!data?.user || !data?.session) {
18
+ res.status(401).json({ message: "Unauthorized" });
19
+ }
20
+ else {
21
+ req.user = data.user;
22
+ req.session = data.session;
23
+ (0, posthog_1.runWithPosthogRequestState)({ disableCapture: Boolean(req.session?.impersonatedBy) }, () => next());
24
+ }
25
+ })
26
+ .catch(() => {
27
+ res.status(500).json({ message: "Unable to authenticate" });
28
+ });
29
+ };
30
+ }
31
+ function createRoleAuthMiddleware(auth) {
32
+ return (role) => (req, res, next) => {
33
+ auth.api
34
+ .getSession({
35
+ headers: (0, node_1.fromNodeHeaders)(req?.headers),
36
+ })
37
+ .then((data) => {
38
+ const user = data?.user || null;
39
+ if (!data?.session || user?.role !== role) {
40
+ res.status(401).json({ message: "Unauthorized" });
41
+ }
42
+ else {
43
+ req.user = user;
44
+ req.session = data?.session;
45
+ (0, posthog_1.runWithPosthogRequestState)({ disableCapture: Boolean(req.session?.impersonatedBy) }, () => next());
46
+ }
47
+ })
48
+ .catch(() => {
49
+ res.status(500).json({ message: "Unable to authenticate" });
50
+ });
51
+ };
52
+ }
@@ -0,0 +1,541 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthRepository = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const drizzle_orm_1 = require("drizzle-orm");
6
+ const neverthrow_1 = require("neverthrow");
7
+ const uuid_1 = require("uuid");
8
+ const auth = tslib_1.__importStar(require("#modules/auth/auth.db"));
9
+ const base_repository_1 = require("#modules/base/base.repository");
10
+ const schema = { ...auth };
11
+ class AuthRepository extends base_repository_1.BaseRepository {
12
+ async getUserWaitlistCount(userId, tx) {
13
+ return this.throwableAsync(async () => {
14
+ const db = tx ?? this.orm;
15
+ const [waitlist] = await db
16
+ .select({ count: (0, drizzle_orm_1.count)() })
17
+ .from(this.schema.waitlist)
18
+ .where((0, drizzle_orm_1.eq)(this.schema.waitlist.userId, userId));
19
+ return (0, neverthrow_1.ok)(waitlist.count ?? 0);
20
+ });
21
+ }
22
+ async getOnboarding(userId, tx) {
23
+ return this.throwableAsync(async () => {
24
+ const db = tx ?? this.orm;
25
+ const [user] = await db
26
+ .select({ onboarding: this.schema.users.onboarding })
27
+ .from(this.schema.users)
28
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId))
29
+ .limit(1);
30
+ if (!user)
31
+ return this.error("FORBIDDEN");
32
+ return (0, neverthrow_1.ok)(user.onboarding ?? 0);
33
+ });
34
+ }
35
+ async setOnboarding(userId, onboarding, tx) {
36
+ return this.throwableAsync(async () => {
37
+ const db = tx ?? this.orm;
38
+ await db
39
+ .update(this.schema.users)
40
+ .set({ onboarding })
41
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId));
42
+ return (0, neverthrow_1.ok)(onboarding);
43
+ });
44
+ }
45
+ async getPreferences(userId, tx) {
46
+ return this.throwableAsync(async () => {
47
+ const db = tx ?? this.orm;
48
+ const [user] = await db
49
+ .select({ preferences: this.schema.users.preferences })
50
+ .from(this.schema.users)
51
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId))
52
+ .limit(1);
53
+ if (!user)
54
+ return this.error("FORBIDDEN");
55
+ const json = user.preferences
56
+ ? JSON.parse(user.preferences)
57
+ : {};
58
+ return (0, neverthrow_1.ok)(json);
59
+ });
60
+ }
61
+ async setPreferences(userId, preferences, tx) {
62
+ return this.throwableAsync(async () => {
63
+ const db = tx ?? this.orm;
64
+ await db
65
+ .update(this.schema.users)
66
+ .set({ preferences: JSON.stringify(preferences) })
67
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId));
68
+ return (0, neverthrow_1.ok)(preferences);
69
+ });
70
+ }
71
+ async getMetadata(userId, tx) {
72
+ return this.throwableAsync(async () => {
73
+ const db = tx ?? this.orm;
74
+ const [user] = await db
75
+ .select({ metadata: this.schema.users.metadata })
76
+ .from(this.schema.users)
77
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId))
78
+ .limit(1);
79
+ if (!user)
80
+ return this.error("FORBIDDEN");
81
+ return (0, neverthrow_1.ok)(user.metadata);
82
+ });
83
+ }
84
+ async setMetadata(userId, metadata, tx) {
85
+ return this.throwableAsync(async () => {
86
+ const db = tx ?? this.orm;
87
+ const [user] = await db
88
+ .select({ metadata: this.schema.users.metadata })
89
+ .from(this.schema.users)
90
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId))
91
+ .limit(1);
92
+ if (!user)
93
+ return this.error("FORBIDDEN");
94
+ await db
95
+ .update(this.schema.users)
96
+ .set({
97
+ metadata: {
98
+ ...user.metadata,
99
+ ...metadata,
100
+ },
101
+ })
102
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId));
103
+ return (0, neverthrow_1.ok)(metadata);
104
+ });
105
+ }
106
+ async getFlags(userId, tx) {
107
+ return this.throwableAsync(async () => {
108
+ const db = tx ?? this.orm;
109
+ const [user] = await db
110
+ .select({ flags: this.schema.users.flags })
111
+ .from(this.schema.users)
112
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId))
113
+ .limit(1);
114
+ if (!user)
115
+ return this.error("FORBIDDEN");
116
+ const json = user.flags ? JSON.parse(user.flags) : [];
117
+ return (0, neverthrow_1.ok)(json);
118
+ });
119
+ }
120
+ async setFlags(userId, flags, tx) {
121
+ return this.throwableAsync(async () => {
122
+ const db = tx ?? this.orm;
123
+ await db
124
+ .update(this.schema.users)
125
+ .set({ flags: JSON.stringify(flags) })
126
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId));
127
+ return (0, neverthrow_1.ok)(flags);
128
+ });
129
+ }
130
+ async listAdminWaitlist(tx) {
131
+ return this.throwableAsync(async () => {
132
+ const db = tx ?? this.orm;
133
+ const waitlist = await db
134
+ .select({
135
+ id: this.schema.waitlist.id,
136
+ name: this.schema.waitlist.name,
137
+ email: this.schema.waitlist.email,
138
+ createdAt: this.schema.waitlist.createdAt,
139
+ updatedAt: this.schema.waitlist.updatedAt,
140
+ status: this.schema.waitlist.status,
141
+ })
142
+ .from(this.schema.waitlist)
143
+ .where((0, drizzle_orm_1.eq)(this.schema.waitlist.type, "WAITLIST"))
144
+ .orderBy((0, drizzle_orm_1.desc)(this.schema.waitlist.createdAt));
145
+ return (0, neverthrow_1.ok)(waitlist);
146
+ });
147
+ }
148
+ async listWaitlist(userId, tx) {
149
+ return this.throwableAsync(async () => {
150
+ const db = tx ?? this.orm;
151
+ const waitlist = await db
152
+ .select()
153
+ .from(this.schema.waitlist)
154
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.waitlist.userId, userId), (0, drizzle_orm_1.eq)(this.schema.waitlist.type, "WAITLIST")));
155
+ return (0, neverthrow_1.ok)(waitlist);
156
+ });
157
+ }
158
+ async addToWaitlist(email, tx) {
159
+ return this.throwableAsync(async () => {
160
+ const db = tx ?? this.orm;
161
+ const [waitlist] = await db.insert(this.schema.waitlist).values({ email }).returning();
162
+ return (0, neverthrow_1.ok)(waitlist);
163
+ });
164
+ }
165
+ async inviteFromWaitlist(id, tx) {
166
+ return this.throwableAsync(async () => {
167
+ const db = tx ?? this.orm;
168
+ const [waitlist] = await db
169
+ .update(this.schema.waitlist)
170
+ .set({
171
+ status: "INVITED",
172
+ code: (0, uuid_1.v4)(),
173
+ expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 14),
174
+ })
175
+ .where((0, drizzle_orm_1.eq)(this.schema.waitlist.id, id))
176
+ .returning();
177
+ return (0, neverthrow_1.ok)(waitlist);
178
+ });
179
+ }
180
+ async inviteToWaitlist({ email, userId, name }, tx) {
181
+ return this.throwableAsync(async () => {
182
+ const db = tx ?? this.orm;
183
+ const [waitlist] = await db
184
+ .insert(this.schema.waitlist)
185
+ .values({
186
+ email,
187
+ name,
188
+ status: "INVITED",
189
+ code: (0, uuid_1.v4)(),
190
+ expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24),
191
+ userId: userId,
192
+ })
193
+ .returning();
194
+ return (0, neverthrow_1.ok)(waitlist);
195
+ });
196
+ }
197
+ async createInvitationCode({ userId, name }, tx) {
198
+ return this.throwableAsync(async () => {
199
+ const db = tx ?? this.orm;
200
+ const [waitlist] = await db
201
+ .insert(this.schema.waitlist)
202
+ .values({
203
+ name,
204
+ status: "INVITED",
205
+ code: (0, uuid_1.v4)(),
206
+ expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24),
207
+ userId: userId,
208
+ })
209
+ .returning();
210
+ return (0, neverthrow_1.ok)(waitlist);
211
+ });
212
+ }
213
+ async joinWaitlist(email, tx) {
214
+ return this.throwableAsync(async () => {
215
+ const db = tx ?? this.orm;
216
+ const [waitlist] = await db.insert(this.schema.waitlist).values({ email }).returning();
217
+ return (0, neverthrow_1.ok)(waitlist);
218
+ });
219
+ }
220
+ async removeFromWaitlist(id, tx) {
221
+ return this.throwableAsync(async () => {
222
+ const db = tx ?? this.orm;
223
+ const [waitlist] = await db
224
+ .update(this.schema.waitlist)
225
+ .set({ status: "REMOVED" })
226
+ .where((0, drizzle_orm_1.eq)(this.schema.waitlist.id, id))
227
+ .returning();
228
+ return (0, neverthrow_1.ok)(waitlist);
229
+ });
230
+ }
231
+ async validateWaitlistCode(code, tx) {
232
+ return this.throwableAsync(async () => {
233
+ const db = tx ?? this.orm;
234
+ const [waitlist] = await db
235
+ .select()
236
+ .from(this.schema.waitlist)
237
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.waitlist.code, code), (0, drizzle_orm_1.eq)(this.schema.waitlist.type, "WAITLIST")))
238
+ .limit(1);
239
+ if (!waitlist)
240
+ return (0, neverthrow_1.ok)({ status: "NOT_FOUND" });
241
+ if (waitlist.expiresAt && waitlist.expiresAt < new Date())
242
+ return (0, neverthrow_1.ok)({ status: "EXPIRED" });
243
+ if (waitlist.status !== "INVITED")
244
+ return (0, neverthrow_1.ok)({ status: "INVALID" });
245
+ return (0, neverthrow_1.ok)({ status: "VALID" });
246
+ });
247
+ }
248
+ async createAccountClaimCode({ userId, expiresInHours = 24 * 14 }, tx) {
249
+ return this.throwableAsync(async () => {
250
+ const db = tx ?? this.orm;
251
+ const [claim] = await db
252
+ .insert(this.schema.waitlist)
253
+ .values({
254
+ type: "ACCOUNT_CLAIM",
255
+ claimUserId: userId,
256
+ code: (0, uuid_1.v4)(),
257
+ status: "INVITED",
258
+ expiresAt: new Date(Date.now() + 1000 * 60 * 60 * expiresInHours),
259
+ })
260
+ .returning();
261
+ return (0, neverthrow_1.ok)(claim);
262
+ });
263
+ }
264
+ async createClaimableProvisionedUser({ name, email, metadata = {}, onboarding = 0, role = "user", expiresInHours = 24 * 14, }) {
265
+ return this.throwableAsync(async () => {
266
+ const normalizedEmail = email.toLowerCase();
267
+ const [existingUser] = await this.orm
268
+ .select({ id: this.schema.users.id })
269
+ .from(this.schema.users)
270
+ .where((0, drizzle_orm_1.eq)(this.schema.users.email, normalizedEmail))
271
+ .limit(1);
272
+ if (existingUser) {
273
+ return this.error("CONFLICT", "Email already in use");
274
+ }
275
+ const created = await this.orm.transaction(async (tx) => {
276
+ const [user] = await tx
277
+ .insert(this.schema.users)
278
+ .values({
279
+ name,
280
+ email: normalizedEmail,
281
+ emailVerified: false,
282
+ role,
283
+ onboarding,
284
+ metadata,
285
+ })
286
+ .returning();
287
+ if (!user)
288
+ throw new Error("Failed to create user");
289
+ const organizationId = (0, uuid_1.v4)();
290
+ const [organization] = await tx
291
+ .insert(this.schema.organizations)
292
+ .values({
293
+ id: organizationId,
294
+ name: organizationId,
295
+ slug: organizationId,
296
+ })
297
+ .returning();
298
+ if (!organization)
299
+ throw new Error("Failed to create organization");
300
+ const [member] = await tx
301
+ .insert(this.schema.members)
302
+ .values({
303
+ userId: user.id,
304
+ organizationId: organization.id,
305
+ role: "owner",
306
+ })
307
+ .returning();
308
+ if (!member)
309
+ throw new Error("Failed to create organization membership");
310
+ const [team] = await tx
311
+ .insert(this.schema.teams)
312
+ .values({
313
+ name: organization.id,
314
+ organizationId: organization.id,
315
+ })
316
+ .returning();
317
+ if (!team)
318
+ throw new Error("Failed to create team");
319
+ const [teamMember] = await tx
320
+ .insert(this.schema.teamMembers)
321
+ .values({
322
+ userId: user.id,
323
+ teamId: team.id,
324
+ role: "owner",
325
+ })
326
+ .returning();
327
+ if (!teamMember)
328
+ throw new Error("Failed to create team membership");
329
+ const [claim] = await tx
330
+ .insert(this.schema.waitlist)
331
+ .values({
332
+ type: "ACCOUNT_CLAIM",
333
+ claimUserId: user.id,
334
+ code: (0, uuid_1.v4)(),
335
+ status: "INVITED",
336
+ expiresAt: new Date(Date.now() + 1000 * 60 * 60 * expiresInHours),
337
+ })
338
+ .returning();
339
+ if (!claim)
340
+ throw new Error("Failed to create account claim");
341
+ return { user, claim };
342
+ });
343
+ return (0, neverthrow_1.ok)(created);
344
+ });
345
+ }
346
+ async listAccountClaims(tx) {
347
+ return this.throwableAsync(async () => {
348
+ const db = tx ?? this.orm;
349
+ const claims = await db
350
+ .select({
351
+ id: this.schema.waitlist.id,
352
+ claimUserId: this.schema.waitlist.claimUserId,
353
+ status: this.schema.waitlist.status,
354
+ expiresAt: this.schema.waitlist.expiresAt,
355
+ claimedAt: this.schema.waitlist.claimedAt,
356
+ claimedEmail: this.schema.waitlist.claimedEmail,
357
+ createdAt: this.schema.waitlist.createdAt,
358
+ updatedAt: this.schema.waitlist.updatedAt,
359
+ })
360
+ .from(this.schema.waitlist)
361
+ .where((0, drizzle_orm_1.eq)(this.schema.waitlist.type, "ACCOUNT_CLAIM"))
362
+ .orderBy((0, drizzle_orm_1.desc)(this.schema.waitlist.createdAt));
363
+ return (0, neverthrow_1.ok)(claims);
364
+ });
365
+ }
366
+ async validateAccountClaimCode(code, tx) {
367
+ return this.throwableAsync(async () => {
368
+ const db = tx ?? this.orm;
369
+ const [claim] = await db
370
+ .select()
371
+ .from(this.schema.waitlist)
372
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.waitlist.code, code), (0, drizzle_orm_1.eq)(this.schema.waitlist.type, "ACCOUNT_CLAIM")))
373
+ .limit(1);
374
+ if (!claim)
375
+ return (0, neverthrow_1.ok)({ status: "NOT_FOUND" });
376
+ if (claim.expiresAt && claim.expiresAt < new Date())
377
+ return (0, neverthrow_1.ok)({ status: "EXPIRED" });
378
+ if (claim.status !== "INVITED")
379
+ return (0, neverthrow_1.ok)({ status: "INVALID" });
380
+ return (0, neverthrow_1.ok)({ status: "VALID" });
381
+ });
382
+ }
383
+ async findAccountClaimByCode(code, tx) {
384
+ return this.throwableAsync(async () => {
385
+ const db = tx ?? this.orm;
386
+ const [claim] = await db
387
+ .select()
388
+ .from(this.schema.waitlist)
389
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.waitlist.code, code), (0, drizzle_orm_1.eq)(this.schema.waitlist.type, "ACCOUNT_CLAIM"), (0, drizzle_orm_1.eq)(this.schema.waitlist.status, "INVITED"), (0, drizzle_orm_1.gte)(this.schema.waitlist.expiresAt, new Date())))
390
+ .limit(1);
391
+ return (0, neverthrow_1.ok)(claim ?? null);
392
+ });
393
+ }
394
+ async findAccountClaimById(id, tx) {
395
+ return this.throwableAsync(async () => {
396
+ const db = tx ?? this.orm;
397
+ const [claim] = await db
398
+ .select()
399
+ .from(this.schema.waitlist)
400
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.waitlist.id, id), (0, drizzle_orm_1.eq)(this.schema.waitlist.type, "ACCOUNT_CLAIM")))
401
+ .limit(1);
402
+ return (0, neverthrow_1.ok)(claim ?? null);
403
+ });
404
+ }
405
+ async findPendingAccountClaimForUser(userId, tx) {
406
+ return this.throwableAsync(async () => {
407
+ const db = tx ?? this.orm;
408
+ const [claim] = await db
409
+ .select()
410
+ .from(this.schema.waitlist)
411
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.waitlist.type, "ACCOUNT_CLAIM"), (0, drizzle_orm_1.eq)(this.schema.waitlist.claimUserId, userId), (0, drizzle_orm_1.eq)(this.schema.waitlist.status, "INVITED"), (0, drizzle_orm_1.gte)(this.schema.waitlist.expiresAt, new Date())))
412
+ .orderBy((0, drizzle_orm_1.desc)(this.schema.waitlist.createdAt))
413
+ .limit(1);
414
+ return (0, neverthrow_1.ok)(claim ?? null);
415
+ });
416
+ }
417
+ async setAccountClaimEmail({ userId, email }, tx) {
418
+ return this.throwableAsync(async () => {
419
+ const db = tx ?? this.orm;
420
+ const normalizedEmail = email.toLowerCase();
421
+ const [existingUser] = await db
422
+ .select({ id: this.schema.users.id })
423
+ .from(this.schema.users)
424
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.users.email, normalizedEmail), (0, drizzle_orm_1.ne)(this.schema.users.id, userId)))
425
+ .limit(1);
426
+ if (existingUser) {
427
+ return this.error("BAD_REQUEST", "Email is already in use");
428
+ }
429
+ const [claim] = await db
430
+ .select({ id: this.schema.waitlist.id })
431
+ .from(this.schema.waitlist)
432
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.waitlist.type, "ACCOUNT_CLAIM"), (0, drizzle_orm_1.eq)(this.schema.waitlist.claimUserId, userId), (0, drizzle_orm_1.eq)(this.schema.waitlist.status, "INVITED"), (0, drizzle_orm_1.gte)(this.schema.waitlist.expiresAt, new Date())))
433
+ .orderBy((0, drizzle_orm_1.desc)(this.schema.waitlist.createdAt))
434
+ .limit(1);
435
+ if (!claim) {
436
+ return this.error("BAD_REQUEST", "No pending claim found");
437
+ }
438
+ await db
439
+ .update(this.schema.users)
440
+ .set({
441
+ email: normalizedEmail,
442
+ emailVerified: false,
443
+ updatedAt: new Date(),
444
+ })
445
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId));
446
+ await db
447
+ .update(this.schema.waitlist)
448
+ .set({
449
+ claimedEmail: normalizedEmail,
450
+ updatedAt: new Date(),
451
+ })
452
+ .where((0, drizzle_orm_1.eq)(this.schema.waitlist.id, claim.id));
453
+ return (0, neverthrow_1.ok)({ status: true });
454
+ });
455
+ }
456
+ async acceptAccountClaim(userId, tx) {
457
+ return this.throwableAsync(async () => {
458
+ const db = tx ?? this.orm;
459
+ const [claim] = await db
460
+ .select({ id: this.schema.waitlist.id })
461
+ .from(this.schema.waitlist)
462
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.waitlist.type, "ACCOUNT_CLAIM"), (0, drizzle_orm_1.eq)(this.schema.waitlist.claimUserId, userId), (0, drizzle_orm_1.eq)(this.schema.waitlist.status, "INVITED"), (0, drizzle_orm_1.gte)(this.schema.waitlist.expiresAt, new Date())))
463
+ .orderBy((0, drizzle_orm_1.desc)(this.schema.waitlist.createdAt))
464
+ .limit(1);
465
+ if (!claim)
466
+ return (0, neverthrow_1.ok)({ status: true });
467
+ const [user] = await db
468
+ .select({ email: this.schema.users.email })
469
+ .from(this.schema.users)
470
+ .where((0, drizzle_orm_1.eq)(this.schema.users.id, userId))
471
+ .limit(1);
472
+ await db
473
+ .update(this.schema.waitlist)
474
+ .set({
475
+ status: "ACCEPTED",
476
+ claimedAt: new Date(),
477
+ claimedEmail: user?.email ?? null,
478
+ updatedAt: new Date(),
479
+ })
480
+ .where((0, drizzle_orm_1.eq)(this.schema.waitlist.id, claim.id));
481
+ return (0, neverthrow_1.ok)({ status: true });
482
+ });
483
+ }
484
+ async createAccountClaimMagicLink({ claimId, userId, email, token, url, expiresAt, }, tx) {
485
+ return this.throwableAsync(async () => {
486
+ const db = tx ?? this.orm;
487
+ const [link] = await db
488
+ .insert(this.schema.accountClaimMagicLinks)
489
+ .values({
490
+ claimId,
491
+ userId,
492
+ email,
493
+ token,
494
+ url,
495
+ expiresAt: expiresAt ?? null,
496
+ })
497
+ .returning();
498
+ return (0, neverthrow_1.ok)(link);
499
+ });
500
+ }
501
+ async listAccountClaimMagicLinks(claimId, tx) {
502
+ return this.throwableAsync(async () => {
503
+ const db = tx ?? this.orm;
504
+ const links = await db
505
+ .select({
506
+ id: this.schema.accountClaimMagicLinks.id,
507
+ claimId: this.schema.accountClaimMagicLinks.claimId,
508
+ userId: this.schema.accountClaimMagicLinks.userId,
509
+ email: this.schema.accountClaimMagicLinks.email,
510
+ url: this.schema.accountClaimMagicLinks.url,
511
+ expiresAt: this.schema.accountClaimMagicLinks.expiresAt,
512
+ createdAt: this.schema.accountClaimMagicLinks.createdAt,
513
+ })
514
+ .from(this.schema.accountClaimMagicLinks)
515
+ .where((0, drizzle_orm_1.eq)(this.schema.accountClaimMagicLinks.claimId, claimId))
516
+ .orderBy((0, drizzle_orm_1.desc)(this.schema.accountClaimMagicLinks.createdAt));
517
+ return (0, neverthrow_1.ok)(links);
518
+ });
519
+ }
520
+ async latestAccountClaimMagicLink(claimId, tx) {
521
+ return this.throwableAsync(async () => {
522
+ const db = tx ?? this.orm;
523
+ const [link] = await db
524
+ .select({
525
+ id: this.schema.accountClaimMagicLinks.id,
526
+ claimId: this.schema.accountClaimMagicLinks.claimId,
527
+ userId: this.schema.accountClaimMagicLinks.userId,
528
+ email: this.schema.accountClaimMagicLinks.email,
529
+ url: this.schema.accountClaimMagicLinks.url,
530
+ expiresAt: this.schema.accountClaimMagicLinks.expiresAt,
531
+ createdAt: this.schema.accountClaimMagicLinks.createdAt,
532
+ })
533
+ .from(this.schema.accountClaimMagicLinks)
534
+ .where((0, drizzle_orm_1.eq)(this.schema.accountClaimMagicLinks.claimId, claimId))
535
+ .orderBy((0, drizzle_orm_1.desc)(this.schema.accountClaimMagicLinks.createdAt))
536
+ .limit(1);
537
+ return (0, neverthrow_1.ok)(link ?? null);
538
+ });
539
+ }
540
+ }
541
+ exports.AuthRepository = AuthRepository;