cross-seed 7.0.0-1 → 7.0.0-2

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 (229) hide show
  1. package/dist/Result.d.ts +27 -0
  2. package/dist/Result.js +64 -0
  3. package/dist/Result.js.map +1 -0
  4. package/dist/action.d.ts +34 -0
  5. package/dist/action.js +694 -0
  6. package/dist/action.js.map +1 -0
  7. package/dist/arr.d.ts +31 -0
  8. package/dist/arr.js +267 -0
  9. package/dist/arr.js.map +1 -0
  10. package/dist/auth.d.ts +3 -0
  11. package/dist/auth.js +28 -0
  12. package/dist/auth.js.map +1 -0
  13. package/dist/clients/Deluge.d.ts +153 -0
  14. package/dist/clients/Deluge.js +698 -0
  15. package/dist/clients/Deluge.js.map +1 -0
  16. package/dist/clients/QBittorrent.d.ts +218 -0
  17. package/dist/clients/QBittorrent.js +785 -0
  18. package/dist/clients/QBittorrent.js.map +1 -0
  19. package/dist/clients/RTorrent.d.ts +43 -0
  20. package/dist/clients/RTorrent.js +657 -0
  21. package/dist/clients/RTorrent.js.map +1 -0
  22. package/dist/clients/TorrentClient.d.ts +108 -0
  23. package/dist/clients/TorrentClient.js +341 -0
  24. package/dist/clients/TorrentClient.js.map +1 -0
  25. package/dist/clients/Transmission.d.ts +43 -0
  26. package/dist/clients/Transmission.js +404 -0
  27. package/dist/clients/Transmission.js.map +1 -0
  28. package/dist/cmd.d.ts +2 -0
  29. package/dist/cmd.js +128 -0
  30. package/dist/cmd.js.map +1 -0
  31. package/dist/configSchema.d.ts +1 -0
  32. package/dist/configSchema.js +2 -0
  33. package/dist/configSchema.js.map +1 -0
  34. package/dist/configuration.d.ts +63 -0
  35. package/dist/configuration.js +321 -0
  36. package/dist/configuration.js.map +1 -0
  37. package/dist/constants.d.ts +108 -0
  38. package/dist/constants.js +251 -0
  39. package/dist/constants.js.map +1 -0
  40. package/dist/dataFiles.d.ts +8 -0
  41. package/dist/dataFiles.js +223 -0
  42. package/dist/dataFiles.js.map +1 -0
  43. package/dist/db.d.ts +3 -0
  44. package/dist/db.js +216 -0
  45. package/dist/db.js.map +1 -0
  46. package/dist/dbConfig.d.ts +4 -0
  47. package/dist/dbConfig.js +67 -0
  48. package/dist/dbConfig.js.map +1 -0
  49. package/dist/decide.d.ts +25 -0
  50. package/dist/decide.js +553 -0
  51. package/dist/decide.js.map +1 -0
  52. package/dist/diff.d.ts +1 -0
  53. package/dist/diff.js +24 -0
  54. package/dist/diff.js.map +1 -0
  55. package/dist/errors.d.ts +3 -0
  56. package/dist/errors.js +7 -0
  57. package/dist/errors.js.map +1 -0
  58. package/dist/indexers.d.ts +105 -0
  59. package/dist/indexers.js +248 -0
  60. package/dist/indexers.js.map +1 -0
  61. package/dist/inject.d.ts +2 -0
  62. package/dist/inject.js +594 -0
  63. package/dist/inject.js.map +1 -0
  64. package/dist/jobs.d.ts +29 -0
  65. package/dist/jobs.js +151 -0
  66. package/dist/jobs.js.map +1 -0
  67. package/dist/logger.d.ts +29 -0
  68. package/dist/logger.js +157 -0
  69. package/dist/logger.js.map +1 -0
  70. package/dist/migrations/00-initialSchema.d.ts +9 -0
  71. package/dist/migrations/00-initialSchema.js +30 -0
  72. package/dist/migrations/00-initialSchema.js.map +1 -0
  73. package/dist/migrations/01-jobs.d.ts +9 -0
  74. package/dist/migrations/01-jobs.js +12 -0
  75. package/dist/migrations/01-jobs.js.map +1 -0
  76. package/dist/migrations/02-timestamps.d.ts +9 -0
  77. package/dist/migrations/02-timestamps.js +21 -0
  78. package/dist/migrations/02-timestamps.js.map +1 -0
  79. package/dist/migrations/03-rateLimits.d.ts +9 -0
  80. package/dist/migrations/03-rateLimits.js +14 -0
  81. package/dist/migrations/03-rateLimits.js.map +1 -0
  82. package/dist/migrations/04-auth.d.ts +9 -0
  83. package/dist/migrations/04-auth.js +13 -0
  84. package/dist/migrations/04-auth.js.map +1 -0
  85. package/dist/migrations/05-caps.d.ts +9 -0
  86. package/dist/migrations/05-caps.js +16 -0
  87. package/dist/migrations/05-caps.js.map +1 -0
  88. package/dist/migrations/06-uniqueDecisions.d.ts +9 -0
  89. package/dist/migrations/06-uniqueDecisions.js +29 -0
  90. package/dist/migrations/06-uniqueDecisions.js.map +1 -0
  91. package/dist/migrations/07-limits.d.ts +9 -0
  92. package/dist/migrations/07-limits.js +12 -0
  93. package/dist/migrations/07-limits.js.map +1 -0
  94. package/dist/migrations/08-rss.d.ts +9 -0
  95. package/dist/migrations/08-rss.js +15 -0
  96. package/dist/migrations/08-rss.js.map +1 -0
  97. package/dist/migrations/09-clientAndDataSearchees.d.ts +9 -0
  98. package/dist/migrations/09-clientAndDataSearchees.js +34 -0
  99. package/dist/migrations/09-clientAndDataSearchees.js.map +1 -0
  100. package/dist/migrations/10-indexerNameAudioBookCaps.d.ts +9 -0
  101. package/dist/migrations/10-indexerNameAudioBookCaps.js +18 -0
  102. package/dist/migrations/10-indexerNameAudioBookCaps.js.map +1 -0
  103. package/dist/migrations/11-trackers.d.ts +9 -0
  104. package/dist/migrations/11-trackers.js +38 -0
  105. package/dist/migrations/11-trackers.js.map +1 -0
  106. package/dist/migrations/12-user-auth.d.ts +9 -0
  107. package/dist/migrations/12-user-auth.js +22 -0
  108. package/dist/migrations/12-user-auth.js.map +1 -0
  109. package/dist/migrations/13-settings.d.ts +9 -0
  110. package/dist/migrations/13-settings.js +23 -0
  111. package/dist/migrations/13-settings.js.map +1 -0
  112. package/dist/migrations/14-indexer-enabled-flag.d.ts +9 -0
  113. package/dist/migrations/14-indexer-enabled-flag.js +12 -0
  114. package/dist/migrations/14-indexer-enabled-flag.js.map +1 -0
  115. package/dist/migrations/15-remove-url-unique-constraint.d.ts +9 -0
  116. package/dist/migrations/15-remove-url-unique-constraint.js +14 -0
  117. package/dist/migrations/15-remove-url-unique-constraint.js.map +1 -0
  118. package/dist/migrations/16-prune-inactive-indexers.d.ts +9 -0
  119. package/dist/migrations/16-prune-inactive-indexers.js +17 -0
  120. package/dist/migrations/16-prune-inactive-indexers.js.map +1 -0
  121. package/dist/migrations/migrations.d.ts +13 -0
  122. package/dist/migrations/migrations.js +41 -0
  123. package/dist/migrations/migrations.js.map +1 -0
  124. package/dist/parseTorrent.d.ts +53 -0
  125. package/dist/parseTorrent.js +128 -0
  126. package/dist/parseTorrent.js.map +1 -0
  127. package/dist/pipeline.d.ts +41 -0
  128. package/dist/pipeline.js +574 -0
  129. package/dist/pipeline.js.map +1 -0
  130. package/dist/preFilter.d.ts +25 -0
  131. package/dist/preFilter.js +250 -0
  132. package/dist/preFilter.js.map +1 -0
  133. package/dist/problems/linking.d.ts +2 -0
  134. package/dist/problems/linking.js +80 -0
  135. package/dist/problems/linking.js.map +1 -0
  136. package/dist/problems/path.d.ts +22 -0
  137. package/dist/problems/path.js +96 -0
  138. package/dist/problems/path.js.map +1 -0
  139. package/dist/problems.d.ts +13 -0
  140. package/dist/problems.js +48 -0
  141. package/dist/problems.js.map +1 -0
  142. package/dist/pushNotifier.d.ts +19 -0
  143. package/dist/pushNotifier.js +137 -0
  144. package/dist/pushNotifier.js.map +1 -0
  145. package/dist/routes/baseApi.d.ts +2 -0
  146. package/dist/routes/baseApi.js +354 -0
  147. package/dist/routes/baseApi.js.map +1 -0
  148. package/dist/routes/indexerApi.d.ts +6 -0
  149. package/dist/routes/indexerApi.js +165 -0
  150. package/dist/routes/indexerApi.js.map +1 -0
  151. package/dist/routes/staticFrontendPlugin.d.ts +4 -0
  152. package/dist/routes/staticFrontendPlugin.js +61 -0
  153. package/dist/routes/staticFrontendPlugin.js.map +1 -0
  154. package/dist/runtimeConfig.d.ts +6 -0
  155. package/dist/runtimeConfig.js +27 -0
  156. package/dist/runtimeConfig.js.map +1 -0
  157. package/dist/searchee.d.ts +108 -0
  158. package/dist/searchee.js +689 -0
  159. package/dist/searchee.js.map +1 -0
  160. package/dist/server.d.ts +4 -0
  161. package/dist/server.js +65 -0
  162. package/dist/server.js.map +1 -0
  163. package/dist/services/indexerService.d.ts +96 -0
  164. package/dist/services/indexerService.js +287 -0
  165. package/dist/services/indexerService.js.map +1 -0
  166. package/dist/sessionCookies.d.ts +5 -0
  167. package/dist/sessionCookies.js +27 -0
  168. package/dist/sessionCookies.js.map +1 -0
  169. package/dist/startup.d.ts +25 -0
  170. package/dist/startup.js +157 -0
  171. package/dist/startup.js.map +1 -0
  172. package/dist/torrent.d.ts +69 -0
  173. package/dist/torrent.js +641 -0
  174. package/dist/torrent.js.map +1 -0
  175. package/dist/torznab.d.ts +60 -0
  176. package/dist/torznab.js +711 -0
  177. package/dist/torznab.js.map +1 -0
  178. package/dist/trpc/fastifyAdapter.d.ts +2 -0
  179. package/dist/trpc/fastifyAdapter.js +9 -0
  180. package/dist/trpc/fastifyAdapter.js.map +1 -0
  181. package/dist/trpc/index.d.ts +49 -0
  182. package/dist/trpc/index.js +53 -0
  183. package/dist/trpc/index.js.map +1 -0
  184. package/dist/trpc/routers/auth.d.ts +43 -0
  185. package/dist/trpc/routers/auth.js +116 -0
  186. package/dist/trpc/routers/auth.js.map +1 -0
  187. package/dist/trpc/routers/clients.d.ts +21 -0
  188. package/dist/trpc/routers/clients.js +65 -0
  189. package/dist/trpc/routers/clients.js.map +1 -0
  190. package/dist/trpc/routers/health.d.ts +14 -0
  191. package/dist/trpc/routers/health.js +20 -0
  192. package/dist/trpc/routers/health.js.map +1 -0
  193. package/dist/trpc/routers/index.d.ts +391 -0
  194. package/dist/trpc/routers/index.js +23 -0
  195. package/dist/trpc/routers/index.js.map +1 -0
  196. package/dist/trpc/routers/indexers.d.ts +75 -0
  197. package/dist/trpc/routers/indexers.js +79 -0
  198. package/dist/trpc/routers/indexers.js.map +1 -0
  199. package/dist/trpc/routers/jobs.d.ts +33 -0
  200. package/dist/trpc/routers/jobs.js +84 -0
  201. package/dist/trpc/routers/jobs.js.map +1 -0
  202. package/dist/trpc/routers/logs.d.ts +27 -0
  203. package/dist/trpc/routers/logs.js +91 -0
  204. package/dist/trpc/routers/logs.js.map +1 -0
  205. package/dist/trpc/routers/searchees.d.ts +51 -0
  206. package/dist/trpc/routers/searchees.js +156 -0
  207. package/dist/trpc/routers/searchees.js.map +1 -0
  208. package/dist/trpc/routers/settings.d.ts +83 -0
  209. package/dist/trpc/routers/settings.js +92 -0
  210. package/dist/trpc/routers/settings.js.map +1 -0
  211. package/dist/trpc/routers/stats.d.ts +42 -0
  212. package/dist/trpc/routers/stats.js +102 -0
  213. package/dist/trpc/routers/stats.js.map +1 -0
  214. package/dist/userAuth.d.ts +21 -0
  215. package/dist/userAuth.js +86 -0
  216. package/dist/userAuth.js.map +1 -0
  217. package/dist/utils/authUtils.d.ts +10 -0
  218. package/dist/utils/authUtils.js +24 -0
  219. package/dist/utils/authUtils.js.map +1 -0
  220. package/dist/utils/logWatcher.d.ts +28 -0
  221. package/dist/utils/logWatcher.js +218 -0
  222. package/dist/utils/logWatcher.js.map +1 -0
  223. package/dist/utils/object.d.ts +1 -0
  224. package/dist/utils/object.js +4 -0
  225. package/dist/utils/object.js.map +1 -0
  226. package/dist/utils.d.ts +175 -0
  227. package/dist/utils.js +660 -0
  228. package/dist/utils.js.map +1 -0
  229. package/package.json +2 -2
