@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,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SocialService = void 0;
4
+ const neverthrow_1 = require("neverthrow");
5
+ const base_service_1 = require("#modules/base/base.service");
6
+ class SocialService extends base_service_1.BaseService {
7
+ providers = new Map();
8
+ constructor(repositories, services, providers) {
9
+ super(repositories, services);
10
+ this.providers = new Map(providers.map((provider) => [provider.id, provider]));
11
+ }
12
+ getProvider(id) {
13
+ return this.providers.get(id) ?? null;
14
+ }
15
+ async postToProvider(providerId, input, { user }) {
16
+ return this.throwableAsync(async () => {
17
+ const provider = this.getProvider(providerId);
18
+ if (!provider) {
19
+ return this.error("BAD_REQUEST", `Unknown provider: ${providerId}`);
20
+ }
21
+ const connectionResult = await this.repository.connect.list({
22
+ userId: user.id,
23
+ providers: [providerId],
24
+ });
25
+ if (connectionResult.isErr()) {
26
+ return this.error("INTERNAL_SERVER_ERROR", "Failed to load connection", {
27
+ cause: connectionResult.error,
28
+ });
29
+ }
30
+ const activeConnection = connectionResult.value.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime())[0];
31
+ const connection = await this.ensureFreshConnection(activeConnection);
32
+ if (connection.isErr()) {
33
+ return this.error("INTERNAL_SERVER_ERROR", "Failed to refresh connection", {
34
+ cause: connection.error,
35
+ });
36
+ }
37
+ const payload = {
38
+ text: input.text,
39
+ media: input.media,
40
+ visibility: input.visibility ?? "PUBLIC",
41
+ };
42
+ const accessToken = connection.value.accessToken;
43
+ if (!accessToken) {
44
+ return this.error("BAD_REQUEST", "Missing access token for connection");
45
+ }
46
+ const result = await provider.post({
47
+ deps: { fileService: this.service.file },
48
+ context: {
49
+ userId: user.id,
50
+ connection: connection.value,
51
+ accessToken,
52
+ },
53
+ payload,
54
+ });
55
+ return (0, neverthrow_1.ok)(result);
56
+ });
57
+ }
58
+ async ensureFreshConnection(connection) {
59
+ if (!connection.expiresAt || !connection.refreshToken) {
60
+ return (0, neverthrow_1.ok)(connection);
61
+ }
62
+ const expiresAt = new Date(connection.expiresAt);
63
+ const bufferMs = 60 * 1000; // Refresh 1 minute before expiry
64
+ if (Date.now() < expiresAt.getTime() - bufferMs) {
65
+ return (0, neverthrow_1.ok)(connection);
66
+ }
67
+ const refreshed = await this.service.connect.refreshToken(connection.id);
68
+ if (refreshed.isErr()) {
69
+ return this.error("INTERNAL_SERVER_ERROR", "Failed to refresh access token", {
70
+ cause: refreshed.error,
71
+ });
72
+ }
73
+ return (0, neverthrow_1.ok)(refreshed.value);
74
+ }
75
+ }
76
+ exports.SocialService = SocialService;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.taggings = exports.tags = void 0;
4
+ const sqlite_core_1 = require("drizzle-orm/sqlite-core");
5
+ const uuid_1 = require("uuid");
6
+ const auth_db_1 = require("#modules/auth/auth.db");
7
+ exports.tags = (0, sqlite_core_1.sqliteTable)("tags", {
8
+ id: (0, sqlite_core_1.text)("id").primaryKey().$default(uuid_1.v4),
9
+ createdAt: (0, sqlite_core_1.integer)("created_at", { mode: "timestamp" })
10
+ .notNull()
11
+ .$default(() => new Date()),
12
+ updatedAt: (0, sqlite_core_1.integer)("updated_at", { mode: "timestamp" }),
13
+ deletedAt: (0, sqlite_core_1.integer)("deleted_at", { mode: "timestamp" }),
14
+ userId: (0, sqlite_core_1.text)("user_id")
15
+ .notNull()
16
+ .references(() => auth_db_1.users.id, { onDelete: "cascade" }),
17
+ organizationId: (0, sqlite_core_1.text)("organization_id").references(() => auth_db_1.organizations.id, {
18
+ onDelete: "cascade",
19
+ }),
20
+ teamId: (0, sqlite_core_1.text)("team_id").references(() => auth_db_1.teams.id, { onDelete: "cascade" }),
21
+ name: (0, sqlite_core_1.text)("name").notNull(),
22
+ color: (0, sqlite_core_1.text)("color"),
23
+ type: (0, sqlite_core_1.text)("type"),
24
+ isEnabled: (0, sqlite_core_1.integer)("is_enabled", { mode: "boolean" }).notNull().default(true),
25
+ parentId: (0, sqlite_core_1.text)("parent_id").references(() => exports.tags.id, { onDelete: "set null" }),
26
+ assignableTo: (0, sqlite_core_1.text)("assignable_to", {
27
+ mode: "json",
28
+ })
29
+ .notNull()
30
+ .$type(),
31
+ });
32
+ exports.taggings = (0, sqlite_core_1.sqliteTable)("taggings", {
33
+ id: (0, sqlite_core_1.text)("id").primaryKey().$default(uuid_1.v4),
34
+ createdAt: (0, sqlite_core_1.integer)("created_at", { mode: "timestamp" })
35
+ .notNull()
36
+ .$default(() => new Date()),
37
+ tagId: (0, sqlite_core_1.text)("tag_id")
38
+ .notNull()
39
+ .references(() => exports.tags.id),
40
+ resourceType: (0, sqlite_core_1.text)("resource_type").notNull(), // e.g., "post", "image"
41
+ resourceId: (0, sqlite_core_1.text)("resource_id").notNull(), // id in the resource table
42
+ });
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.taggingsSelectOutput = exports.tagsSelectOutput = exports.taggingsSelectDTO = exports.tagsSelectDTO = void 0;
4
+ const base_dto_1 = require("#modules/base/base.dto");
5
+ const tag_db_1 = require("#modules/tag/tag.db");
6
+ exports.tagsSelectDTO = (0, base_dto_1.createSelectDTO)(tag_db_1.tags);
7
+ exports.taggingsSelectDTO = (0, base_dto_1.createSelectDTO)(tag_db_1.taggings);
8
+ exports.tagsSelectOutput = exports.tagsSelectDTO.schema;
9
+ exports.taggingsSelectOutput = exports.taggingsSelectDTO.schema;
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TagRepository = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const drizzle_orm_1 = require("drizzle-orm");
6
+ const neverthrow_1 = require("neverthrow");
7
+ const base_repository_1 = require("#modules/base/base.repository");
8
+ const tag = tslib_1.__importStar(require("#modules/tag/tag.db"));
9
+ const schema = { ...tag };
10
+ class TagRepository extends base_repository_1.BaseTableRepository {
11
+ async link({ userId, ...data }, tx) {
12
+ return this.throwableAsync(async () => {
13
+ const db = tx ?? this.orm;
14
+ const [foundTag] = await db
15
+ .select({ id: this.schema.tags.id })
16
+ .from(this.schema.tags)
17
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.tags.id, data.tagId), (0, drizzle_orm_1.eq)(this.schema.tags.userId, userId)))
18
+ .limit(1);
19
+ if (!foundTag)
20
+ return this.error("FORBIDDEN");
21
+ const [tagging] = await db
22
+ .insert(this.schema.taggings)
23
+ .values({ ...data, tagId: foundTag.id })
24
+ .returning();
25
+ if (!tagging)
26
+ return this.error("NOT_FOUND");
27
+ return (0, neverthrow_1.ok)(tagging);
28
+ });
29
+ }
30
+ async linkBulk(data, tx) {
31
+ return this.throwableAsync(async () => {
32
+ const db = tx ?? this.orm;
33
+ await db.insert(this.schema.taggings).values(data);
34
+ const tags = await db
35
+ .select()
36
+ .from(this.schema.tags)
37
+ .where((0, drizzle_orm_1.inArray)(this.schema.tags.id, data.map((tag) => tag.tagId)));
38
+ return (0, neverthrow_1.ok)(tags);
39
+ });
40
+ }
41
+ async set(data, tx) {
42
+ return this.throwableAsync(async () => {
43
+ const db = tx ?? this.orm;
44
+ const result = await db.transaction(async (trx) => {
45
+ // FIXME: We are assuming that all resourceIds are the same, this is not a good assumption.
46
+ await trx
47
+ .delete(this.schema.taggings)
48
+ .where((0, drizzle_orm_1.eq)(this.schema.taggings.resourceId, data[0].resourceId));
49
+ await db.insert(this.schema.taggings).values(data);
50
+ const tags = await db
51
+ .select()
52
+ .from(this.schema.tags)
53
+ .where((0, drizzle_orm_1.inArray)(this.schema.tags.id, data.map((tag) => tag.tagId)));
54
+ return tags;
55
+ });
56
+ return (0, neverthrow_1.ok)(result);
57
+ });
58
+ }
59
+ async unlink({ userId, ...data }, tx) {
60
+ return this.throwableAsync(async () => {
61
+ const db = tx ?? this.orm;
62
+ const [foundTag] = await db
63
+ .select()
64
+ .from(this.schema.tags)
65
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.tags.id, data.tagId), (0, drizzle_orm_1.eq)(this.schema.tags.userId, userId)))
66
+ .limit(1);
67
+ if (!foundTag)
68
+ return this.error("FORBIDDEN");
69
+ await db
70
+ .delete(this.schema.taggings)
71
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.taggings.tagId, data.tagId), (0, drizzle_orm_1.eq)(this.schema.taggings.resourceId, data.resourceId), (0, drizzle_orm_1.eq)(this.schema.taggings.resourceType, data.resourceType)));
72
+ return (0, neverthrow_1.ok)(foundTag);
73
+ });
74
+ }
75
+ async findTagsForResources(data, tx) {
76
+ return this.throwableAsync(async () => {
77
+ const db = tx ?? this.orm;
78
+ if (data.resourceIds.length === 0)
79
+ return (0, neverthrow_1.ok)({});
80
+ const taggings = await db
81
+ .select({
82
+ resourceId: this.schema.taggings.resourceId,
83
+ tagId: this.schema.taggings.tagId,
84
+ })
85
+ .from(this.schema.taggings)
86
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.taggings.resourceType, data.resourceType), (0, drizzle_orm_1.inArray)(this.schema.taggings.resourceId, data.resourceIds)));
87
+ if (taggings.length === 0)
88
+ return (0, neverthrow_1.ok)({});
89
+ const tagIds = Array.from(new Set(taggings.map((tagging) => tagging.tagId)));
90
+ const tags = await db
91
+ .select()
92
+ .from(this.schema.tags)
93
+ .where((0, drizzle_orm_1.inArray)(this.schema.tags.id, tagIds));
94
+ const tagById = tags.reduce((acc, tagRow) => {
95
+ acc[tagRow.id] = tagRow;
96
+ return acc;
97
+ }, {});
98
+ const grouped = taggings.reduce((acc, tagging) => {
99
+ const tagRow = tagById[tagging.tagId];
100
+ if (!tagRow)
101
+ return acc;
102
+ const existing = acc[tagging.resourceId] ?? [];
103
+ acc[tagging.resourceId] = [...existing, tagRow];
104
+ return acc;
105
+ }, {});
106
+ return (0, neverthrow_1.ok)(grouped);
107
+ });
108
+ }
109
+ async attachTagsToResources(resourceType, rows, tx) {
110
+ return this.throwableAsync(async () => {
111
+ if (rows.length === 0)
112
+ return (0, neverthrow_1.ok)([]);
113
+ const tagsResult = await this.findTagsForResources({ resourceType, resourceIds: rows.map((row) => row.id) }, tx);
114
+ if (tagsResult.isErr())
115
+ return (0, neverthrow_1.err)(tagsResult.error);
116
+ const tagsByResource = tagsResult.value;
117
+ const withTags = rows.map((row) => ({
118
+ ...row,
119
+ tags: tagsByResource[row.id] ?? [],
120
+ }));
121
+ return (0, neverthrow_1.ok)(withTags);
122
+ });
123
+ }
124
+ async listTaggings(input, tx) {
125
+ return this.throwableAsync(async () => {
126
+ const db = tx ?? this.orm;
127
+ const filters = [(0, drizzle_orm_1.eq)(this.schema.taggings.resourceType, input.resourceType)];
128
+ if (input.resourceIds?.length) {
129
+ filters.push((0, drizzle_orm_1.inArray)(this.schema.taggings.resourceId, input.resourceIds));
130
+ }
131
+ const rows = await db
132
+ .select()
133
+ .from(this.schema.taggings)
134
+ .where((0, drizzle_orm_1.and)(...filters));
135
+ return (0, neverthrow_1.ok)(rows);
136
+ });
137
+ }
138
+ async list(input, tx) {
139
+ return this.throwableAsync(async () => {
140
+ const db = tx ?? this.orm;
141
+ const conditions = this.getConditionBuilder(this.table);
142
+ conditions.applyFilters(input);
143
+ if (input?.assignableTo) {
144
+ conditions.push(this.helpers.arrayContains(this.table.assignableTo, [input.assignableTo]));
145
+ }
146
+ const whereClause = conditions.join();
147
+ const rowsQuery = this.withSortingAndPagination(db.select().from(this.table).where(whereClause), input || {});
148
+ const countQuery = db.select({ count: (0, drizzle_orm_1.count)() }).from(this.table).where(whereClause);
149
+ const [rows, [totalResult]] = await Promise.all([rowsQuery, countQuery]);
150
+ return (0, neverthrow_1.ok)({ rows, total: totalResult?.count ?? 0 });
151
+ });
152
+ }
153
+ }
154
+ exports.TagRepository = TagRepository;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TagService = void 0;
4
+ const base_service_1 = require("#modules/base/base.service");
5
+ class TagService extends base_service_1.BaseService {
6
+ async list(input) {
7
+ return this.repository.tag.list(input);
8
+ }
9
+ async listTaggings(input) {
10
+ return this.repository.tag.listTaggings(input);
11
+ }
12
+ async create(data, { user }) {
13
+ return this.repository.tag.create({ ...data, userId: user.id });
14
+ }
15
+ async update(data, { user }) {
16
+ return this.repository.tag.update({ ...data, userId: user.id });
17
+ }
18
+ async link(data, { user }) {
19
+ return this.repository.tag.link({ ...data, userId: user.id });
20
+ }
21
+ async linkBulk(data) {
22
+ return this.repository.tag.linkBulk(data);
23
+ }
24
+ async set(data) {
25
+ return this.repository.tag.set(data);
26
+ }
27
+ async unlink(data, { user }) {
28
+ return this.repository.tag.unlink({ ...data, userId: user.id });
29
+ }
30
+ }
31
+ exports.TagService = TagService;
@@ -4,9 +4,9 @@ export declare function createTagTRPC(tagService: TagService): import("@trpc/ser
4
4
  session: {
5
5
  id: string;
6
6
  userId: string;
7
- expiresAt: Date;
8
- createdAt: Date;
9
7
  updatedAt: Date;
8
+ createdAt: Date;
9
+ expiresAt: Date;
10
10
  token: string;
11
11
  ipAddress: string | null;
12
12
  userAgent: string | null;
@@ -18,13 +18,12 @@ export declare function createTagTRPC(tagService: TagService): import("@trpc/ser
18
18
  };
19
19
  user: {
20
20
  name: string;
21
- image: string | null;
22
21
  id: string;
23
- createdAt: Date;
24
22
  updatedAt: Date;
25
23
  email: string;
26
- metadata: Record<string, unknown>;
27
24
  emailVerified: boolean;
25
+ image: string | null;
26
+ createdAt: Date;
28
27
  role: string | null;
29
28
  banned: boolean | null;
30
29
  banReason: string | null;
@@ -34,6 +33,7 @@ export declare function createTagTRPC(tagService: TagService): import("@trpc/ser
34
33
  paymentPlanTier: string | null;
35
34
  paymentPlanExpiresAt: Date | null;
36
35
  preferences: string | null;
36
+ metadata: Record<string, unknown>;
37
37
  onboarding: number | null;
38
38
  flags: string | null;
39
39
  };
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTagTRPC = createTagTRPC;
4
+ const tag_schema_1 = require("@m5kdev/commons/modules/tag/tag.schema");
5
+ const tag_dto_1 = require("#modules/tag/tag.dto");
6
+ const _trpc_1 = require("#trpc");
7
+ function createTagTRPC(tagService) {
8
+ const tagListInput = tag_schema_1.tagListInputSchema.extend({
9
+ assignableTo: tag_schema_1.tagListSchema.shape.assignableTo,
10
+ });
11
+ return (0, _trpc_1.router)({
12
+ list: _trpc_1.procedure
13
+ .input(tagListInput)
14
+ .output(tag_schema_1.tagListOutputSchema)
15
+ .query(async ({ input }) => (0, _trpc_1.handleTRPCResult)(await tagService.list(input))),
16
+ listTaggings: _trpc_1.procedure
17
+ .input(tag_schema_1.taggingSchema
18
+ .pick({ resourceType: true })
19
+ .extend({ resourceIds: tag_schema_1.tagListInputSchema.shape.filters.optional() }))
20
+ .output(tag_dto_1.taggingsSelectOutput.array())
21
+ .query(async ({ input }) => (0, _trpc_1.handleTRPCResult)(await tagService.listTaggings(input))),
22
+ create: _trpc_1.procedure
23
+ .input(tag_schema_1.tagCreateSchema)
24
+ .output(tag_dto_1.tagsSelectOutput)
25
+ .mutation(async ({ ctx, input }) => {
26
+ return (0, _trpc_1.handleTRPCResult)(await tagService.create(input, ctx));
27
+ }),
28
+ update: _trpc_1.procedure
29
+ .input(tag_schema_1.tagUpdateSchema)
30
+ .output(tag_dto_1.tagsSelectOutput)
31
+ .mutation(async ({ ctx, input }) => {
32
+ return (0, _trpc_1.handleTRPCResult)(await tagService.update(input, ctx));
33
+ }),
34
+ link: _trpc_1.procedure
35
+ .input(tag_schema_1.tagLinkSchema)
36
+ .output(tag_dto_1.taggingsSelectOutput)
37
+ .mutation(async ({ ctx, input }) => {
38
+ return (0, _trpc_1.handleTRPCResult)(await tagService.link(input, ctx));
39
+ }),
40
+ unlink: _trpc_1.procedure
41
+ .input(tag_schema_1.tagLinkSchema)
42
+ .output(tag_dto_1.tagsSelectOutput)
43
+ .mutation(async ({ ctx, input }) => {
44
+ return (0, _trpc_1.handleTRPCResult)(await tagService.unlink(input, ctx));
45
+ }),
46
+ });
47
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ /**
3
+ * Applies pagination (limit and offset) to a drizzle query builder.
4
+ * Returns the query builder with pagination applied, or the original query if no limit is specified.
5
+ * Page is 1-based and only applied if limit is also provided.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.applyPagination = void 0;
9
+ const applyPagination = (query, limit, page) => {
10
+ if (limit)
11
+ query.limit(limit);
12
+ if (page && page > 1 && limit)
13
+ query.offset((page - 1) * limit);
14
+ return query;
15
+ };
16
+ exports.applyPagination = applyPagination;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applySorting = void 0;
4
+ const drizzle_orm_1 = require("drizzle-orm");
5
+ /**
6
+ * Applies sorting to a drizzle query builder.
7
+ * Returns the query builder with sorting applied.
8
+ * If no sort or order is specified, defaults to createdAt descending.
9
+ * If createdAt column doesn't exist, returns the query unchanged.
10
+ */
11
+ const applySorting = (query, table, sort, order) => {
12
+ const column = sort ? table[sort] : table.createdAt || table.id;
13
+ if (!column)
14
+ throw new Error(`Column ${sort} not found in table ${table.name}`);
15
+ query.orderBy(order === "asc" ? (0, drizzle_orm_1.asc)(column) : (0, drizzle_orm_1.desc)(column));
16
+ return query;
17
+ };
18
+ exports.applySorting = applySorting;
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getConditionsFromFilters = void 0;
4
+ const drizzle_orm_1 = require("drizzle-orm");
5
+ const luxon_1 = require("luxon");
6
+ // Helper: Create UTC date boundaries from ISO string
7
+ const getUTCDateBoundaries = (isoString) => {
8
+ const dateTime = luxon_1.DateTime.fromISO(isoString, { zone: "utc" });
9
+ return {
10
+ start: dateTime.startOf("day").toJSDate(),
11
+ end: dateTime.endOf("day").toJSDate(),
12
+ };
13
+ };
14
+ const getConditionsFromFilters = (conditions, filters, table) => {
15
+ if (!filters || filters.length === 0) {
16
+ return conditions;
17
+ }
18
+ // Process each filter (maximum one filter per column)
19
+ for (const filter of filters) {
20
+ const { columnId, type, method, value, valueTo } = filter;
21
+ // Get the column from the table using columnId
22
+ const column = table[columnId];
23
+ if (!column) {
24
+ continue; // Skip if column doesn't exist
25
+ }
26
+ // Handle isEmpty/isNotEmpty methods (work across types, ignore value)
27
+ if (method === "isEmpty" || method === "isNotEmpty") {
28
+ switch (type) {
29
+ case "string":
30
+ case "enum":
31
+ // isEmpty: IS NULL OR = ''
32
+ // isNotEmpty: IS NOT NULL AND != ''
33
+ if (method === "isEmpty") {
34
+ conditions.push((0, drizzle_orm_1.or)((0, drizzle_orm_1.isNull)(column), (0, drizzle_orm_1.eq)(column, "")));
35
+ }
36
+ else {
37
+ conditions.push((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(column), (0, drizzle_orm_1.ne)(column, "")));
38
+ }
39
+ continue;
40
+ case "number":
41
+ // isEmpty: IS NULL OR = 0
42
+ // isNotEmpty: IS NOT NULL AND != 0
43
+ if (method === "isEmpty") {
44
+ conditions.push((0, drizzle_orm_1.or)((0, drizzle_orm_1.isNull)(column), (0, drizzle_orm_1.eq)(column, 0)));
45
+ }
46
+ else {
47
+ conditions.push((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(column), (0, drizzle_orm_1.ne)(column, 0)));
48
+ }
49
+ continue;
50
+ case "boolean":
51
+ // Should not happen per plan, but handle gracefully
52
+ continue;
53
+ default:
54
+ continue;
55
+ }
56
+ }
57
+ // Apply filter based on type and method
58
+ switch (type) {
59
+ case "string":
60
+ switch (method) {
61
+ case "contains":
62
+ if (typeof value === "string") {
63
+ conditions.push((0, drizzle_orm_1.like)(column, `%${value}%`));
64
+ }
65
+ break;
66
+ case "equals":
67
+ if (typeof value === "string") {
68
+ conditions.push((0, drizzle_orm_1.eq)(column, value));
69
+ }
70
+ break;
71
+ case "starts_with":
72
+ if (typeof value === "string") {
73
+ conditions.push((0, drizzle_orm_1.like)(column, `${value}%`));
74
+ }
75
+ break;
76
+ case "ends_with":
77
+ if (typeof value === "string") {
78
+ conditions.push((0, drizzle_orm_1.like)(column, `%${value}`));
79
+ }
80
+ break;
81
+ case "is_null":
82
+ conditions.push((0, drizzle_orm_1.isNull)(column));
83
+ break;
84
+ case "is_not_null":
85
+ conditions.push((0, drizzle_orm_1.isNotNull)(column));
86
+ break;
87
+ }
88
+ break;
89
+ case "number":
90
+ switch (method) {
91
+ case "equals":
92
+ if (typeof value === "number") {
93
+ conditions.push((0, drizzle_orm_1.eq)(column, value));
94
+ }
95
+ break;
96
+ case "greater_than":
97
+ if (typeof value === "number") {
98
+ conditions.push((0, drizzle_orm_1.gte)(column, value));
99
+ }
100
+ break;
101
+ case "less_than":
102
+ if (typeof value === "number") {
103
+ conditions.push((0, drizzle_orm_1.lte)(column, value));
104
+ }
105
+ break;
106
+ case "is_null":
107
+ conditions.push((0, drizzle_orm_1.isNull)(column));
108
+ break;
109
+ case "is_not_null":
110
+ conditions.push((0, drizzle_orm_1.isNotNull)(column));
111
+ break;
112
+ }
113
+ break;
114
+ case "date":
115
+ if (typeof value !== "string")
116
+ break;
117
+ switch (method) {
118
+ case "on": {
119
+ const { start, end } = getUTCDateBoundaries(value);
120
+ conditions.push((0, drizzle_orm_1.and)((0, drizzle_orm_1.gte)(column, start), (0, drizzle_orm_1.lte)(column, end)));
121
+ break;
122
+ }
123
+ case "between":
124
+ if (valueTo) {
125
+ const { start } = getUTCDateBoundaries(value);
126
+ const { end } = getUTCDateBoundaries(valueTo);
127
+ conditions.push((0, drizzle_orm_1.between)(column, start, end));
128
+ }
129
+ break;
130
+ case "before": {
131
+ const { end } = getUTCDateBoundaries(value);
132
+ conditions.push((0, drizzle_orm_1.lte)(column, end));
133
+ break;
134
+ }
135
+ case "after": {
136
+ const { start } = getUTCDateBoundaries(value);
137
+ conditions.push((0, drizzle_orm_1.gte)(column, start));
138
+ break;
139
+ }
140
+ case "intersect": {
141
+ // Interval overlap: [columnId, endColumnId] intersects with [value, valueTo]
142
+ // Logic: columnId <= valueTo AND (endColumnId IS NULL OR endColumnId >= value)
143
+ if (!valueTo || !filter.endColumnId)
144
+ break;
145
+ const endColumn = table[filter.endColumnId];
146
+ if (!endColumn)
147
+ break;
148
+ const { start } = getUTCDateBoundaries(value);
149
+ const { end } = getUTCDateBoundaries(valueTo);
150
+ conditions.push((0, drizzle_orm_1.and)((0, drizzle_orm_1.lte)(column, end), (0, drizzle_orm_1.or)((0, drizzle_orm_1.isNull)(endColumn), (0, drizzle_orm_1.gte)(endColumn, start))));
151
+ break;
152
+ }
153
+ case "is_null":
154
+ conditions.push((0, drizzle_orm_1.isNull)(column));
155
+ break;
156
+ case "is_not_null":
157
+ conditions.push((0, drizzle_orm_1.isNotNull)(column));
158
+ break;
159
+ }
160
+ break;
161
+ case "boolean":
162
+ switch (method) {
163
+ case "equals":
164
+ if (typeof value === "boolean") {
165
+ conditions.push((0, drizzle_orm_1.eq)(column, value));
166
+ }
167
+ break;
168
+ case "is_null":
169
+ conditions.push((0, drizzle_orm_1.isNull)(column));
170
+ break;
171
+ case "is_not_null":
172
+ conditions.push((0, drizzle_orm_1.isNotNull)(column));
173
+ break;
174
+ }
175
+ break;
176
+ case "enum":
177
+ switch (method) {
178
+ case "oneOf":
179
+ if (Array.isArray(value) && value.length > 0) {
180
+ conditions.push((0, drizzle_orm_1.inArray)(column, value));
181
+ }
182
+ break;
183
+ case "equals":
184
+ if (typeof value === "string") {
185
+ conditions.push((0, drizzle_orm_1.eq)(column, value));
186
+ }
187
+ break;
188
+ case "is_null":
189
+ conditions.push((0, drizzle_orm_1.isNull)(column));
190
+ break;
191
+ case "is_not_null":
192
+ conditions.push((0, drizzle_orm_1.isNotNull)(column));
193
+ break;
194
+ }
195
+ break;
196
+ }
197
+ }
198
+ return conditions;
199
+ };
200
+ exports.getConditionsFromFilters = getConditionsFromFilters;