@@ -0,0 +1,102 @@
1
+ import { authedProcedure, router } from "../index.js";
2
+ import { db } from "../../db.js";
3
+ import { estimateSearchString } from "../../torznab.js";
4
+ import { mapAsync } from "../../utils.js";
5
+ export const statsRouter = router({
6
+ getOverview: authedProcedure.query(async () => {
7
+ const [searcheeResult, searcheeNames, totalIndexerResult, healthyIndexerResult, timestampResult, decisionsByType, recentMatches, matchAggregates,] = await Promise.all([
8
+ db("searchee").count({ count: "*" }).first(),
9
+ db("searchee").select("name"),
10
+ db("indexer").count({ count: "*" }).first(),
11
+ db("indexer")
12
+ .where({ enabled: true, search_cap: true })
13
+ .where((qb) => qb
14
+ .whereNull("status")
15
+ .orWhere("status", "OK")
16
+ .orWhere("retry_after", "<", Date.now()))
17
+ .count({ count: "*" })
18
+ .first(),
19
+ db("timestamp").count({ count: "*" }).first(),
20
+ db("decision")
21
+ .select("decision")
22
+ .count({ count: "*" })
23
+ .groupBy("decision"),
24
+ db("decision")
25
+ .whereIn("decision", [
26
+ "MATCH",
27
+ "MATCH_SIZE_ONLY",
28
+ "MATCH_PARTIAL",
29
+ ])
30
+ .where("last_seen", ">", Date.now() - 24 * 60 * 60 * 1000) // last 24h
31
+ .count({ count: "*" })
32
+ .first(),
33
+ db("decision")
34
+ .whereNotNull("info_hash")
35
+ .select({
36
+ snatchCount: db.raw("COUNT(DISTINCT info_hash)"),
37
+ matchCount: db.raw("COUNT(DISTINCT CASE WHEN decision IN ('MATCH','MATCH_SIZE_ONLY','MATCH_PARTIAL') THEN info_hash END)"),
38
+ matchCountWithInfoHash: db.raw("COUNT(DISTINCT CASE WHEN decision IN ('MATCH','MATCH_SIZE_ONLY','MATCH_PARTIAL','SAME_INFO_HASH','INFO_HASH_ALREADY_EXISTS') THEN info_hash END)"),
39
+ })
40
+ .first(),
41
+ ]);
42
+ const snatchCount = Number(matchAggregates?.snatchCount ?? 0);
43
+ const matchCount = Number(matchAggregates?.matchCount ?? 0);
44
+ const matchCountWithInfoHash = Number(matchAggregates?.matchCountWithInfoHash ?? 0);
45
+ const totalMatches = matchCount;
46
+ const searcheeNameList = searcheeNames
47
+ .map((row) => row.name)
48
+ .filter((name) => typeof name === "string" && name.length > 0);
49
+ const queryCount = new Set(await mapAsync(searcheeNameList, estimateSearchString)).size;
50
+ const totalSearchees = Number(searcheeResult?.count || 0);
51
+ const matchRate = totalSearchees > 0
52
+ ? (totalMatches / totalSearchees).toFixed(2)
53
+ : "0";
54
+ const matchesPerSnatch = snatchCount > 0
55
+ ? (matchCountWithInfoHash / snatchCount).toFixed(3)
56
+ : "0";
57
+ const matchesPerQuery = queryCount > 0 ? (matchCount / queryCount).toFixed(3) : "0";
58
+ const queryIndexerCount = Number(timestampResult?.count || 0);
59
+ const matchesPerQueryIndexer = queryIndexerCount > 0
60
+ ? (matchCount / queryIndexerCount).toFixed(3)
61
+ : "0";
62
+ const wastedSnatchCount = Math.max(snatchCount - matchCountWithInfoHash, 0);
63
+ const wastedSnatchRate = snatchCount > 0
64
+ ? (wastedSnatchCount / snatchCount).toFixed(3)
65
+ : "0";
66
+ const totalIndexers = Number(totalIndexerResult?.count || 0);
67
+ const healthyIndexers = Number(healthyIndexerResult?.count || 0);
68
+ const unhealthyIndexers = Math.max(totalIndexers - healthyIndexers, 0);
69
+ const allIndexersHealthy = unhealthyIndexers === 0;
70
+ return {
71
+ totalSearchees,
72
+ totalMatches,
73
+ totalIndexers,
74
+ healthyIndexers,
75
+ recentMatches: recentMatches?.count || 0,
76
+ matchRate: parseFloat(matchRate),
77
+ matchesPerSnatch: parseFloat(matchesPerSnatch),
78
+ matchesPerQuery: parseFloat(matchesPerQuery),
79
+ matchesPerQueryIndexer: parseFloat(matchesPerQueryIndexer),
80
+ snatchCount,
81
+ queryCount,
82
+ queryIndexerCount,
83
+ wastedSnatchCount,
84
+ wastedSnatchRate: parseFloat(wastedSnatchRate),
85
+ unhealthyIndexers,
86
+ allIndexersHealthy,
87
+ decisionBreakdown: decisionsByType,
88
+ };
89
+ }),
90
+ getIndexerStats: authedProcedure.query(async () => {
91
+ const indexers = await db("indexer")
92
+ .select("id", "name", "enabled", "status")
93
+ .orderBy("name");
94
+ return indexers.map((indexer) => ({
95
+ id: indexer.id,
96
+ name: indexer.name || `Indexer ${indexer.id}`,
97
+ enabled: indexer.enabled,
98
+ status: indexer.status || "unknown",
99
+ }));
100
+ }),
101
+ });
102
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/trpc/routers/stats.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface User {
2
+ id: number;
3
+ username: string;
4
+ password: string;
5
+ created_at: Date;
6
+ }
7
+ export interface Session {
8
+ id: string;
9
+ user_id: number;
10
+ expires_at: number;
11
+ created_at: number;
12
+ }
13
+ export declare function createUser(username: string, password: string): Promise<User>;
14
+ export declare function findUserByUsername(username: string): Promise<User | undefined>;
15
+ export declare function validateUserCredentials(username: string, password: string): Promise<User | null>;
16
+ export declare function createSession(userId: number): Promise<Session>;
17
+ export declare function validateSession(sessionId: string): Promise<User | null>;
18
+ export declare function removeSession(sessionId: string): Promise<void>;
19
+ export declare function hasUsers(): Promise<boolean>;
20
+ export declare function createInitialUserIfNeeded(username: string, password: string): Promise<User | null>;
21
+ export declare function resetUsers(): Promise<string>;
@@ -0,0 +1,86 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import bcrypt from "bcryptjs";
3
+ import { db } from "./db.js";
4
+ import { Label, logger } from "./logger.js";
5
+ const SESSION_EXPIRY = 30 * 24 * 60 * 60 * 1000; // 30 days in milliseconds
6
+ export async function createUser(username, password) {
7
+ const hashedPassword = await bcrypt.hash(password, 10);
8
+ const [user] = await db("user")
9
+ .insert({
10
+ username,
11
+ password: hashedPassword,
12
+ })
13
+ .returning("*");
14
+ logger.info({
15
+ label: Label.AUTH,
16
+ message: `Created user: ${username}`,
17
+ });
18
+ return user;
19
+ }
20
+ export async function findUserByUsername(username) {
21
+ return db("user").where({ username }).first();
22
+ }
23
+ export async function validateUserCredentials(username, password) {
24
+ const user = await findUserByUsername(username);
25
+ if (!user) {
26
+ return null;
27
+ }
28
+ const isValid = await bcrypt.compare(password, user.password);
29
+ return isValid ? user : null;
30
+ }
31
+ export async function createSession(userId) {
32
+ const sessionId = randomBytes(32).toString("hex");
33
+ const now = Date.now();
34
+ const expiresAt = now + SESSION_EXPIRY;
35
+ const session = {
36
+ id: sessionId,
37
+ user_id: userId,
38
+ expires_at: expiresAt,
39
+ created_at: now,
40
+ };
41
+ await db("session").insert(session);
42
+ return session;
43
+ }
44
+ export async function validateSession(sessionId) {
45
+ const session = await db("session")
46
+ .where({
47
+ id: sessionId,
48
+ })
49
+ .where("expires_at", ">", Date.now())
50
+ .first();
51
+ if (!session) {
52
+ return null;
53
+ }
54
+ const user = await db("user").where({ id: session.user_id }).first();
55
+ return user || null;
56
+ }
57
+ export async function removeSession(sessionId) {
58
+ await db("session").where({ id: sessionId }).delete();
59
+ }
60
+ export async function hasUsers() {
61
+ const count = await db("user").count("* as count").first();
62
+ return count?.count > 0;
63
+ }
64
+ export async function createInitialUserIfNeeded(username, password) {
65
+ const hasExistingUsers = await hasUsers();
66
+ if (hasExistingUsers) {
67
+ logger.info({
68
+ label: Label.AUTH,
69
+ message: "Initial user already exists, skipping creation",
70
+ });
71
+ return null;
72
+ }
73
+ logger.info({
74
+ label: Label.AUTH,
75
+ message: "Creating initial user",
76
+ });
77
+ return createUser(username, password);
78
+ }
79
+ export async function resetUsers() {
80
+ const deletedSessions = await db("session").del();
81
+ const deletedUsers = await db("user").del();
82
+ const userLabel = deletedUsers === 1 ? "user" : "users";
83
+ const sessionLabel = deletedSessions === 1 ? "session" : "sessions";
84
+ return `Deleted ${deletedUsers} ${userLabel} and ${deletedSessions} ${sessionLabel}.`;
85
+ }
86
+ //# sourceMappingURL=userAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userAuth.js","sourceRoot":"","sources":["../src/userAuth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { FastifyRequest, FastifyReply } from "fastify";
2
+ /**
3
+ * Checks all http API requests for authorized apiKey
4
+ * uses param `?apikey=` or as header `x-api-key`
5
+ */
6
+ export declare function authorize(request: FastifyRequest<{
7
+ Querystring: {
8
+ apikey?: string;
9
+ };
10
+ }>, reply: FastifyReply): Promise<boolean>;
@@ -0,0 +1,24 @@
1
+ import { checkApiKey } from "../auth.js";
2
+ import { Label, logger } from "../logger.js";
3
+ /**
4
+ * Checks all http API requests for authorized apiKey
5
+ * uses param `?apikey=` or as header `x-api-key`
6
+ */
7
+ export async function authorize(request, reply) {
8
+ const apiKey = request.headers["x-api-key"] || request.query.apikey || "";
9
+ const isAuthorized = await checkApiKey(apiKey);
10
+ if (!isAuthorized) {
11
+ const ipAddress = request.headers["x-forwarded-for"]
12
+ ?.split(",")
13
+ .shift() || request.socket.remoteAddress;
14
+ logger.error({
15
+ label: Label.SERVER,
16
+ message: `Unauthorized API access attempt to ${request.url} from ${ipAddress}`,
17
+ });
18
+ void reply
19
+ .code(401)
20
+ .send("Specify the API key in an X-Api-Key header or an apikey query param.");
21
+ }
22
+ return isAuthorized;
23
+ }
24
+ //# sourceMappingURL=authUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authUtils.js","sourceRoot":"","sources":["../../src/utils/authUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE7C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC9B,OAEE,EACF,KAAmB;IAEnB,MAAM,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,WAAW,CAAY,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;IACxE,MAAM,YAAY,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,YAAY,EAAE,CAAC;QACnB,MAAM,SAAS,GACb,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAY;YAC7C,EAAE,KAAK,CAAC,GAAG,CAAC;aACX,KAAK,EAAE,IAAI,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC;YACZ,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,OAAO,EAAE,sCAAsC,OAAO,CAAC,GAAG,SAAS,SAAS,EAAE;SAC9E,CAAC,CAAC;QACH,KAAK,KAAK;aACR,IAAI,CAAC,GAAG,CAAC;aACT,IAAI,CACJ,sEAAsE,CACtE,CAAC;IACJ,CAAC;IACD,OAAO,YAAY,CAAC;AACrB,CAAC"}
@@ -0,0 +1,28 @@
1
+ export interface LogEntry {
2
+ timestamp: string;
3
+ level: string;
4
+ label?: string;
5
+ message: string;
6
+ }
7
+ type LogCallback = (log: LogEntry) => void;
8
+ declare class LogWatcher {
9
+ private watchers;
10
+ private subscribers;
11
+ private lastPositions;
12
+ private retryTimers;
13
+ constructor();
14
+ private startWatching;
15
+ private watchLogFile;
16
+ private initializePosition;
17
+ private handleFileChange;
18
+ private parseLogContent;
19
+ private tryParseLogLine;
20
+ private notifySubscribers;
21
+ subscribe(callback: LogCallback): () => void;
22
+ getRecentLogs(limit?: number): Promise<LogEntry[]>;
23
+ private shouldIncludeLevel;
24
+ destroy(): void;
25
+ }
26
+ export declare function getLogWatcher(): LogWatcher;
27
+ export declare function destroyLogWatcher(): void;
28
+ export {};
@@ -0,0 +1,218 @@
1
+ import { promises as fs, watch } from "fs";
2
+ import { join } from "path";
3
+ import { appDir } from "../configuration.js";
4
+ import { logger } from "../logger.js";
5
+ class LogWatcher {
6
+ watchers = new Map();
7
+ subscribers = new Set();
8
+ lastPositions = new Map();
9
+ retryTimers = new Map();
10
+ constructor() {
11
+ this.startWatching();
12
+ }
13
+ startWatching() {
14
+ const logFiles = ["verbose.current.log"];
15
+ for (const fileName of logFiles) {
16
+ const filePath = join(appDir(), "logs", fileName);
17
+ this.watchLogFile(filePath);
18
+ }
19
+ }
20
+ watchLogFile(filePath) {
21
+ // Initialize position to end of file (only watch new entries)
22
+ void this.initializePosition(filePath);
23
+ const clearRetryTimer = () => {
24
+ const existingTimer = this.retryTimers.get(filePath);
25
+ if (existingTimer) {
26
+ clearTimeout(existingTimer);
27
+ this.retryTimers.delete(filePath);
28
+ }
29
+ };
30
+ const scheduleRetry = () => {
31
+ if (this.retryTimers.has(filePath)) {
32
+ return;
33
+ }
34
+ const timeout = setTimeout(() => {
35
+ this.retryTimers.delete(filePath);
36
+ this.watchLogFile(filePath);
37
+ }, 1000);
38
+ if (typeof timeout.unref === "function") {
39
+ timeout.unref();
40
+ }
41
+ this.retryTimers.set(filePath, timeout);
42
+ };
43
+ try {
44
+ const watcher = watch(filePath, (eventType) => {
45
+ if (eventType === "change") {
46
+ void this.handleFileChange(filePath);
47
+ }
48
+ else if (eventType === "rename") {
49
+ // File was rotated or replaced - reset position and retry watching
50
+ this.lastPositions.set(filePath, 0);
51
+ this.watchers.get(filePath)?.close();
52
+ this.watchers.delete(filePath);
53
+ scheduleRetry();
54
+ }
55
+ });
56
+ watcher.on("error", (error) => {
57
+ console.error(`Error watching ${filePath}:`, error);
58
+ this.watchers.delete(filePath);
59
+ if (error.code === "ENOENT") {
60
+ scheduleRetry();
61
+ }
62
+ });
63
+ clearRetryTimer();
64
+ this.watchers.set(filePath, watcher);
65
+ }
66
+ catch (error) {
67
+ const err = error;
68
+ if (err.code === "ENOENT") {
69
+ scheduleRetry();
70
+ }
71
+ else {
72
+ console.error(`Failed to watch ${filePath}:`, error);
73
+ }
74
+ }
75
+ }
76
+ async initializePosition(filePath) {
77
+ try {
78
+ const stats = await fs.stat(filePath);
79
+ this.lastPositions.set(filePath, stats.size);
80
+ }
81
+ catch (error) {
82
+ // File doesn't exist yet, start from beginning
83
+ this.lastPositions.set(filePath, 0);
84
+ }
85
+ }
86
+ async handleFileChange(filePath) {
87
+ try {
88
+ const stats = await fs.stat(filePath);
89
+ const lastPosition = this.lastPositions.get(filePath) || 0;
90
+ if (stats.size <= lastPosition) {
91
+ // File was truncated or rotated, start from beginning
92
+ this.lastPositions.set(filePath, 0);
93
+ return;
94
+ }
95
+ // Read only the new content
96
+ const stream = await fs.open(filePath, "r");
97
+ const buffer = Buffer.alloc(stats.size - lastPosition);
98
+ await stream.read(buffer, 0, buffer.length, lastPosition);
99
+ await stream.close();
100
+ const newContent = buffer.toString("utf8");
101
+ const logEntries = this.parseLogContent(newContent);
102
+ for (const logEntry of logEntries) {
103
+ this.notifySubscribers(logEntry);
104
+ }
105
+ this.lastPositions.set(filePath, stats.size);
106
+ }
107
+ catch (error) {
108
+ console.error(`Error reading ${filePath}:`, error);
109
+ }
110
+ }
111
+ parseLogContent(content) {
112
+ const logEntries = [];
113
+ const lines = content.split("\n");
114
+ let currentEntry = null;
115
+ for (const line of lines) {
116
+ if (!line.trim())
117
+ continue;
118
+ const parsedEntry = this.tryParseLogLine(line);
119
+ if (parsedEntry) {
120
+ // This is a new log entry
121
+ if (currentEntry) {
122
+ logEntries.push(currentEntry);
123
+ }
124
+ currentEntry = parsedEntry;
125
+ }
126
+ else if (currentEntry) {
127
+ // This is a continuation line (stack trace, etc.)
128
+ currentEntry.message += "\n" + line;
129
+ }
130
+ else {
131
+ // Orphan line with no preceding log entry
132
+ logEntries.push({
133
+ timestamp: new Date().toISOString(),
134
+ level: "info",
135
+ label: "raw",
136
+ message: line,
137
+ });
138
+ }
139
+ }
140
+ if (currentEntry) {
141
+ logEntries.push(currentEntry);
142
+ }
143
+ return logEntries;
144
+ }
145
+ tryParseLogLine(line) {
146
+ // Parse winston text format: "2025-06-01 00:00:35.123 info: [scheduler] starting job: rss"
147
+ const logRegex = /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d{3})?) (\w+):\s*(?:\[([^\]]+)\])?\s*(.*)$/;
148
+ const match = line.match(logRegex);
149
+ if (match) {
150
+ const [, timestamp, level, label, message] = match;
151
+ return {
152
+ timestamp,
153
+ level,
154
+ label: label || undefined,
155
+ message: message.trim(),
156
+ };
157
+ }
158
+ return null;
159
+ }
160
+ notifySubscribers(logEntry) {
161
+ this.subscribers.forEach((callback) => {
162
+ try {
163
+ callback(logEntry);
164
+ }
165
+ catch (error) {
166
+ console.error("Error in log subscriber:", error);
167
+ }
168
+ });
169
+ }
170
+ subscribe(callback) {
171
+ this.subscribers.add(callback);
172
+ return () => this.subscribers.delete(callback);
173
+ }
174
+ async getRecentLogs(limit = 100) {
175
+ const filePath = join(appDir(), "logs", "verbose.current.log");
176
+ try {
177
+ const fileContent = await fs.readFile(filePath, "utf-8");
178
+ const allEntries = this.parseLogContent(fileContent);
179
+ return allEntries.slice(-limit);
180
+ }
181
+ catch (error) {
182
+ logger.error(`Error reading log file ${filePath}:`, error);
183
+ return [];
184
+ }
185
+ }
186
+ shouldIncludeLevel(logLevel, filterLevel) {
187
+ const levels = ["error", "warn", "info", "verbose", "debug"];
188
+ const logIndex = levels.indexOf(logLevel);
189
+ const filterIndex = levels.indexOf(filterLevel);
190
+ return logIndex <= filterIndex;
191
+ }
192
+ destroy() {
193
+ for (const watcher of this.watchers.values()) {
194
+ watcher.close();
195
+ }
196
+ this.watchers.clear();
197
+ this.subscribers.clear();
198
+ for (const timer of this.retryTimers.values()) {
199
+ clearTimeout(timer);
200
+ }
201
+ this.retryTimers.clear();
202
+ }
203
+ }
204
+ // Singleton instance
205
+ let logWatcher = null;
206
+ export function getLogWatcher() {
207
+ if (!logWatcher) {
208
+ logWatcher = new LogWatcher();
209
+ }
210
+ return logWatcher;
211
+ }
212
+ export function destroyLogWatcher() {
213
+ if (logWatcher) {
214
+ logWatcher.destroy();
215
+ logWatcher = null;
216
+ }
217
+ }
218
+ //# sourceMappingURL=logWatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logWatcher.js","sourceRoot":"","sources":["../../src/utils/logWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAWtC,MAAM,UAAU;IACP,QAAQ,GAAG,IAAI,GAAG,EAAoC,CAAC;IACvD,WAAW,GAAG,IAAI,GAAG,EAAe,CAAC;IACrC,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,WAAW,GAAG,IAAI,GAAG,EAA0B,CAAC;IAExD;QACC,IAAI,CAAC,aAAa,EAAE,CAAC;IACtB,CAAC;IAEO,aAAa;QACpB,MAAM,QAAQ,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAEzC,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;YAClD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;IACF,CAAC;IAEO,YAAY,CAAC,QAAgB;QACpC,8DAA8D;QAC9D,KAAK,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAEvC,MAAM,eAAe,GAAG,GAAG,EAAE;YAC5B,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACrD,IAAI,aAAa,EAAE,CAAC;gBACnB,YAAY,CAAC,aAAa,CAAC,CAAC;gBAC5B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACnC,CAAC;QACF,CAAC,CAAC;QAEF,MAAM,aAAa,GAAG,GAAG,EAAE;YAC1B,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpC,OAAO;YACR,CAAC;YACD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC/B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAClC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC,EAAE,IAAI,CAAC,CAAC;YACT,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;gBACzC,OAAO,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;YACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACzC,CAAC,CAAC;QAEF,IAAI,CAAC;YACJ,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE;gBAC7C,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;oBAC5B,KAAK,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;gBACtC,CAAC;qBAAM,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;oBACnC,mEAAmE;oBACnE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;oBACpC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;oBACrC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;oBAC/B,aAAa,EAAE,CAAC;gBACjB,CAAC;YACF,CAAC,CAAC,CAAC;YAEH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAA4B,EAAE,EAAE;gBACpD,OAAO,CAAC,KAAK,CAAC,kBAAkB,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;gBACpD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC7B,aAAa,EAAE,CAAC;gBACjB,CAAC;YACF,CAAC,CAAC,CAAC;YAEH,eAAe,EAAE,CAAC;YAClB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,KAA8B,CAAC;YAC3C,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC3B,aAAa,EAAE,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACP,OAAO,CAAC,KAAK,CAAC,mBAAmB,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;YACtD,CAAC;QACF,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,QAAgB;QAChD,IAAI,CAAC;YACJ,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,+CAA+C;YAC/C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,QAAgB;QAC9C,IAAI,CAAC;YACJ,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAE3D,IAAI,KAAK,CAAC,IAAI,IAAI,YAAY,EAAE,CAAC;gBAChC,sDAAsD;gBACtD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;gBACpC,OAAO;YACR,CAAC;YAED,4BAA4B;YAC5B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC;YACvD,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAC1D,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YAErB,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC;YAEpD,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;gBACnC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAClC,CAAC;YAED,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,iBAAiB,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;QACpD,CAAC;IACF,CAAC;IAEO,eAAe,CAAC,OAAe;QACtC,MAAM,UAAU,GAAe,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,YAAY,GAAoB,IAAI,CAAC;QAEzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAE3B,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,WAAW,EAAE,CAAC;gBACjB,0BAA0B;gBAC1B,IAAI,YAAY,EAAE,CAAC;oBAClB,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC/B,CAAC;gBACD,YAAY,GAAG,WAAW,CAAC;YAC5B,CAAC;iBAAM,IAAI,YAAY,EAAE,CAAC;gBACzB,kDAAkD;gBAClD,YAAY,CAAC,OAAO,IAAI,IAAI,GAAG,IAAI,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACP,0CAA0C;gBAC1C,UAAU,CAAC,IAAI,CAAC;oBACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACnC,KAAK,EAAE,MAAM;oBACb,KAAK,EAAE,KAAK;oBACZ,OAAO,EAAE,IAAI;iBACb,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;QAED,IAAI,YAAY,EAAE,CAAC;YAClB,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/B,CAAC;QAED,OAAO,UAAU,CAAC;IACnB,CAAC;IAEO,eAAe,CAAC,IAAY;QACnC,2FAA2F;QAC3F,MAAM,QAAQ,GACb,uFAAuF,CAAC;QACzF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAEnC,IAAI,KAAK,EAAE,CAAC;YACX,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;YACnD,OAAO;gBACN,SAAS;gBACT,KAAK;gBACL,KAAK,EAAE,KAAK,IAAI,SAAS;gBACzB,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;aACvB,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,iBAAiB,CAAC,QAAkB;QAC3C,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;YACrC,IAAI,CAAC;gBACJ,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YAClD,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,QAAqB;QAC9B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB,GAAG;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC;QAE/D,IAAI,CAAC;YACJ,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACzD,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;YACrD,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,CAAC,KAAK,CAAC,0BAA0B,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3D,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC;IAEO,kBAAkB,CAAC,QAAgB,EAAE,WAAmB;QAC/D,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAChD,OAAO,QAAQ,IAAI,WAAW,CAAC;IAChC,CAAC;IAED,OAAO;QACN,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC9C,OAAO,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;YAC/C,YAAY,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;CACD;AAED,qBAAqB;AACrB,IAAI,UAAU,GAAsB,IAAI,CAAC;AAEzC,MAAM,UAAU,aAAa;IAC5B,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,UAAU,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAChC,IAAI,UAAU,EAAE,CAAC;QAChB,UAAU,CAAC,OAAO,EAAE,CAAC;QACrB,UAAU,GAAG,IAAI,CAAC;IACnB,CAAC;AACF,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function omitUndefined<T extends Record<string, unknown>>(obj: T): Partial<T>;
@@ -0,0 +1,4 @@
1
+ export function omitUndefined(obj) {
2
+ return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
3
+ }
4
+ //# sourceMappingURL=object.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object.js","sourceRoot":"","sources":["../../src/utils/object.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAC5B,GAAM;IAEN,OAAO,MAAM,CAAC,WAAW,CACxB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAChD,CAAC;AACjB,CAAC"}