···1import { html } from 'hono/html';
2import { Child } from 'hono/jsx';
3import { APP_NAME } from "../siteinfo";
4-import { PreloadRules } from '../types';
5import { mainScriptStr } from '../utils/appScripts';
6import { PreloadDependencyTags } from './helpers/includesTags';
7import MetaTags from './helpers/metaTags';
···1import { html } from 'hono/html';
2import { Child } from 'hono/jsx';
3import { APP_NAME } from "../siteinfo";
4+import { PreloadRules } from "../types/site";
5import { mainScriptStr } from '../utils/appScripts';
6import { PreloadDependencyTags } from './helpers/includesTags';
7import MetaTags from './helpers/metaTags';
+1-1
src/layout/makePost.tsx
···10 R2_FILE_SIZE_LIMIT_IN_MB
11} from "../limits";
12import { APP_NAME } from "../siteinfo";
13-import { PreloadRules } from "../types";
14import { ConstScriptPreload } from "../utils/constScriptGen";
15import { IncludeDependencyTags } from "./helpers/includesTags";
16import { ContentLabelOptions } from "./options/contentLabelOptions";
···10 R2_FILE_SIZE_LIMIT_IN_MB
11} from "../limits";
12import { APP_NAME } from "../siteinfo";
13+import { PreloadRules } from "../types/site";
14import { ConstScriptPreload } from "../utils/constScriptGen";
15import { IncludeDependencyTags } from "./helpers/includesTags";
16import { ContentLabelOptions } from "./options/contentLabelOptions";
+1-1
src/layout/passwordFields.tsx
···1import { html } from "hono/html";
2import { BSKY_MAX_APP_PASSWORD_LENGTH, MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits";
3-import { PWAutoCompleteSettings } from "../types";
45type PasswordFieldSettings = {
6 required?: boolean
···1import { html } from "hono/html";
2import { BSKY_MAX_APP_PASSWORD_LENGTH, MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits";
3+import { PWAutoCompleteSettings } from "../types/site";
45type PasswordFieldSettings = {
6 required?: boolean
+1-1
src/layout/post.tsx
···1import { html } from "hono/html";
02import { MAX_POSTED_LENGTH } from "../limits";
3-import { Post } from "../types";
4import { PostDataFooter, PostDataHeader } from "./posts/wrappers";
56type PostContentProps = {
···1import { html } from "hono/html";
2+import { Post } from "../classes/post";
3import { MAX_POSTED_LENGTH } from "../limits";
04import { PostDataFooter, PostDataHeader } from "./posts/wrappers";
56type PostContentProps = {
+1-1
src/layout/postList.tsx
···1import { Context } from "hono";
2import isEmpty from "just-is-empty";
3-import { Post } from "../types";
4import { getPostsForUser } from "../utils/dbQuery";
5import { PostHTML } from "./post";
6
···1import { Context } from "hono";
2import isEmpty from "just-is-empty";
3+import { Post } from "../classes/post";
4import { getPostsForUser } from "../utils/dbQuery";
5import { PostHTML } from "./post";
6
+1-1
src/layout/posts/repostData.tsx
···1import { raw } from "hono/html";
2import isEmpty from "just-is-empty";
3-import { RepostInfo } from "../../types";
45type RepostIconProps = {
6 isRepost?: boolean;
···1import { raw } from "hono/html";
2import isEmpty from "just-is-empty";
3+import { RepostInfo } from "../../classes/repost";
45type RepostIconProps = {
6 isRepost?: boolean;
+1-1
src/layout/posts/wrappers.tsx
···1import { raw } from "hono/html";
2import isEmpty from "just-is-empty";
3-import { Post } from "../../types";
4import { AddPostToThreadButton, DeletePostButton, EditPostButton } from "./buttons";
5import { RepostCountElement, RepostIcon } from "./repostData";
6
···1import { raw } from "hono/html";
2import isEmpty from "just-is-empty";
3+import { Post } from "../../classes/post";
4import { AddPostToThreadButton, DeletePostButton, EditPostButton } from "./buttons";
5import { RepostCountElement, RepostIcon } from "./repostData";
6
+1-1
src/layout/settings.tsx
···1import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits";
2import { APP_NAME } from "../siteinfo";
3-import { PWAutoCompleteSettings } from "../types";
4import { settingsScriptStr } from "../utils/appScripts";
5import { BSkyAppPasswordField, DashboardPasswordField } from "./passwordFields";
6import { UsernameField } from "./usernameField";
···1import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits";
2import { APP_NAME } from "../siteinfo";
3+import { PWAutoCompleteSettings } from "../types/site";
4import { settingsScriptStr } from "../utils/appScripts";
5import { BSkyAppPasswordField, DashboardPasswordField } from "./passwordFields";
6import { UsernameField } from "./usernameField";
+3-3
src/pages/dashboard.tsx
···2import { AltTextDialog } from "../layout/altTextModal";
3import FooterCopyright from "../layout/helpers/footer";
4import { IncludeDependencyTags } from "../layout/helpers/includesTags";
05import { BaseLayout } from "../layout/main";
6import { PostCreation, PreloadPostCreation } from "../layout/makePost";
7import { MakeRetweet } from "../layout/makeRetweet";
···9import { Settings, SettingsButton } from "../layout/settings";
10import { ViolationNoticeBar } from "../layout/violationsBar";
11import { APP_NAME, SHOW_SUPPORT_PROGRESS_BAR } from "../siteinfo";
12-import { PreloadRules } from "../types";
13import {
14 dashboardScriptStr,
15 settingsScriptStr
16} from "../utils/appScripts";
17-import { LogoImage } from "../layout/helpers/logo";
1819-export default function Dashboard(props:any) {
20 const ctx: Context = props.c;
21 // 3rd party dependencies
22 const defaultDashboardPreloads: PreloadRules[] = [
···2import { AltTextDialog } from "../layout/altTextModal";
3import FooterCopyright from "../layout/helpers/footer";
4import { IncludeDependencyTags } from "../layout/helpers/includesTags";
5+import { LogoImage } from "../layout/helpers/logo";
6import { BaseLayout } from "../layout/main";
7import { PostCreation, PreloadPostCreation } from "../layout/makePost";
8import { MakeRetweet } from "../layout/makeRetweet";
···10import { Settings, SettingsButton } from "../layout/settings";
11import { ViolationNoticeBar } from "../layout/violationsBar";
12import { APP_NAME, SHOW_SUPPORT_PROGRESS_BAR } from "../siteinfo";
13+import { PreloadRules } from "../types/site";
14import {
15 dashboardScriptStr,
16 settingsScriptStr
17} from "../utils/appScripts";
01819+export default function Dashboard(props: any) {
20 const ctx: Context = props.c;
21 // 3rd party dependencies
22 const defaultDashboardPreloads: PreloadRules[] = [
+1-1
src/pages/login.tsx
···3import { BaseLayout } from "../layout/main";
4import { DashboardPasswordField } from "../layout/passwordFields";
5import { UsernameField } from "../layout/usernameField";
6-import { PWAutoCompleteSettings } from "../types";
78export default function Login() {
9 const links = [{title: "Sign Up", url: "/signup"}, {title: "Forgot Password", url: "/forgot"}];
···3import { BaseLayout } from "../layout/main";
4import { DashboardPasswordField } from "../layout/passwordFields";
5import { UsernameField } from "../layout/usernameField";
6+import { PWAutoCompleteSettings } from "../types/site";
78export default function Login() {
9 const links = [{title: "Sign Up", url: "/signup"}, {title: "Forgot Password", url: "/forgot"}];
+1-1
src/pages/signup.tsx
···7import { BSkyAppPasswordField, DashboardPasswordField } from "../layout/passwordFields";
8import { UsernameField } from "../layout/usernameField";
9import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits";
10-import { PWAutoCompleteSettings } from "../types";
11import { getInviteThread, isUsingInviteKeys } from "../utils/inviteKeys";
1213export default function Signup(props:any) {
···7import { BSkyAppPasswordField, DashboardPasswordField } from "../layout/passwordFields";
8import { UsernameField } from "../layout/usernameField";
9import { MAX_DASHBOARD_PASS, MIN_DASHBOARD_PASS } from "../limits";
10+import { PWAutoCompleteSettings } from "../types/site";
11import { getInviteThread, isUsingInviteKeys } from "../utils/inviteKeys";
1213export default function Signup(props:any) {
+7
src/types.d.ts
···0000000
···1+// Easy type declares for typescript type checking
2+// not used otherwise
3+declare type LooseObj = {
4+ [key: string]: any;
5+};
6+declare type BatchQuery = [BatchItem<'sqlite'>, ...BatchItem<'sqlite'>[]];
7+declare type AllContext = Context | ScheduledContext;
···1+import { EmbedDataType } from "./posts";
2+3+export type BskyEmbedWrapper = {
4+ type: EmbedDataType;
5+ data?: any;
6+};
7+8+export type BskyRecordWrapper = {
9+ cid?: string;
10+ uri?: string;
11+};
+11
src/types/data.ts
···00000000000
···1+// Used for the pruning and database operations
2+export type GetAllPostedBatch = {
3+ id: string;
4+ uri: string|null;
5+};
6+7+export type R2BucketObject = {
8+ name: string;
9+ user: string|null;
10+ date: Date
11+};
···1+// Used for jsx rendering
2+export type PreloadRules = {
3+ type: string;
4+ href: string;
5+};
6+7+export enum PWAutoCompleteSettings {
8+ Off,
9+ NewPass,
10+ CurrentPass
11+};
+5-4
src/utils/bskyAgents.ts
···4//
5// Also just handles general login.
6import AtpAgent from "@atproto/api";
7-import {
8- AccountStatus, AgentConfigSettings,
9- AllContext, LooseObj, Post, Repost, TaskType
10-} from "../types";
011import { getBskyUserPassForId } from "./db/userinfo";
12import { createViolationForUser } from "./db/violations";
13
···4//
5// Also just handles general login.
6import AtpAgent from "@atproto/api";
7+import { Post } from "../classes/post";
8+import { Repost } from "../classes/repost";
9+import { AccountStatus } from "../types/accounts";
10+import { TaskType } from "../types/queue";
11+import { AgentConfigSettings } from "../types/settings";
12import { getBskyUserPassForId } from "./db/userinfo";
13import { createViolationForUser } from "./db/violations";
14
+10-8
src/utils/bskyApi.ts
···4import has from 'just-has';
5import isEmpty from "just-is-empty";
6import truncate from "just-truncate";
007import { BSKY_IMG_SIZE_LIMIT, MAX_ALT_TEXT, MAX_EMBEDS_PER_POST } from '../limits';
8-import {
9- AccountStatus,
10- AllContext,
11- BskyEmbedWrapper, BskyRecordWrapper, EmbedData, EmbedDataType,
12- LooseObj, Post, PostLabel,
13- PostRecordResponse, PostStatus, Repost
14-} from '../types';
15import { atpRecordURI } from '../validation/regexCases';
16import { makeAgentForUser } from './bskyAgents';
17-import { bulkUpdatePostedData, getChildPostsOfThread, isPostAlreadyPosted, setPostNowOffForPost } from './db/data';
00018import { getUsernameForUserId } from './db/userinfo';
19import { createViolationForUser } from './db/violations';
20import { deleteEmbedsFromR2 } from './r2Query';
···4import has from 'just-has';
5import isEmpty from "just-is-empty";
6import truncate from "just-truncate";
7+import { Post } from "../classes/post";
8+import { Repost } from "../classes/repost";
9import { BSKY_IMG_SIZE_LIMIT, MAX_ALT_TEXT, MAX_EMBEDS_PER_POST } from '../limits';
10+import { AccountStatus } from "../types/accounts";
11+import { BskyEmbedWrapper, BskyRecordWrapper } from "../types/bsky";
12+import { EmbedData, EmbedDataType, PostLabel } from "../types/posts";
13+import { PostRecordResponse, PostStatus } from "../types/responses";
00014import { atpRecordURI } from '../validation/regexCases';
15import { makeAgentForUser } from './bskyAgents';
16+import {
17+ bulkUpdatePostedData, getChildPostsOfThread,
18+ isPostAlreadyPosted, setPostNowOffForPost
19+} from './db/data';
20import { getUsernameForUserId } from './db/userinfo';
21import { createViolationForUser } from './db/violations';
22import { deleteEmbedsFromR2 } from './r2Query';
+2-1
src/utils/bskyMsg.ts
···1import { AtpAgent, RichText } from '@atproto/api';
2-import { AccountStatus, Bindings } from '../types';
03import { loginToBsky } from './bskyAgents';
45const chatHeaders = {headers: {
···1import { AtpAgent, RichText } from '@atproto/api';
2+import { AccountStatus } from "../types/accounts";
3+import { Bindings } from '../types/settings';
4import { loginToBsky } from './bskyAgents';
56const chatHeaders = {headers: {
-1
src/utils/bskyPrune.ts
···1import isEmpty from 'just-is-empty';
2import split from 'just-split';
3-import { AllContext } from '../types';
4import { getPostRecords } from './bskyApi';
5import { getAllPostedPosts, getAllPostedPostsOfUser } from './db/data';
6
···1import isEmpty from 'just-is-empty';
2import split from 'just-split';
03import { getPostRecords } from './bskyApi';
4import { getAllPostedPosts, getAllPostedPostsOfUser } from './db/data';
5
+1-1
src/utils/constScriptGen.ts
···12 MAX_THUMBNAIL_SIZE,
13 R2_FILE_SIZE_LIMIT
14} from "../limits";
15-import { PreloadRules } from "../types";
16import { postRecordURI } from "../validation/regexCases";
1718const CONST_SCRIPT_VERSION: number = 8;
···12 MAX_THUMBNAIL_SIZE,
13 R2_FILE_SIZE_LIMIT
14} from "../limits";
15+import { PreloadRules } from "../types/site";
16import { postRecordURI } from "../validation/regexCases";
1718const CONST_SCRIPT_VERSION: number = 8;
···3import flatten from "just-flatten-it";
4import isEmpty from "just-is-empty";
5import { bannedUsers, violations } from "../../db/enforcement.schema";
6-import { AccountStatus, AllContext, LooseObj, Violation } from "../../types";
7import { lookupBskyHandle } from "../bskyApi";
8import { getUsernameForUserId } from "./userinfo";
9
···3import flatten from "just-flatten-it";
4import isEmpty from "just-is-empty";
5import { bannedUsers, violations } from "../../db/enforcement.schema";
6+import { AccountStatus, Violation } from "../../types/accounts";
7import { lookupBskyHandle } from "../bskyApi";
8import { getUsernameForUserId } from "./userinfo";
9
+12-17
src/utils/dbQuery.ts
···5import has from "just-has";
6import isEmpty from "just-is-empty";
7import { v4 as uuidv4, validate as uuidValid } from 'uuid';
008import { mediaFiles, posts, repostCounts, reposts } from "../db/app.schema";
9import { accounts, users } from "../db/auth.schema";
10import { MAX_POSTS_PER_THREAD, MAX_REPOST_POSTS, MAX_REPOST_RULES_PER_POST } from "../limits";
11import { APP_NAME } from "../siteinfo";
12-import {
13- AccountStatus,
14- AllContext,
15- BatchQuery,
16- CreateObjectResponse, CreatePostQueryResponse,
17- DeleteResponse,
18- EmbedDataType,
19- Post, PostLabel,
20- RepostInfo
21-} from "../types";
22import { PostSchema } from "../validation/postSchema";
23import { RepostSchema } from "../validation/repostSchema";
24import { getChildPostsOfThread, getPostByCID, getPostThreadCount, updatePostForGivenUser } from "./db/data";
25import { getViolationsForUser, removeViolation, removeViolations, userHasViolations } from "./db/violations";
26-import { createPostObject, createRepostInfo, floorGivenTime } from "./helpers";
27import { deleteEmbedsFromR2 } from "./r2Query";
2829export const getPostsForUser = async (c: AllContext): Promise<Post[]|null> => {
···42 if (isEmpty(results))
43 return null;
4445- return results.map((itm) => createPostObject(itm));
46 }
47 } catch(err) {
48 console.error(`Failed to get posts for user, session could not be fetched ${err}`);
···255 // Create repost metadata
256 const scheduleGUID = (!isThreadedPost) ? uuidv4() : undefined;
257 const repostInfo = (!isThreadedPost) ?
258- createRepostInfo(scheduleGUID!, scheduleDate, false, repostData) : undefined;
259260 // Create the posts
261 const postUUID = uuidv4();
···358 if (violationData.tosViolation) {
359 return {ok: false, msg: `This account is unable to use ${APP_NAME} services at this time`};
360 } else if (violationData.userPassInvalid) {
361- return {ok: false, msg: "The BSky account credentials is invalid, please update these in the settings"};
362 }
363 }
364 let postUUID;
365 let dbOperations: BatchItem<"sqlite">[] = [];
366 const scheduleGUID = uuidv4();
367- const repostInfo: RepostInfo = createRepostInfo(scheduleGUID, scheduleDate, true, repostData);
368369 // Check to see if the post already exists
370 // (check also against the userId here as well to avoid cross account data collisions)
···470 .limit(1).all();
471472 if (!isEmpty(result))
473- return createPostObject(result[0]);
474 return null;
475};
476···495 .limit(1).all();
496497 if (!isEmpty(result))
498- return createPostObject(result[0]);
499 return null;
500};
···5import has from "just-has";
6import isEmpty from "just-is-empty";
7import { v4 as uuidv4, validate as uuidValid } from 'uuid';
8+import { Post } from "../classes/post";
9+import { RepostInfo } from "../classes/repost";
10import { mediaFiles, posts, repostCounts, reposts } from "../db/app.schema";
11import { accounts, users } from "../db/auth.schema";
12import { MAX_POSTS_PER_THREAD, MAX_REPOST_POSTS, MAX_REPOST_RULES_PER_POST } from "../limits";
13import { APP_NAME } from "../siteinfo";
14+import { AccountStatus } from "../types/accounts";
15+import { EmbedDataType, PostLabel } from "../types/posts";
16+import { CreateObjectResponse, CreatePostQueryResponse, DeleteResponse } from "../types/responses";
000000017import { PostSchema } from "../validation/postSchema";
18import { RepostSchema } from "../validation/repostSchema";
19import { getChildPostsOfThread, getPostByCID, getPostThreadCount, updatePostForGivenUser } from "./db/data";
20import { getViolationsForUser, removeViolation, removeViolations, userHasViolations } from "./db/violations";
21+import { floorGivenTime } from "./helpers";
22import { deleteEmbedsFromR2 } from "./r2Query";
2324export const getPostsForUser = async (c: AllContext): Promise<Post[]|null> => {
···37 if (isEmpty(results))
38 return null;
3940+ return results.map((itm) => new Post(itm));
41 }
42 } catch(err) {
43 console.error(`Failed to get posts for user, session could not be fetched ${err}`);
···250 // Create repost metadata
251 const scheduleGUID = (!isThreadedPost) ? uuidv4() : undefined;
252 const repostInfo = (!isThreadedPost) ?
253+ new RepostInfo(scheduleGUID!, scheduleDate, false, repostData) : undefined;
254255 // Create the posts
256 const postUUID = uuidv4();
···353 if (violationData.tosViolation) {
354 return {ok: false, msg: `This account is unable to use ${APP_NAME} services at this time`};
355 } else if (violationData.userPassInvalid) {
356+ return {ok: false, msg: "The BSky account credentials is invalid, please update th/ese in the settings"};
357 }
358 }
359 let postUUID;
360 let dbOperations: BatchItem<"sqlite">[] = [];
361 const scheduleGUID = uuidv4();
362+ const repostInfo: RepostInfo = new RepostInfo(scheduleGUID, scheduleDate, true, repostData);
363364 // Check to see if the post already exists
365 // (check also against the userId here as well to avoid cross account data collisions)
···465 .limit(1).all();
466467 if (!isEmpty(result))
468+ return new Post(result[0]);
469 return null;
470};
471···490 .limit(1).all();
491492 if (!isEmpty(result))
493+ return new Post(result[0]);
494 return null;
495};
-94
src/utils/helpers.ts
···1import { startOfHour, subDays } from "date-fns";
2import { Context } from "hono";
3-import has from "just-has";
4-import isEmpty from "just-is-empty";
5-import { BskyAPILoginCreds, Post, Repost, RepostInfo } from "../types";
6-7-export function createPostObject(data: any) {
8- const postData: Post = (new Object() as Post);
9- postData.user = data.userId;
10- postData.postid = data.uuid;
11- postData.embeds = data.embedContent;
12- postData.label = data.contentLabel;
13- postData.text = data.content;
14- postData.postNow = data.postNow;
15- postData.threadOrder = data.threadOrder;
16-17- if (has(data, "repostCount"))
18- postData.repostCount = data.repostCount;
19-20- if (data.scheduledDate)
21- postData.scheduledDate = data.scheduledDate;
22-23- if (data.repostInfo)
24- postData.repostInfo = data.repostInfo;
25-26- if (data.rootPost)
27- postData.rootPost = data.rootPost;
28-29- if (data.parentPost) {
30- postData.parentPost = data.parentPost;
31- postData.isChildPost = true;
32- } else {
33- postData.isChildPost = false;
34- }
35-36- if (data.threadOrder == 0)
37- postData.isThreadRoot = true;
38- else
39- postData.isThreadRoot = false;
40-41- // ATProto data
42- if (data.uri)
43- postData.uri = data.uri;
44- if (data.cid)
45- postData.cid = data.cid;
46-47- if (has(data, "isRepost"))
48- postData.isRepost = data.isRepost;
49-50- if (has(data, "posted"))
51- postData.posted = data.posted;
52-53- // if a cid flag appears for the object and it's a thread root, then the post (if marked not posted) is posted.
54- if (postData.posted == false && !isEmpty(data.cid) && postData.isThreadRoot)
55- postData.posted = true;
56-57- return postData;
58-}
59-60-export function createRepostObject(data: any) {
61- const repostObj: Repost = (new Object() as Repost);
62- repostObj.postid = data.uuid;
63- repostObj.cid = data.cid;
64- repostObj.uri = data.uri;
65- repostObj.userId = data.userId;
66- if (data.scheduleGuid)
67- repostObj.scheduleGuid = data.scheduleGuid;
68- return repostObj;
69-}
70-71-export function createRepostInfo(id: string, time: Date, isRepost: boolean, repostData: any) {
72- const repostObj: RepostInfo = (new Object() as RepostInfo);
73- repostObj.time = time;
74- repostObj.guid = id;
75- if (has(repostData, "hours") && has(repostData, "times")) {
76- repostObj.hours = repostData.hours;
77- repostObj.count = repostData.times;
78- } else {
79- repostObj.count = (isRepost) ? 1 : 0;
80- repostObj.hours = 0;
81- }
82- return repostObj;
83-}
84-85-export function createLoginCredsObj(data: any) {
86- const loginCreds: BskyAPILoginCreds = (new Object() as BskyAPILoginCreds);
87- if (isEmpty(data)) {
88- loginCreds.password = loginCreds.username = loginCreds.pds = "";
89- } else {
90- loginCreds.pds = data.pds;
91- loginCreds.username = data.user;
92- loginCreds.password = data.pass;
93- }
94- loginCreds.valid = !isEmpty(data.user) && !isEmpty(data.pass);
95- return loginCreds;
96-}
9798export function floorCurrentTime() {
99 return startOfHour(new Date());
···1import { startOfHour, subDays } from "date-fns";
2import { Context } from "hono";
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034export function floorCurrentTime() {
5 return startOfHour(new Date());
+4-1
src/utils/queuePublisher.ts
···1import isEmpty from 'just-is-empty';
2import random from 'just-random';
3import get from 'just-safe-get';
4-import { AllContext, Bindings, Post, QueueTaskData, Repost, TaskType } from "../types";
00056const queueContentType = 'v8';
7
···1import isEmpty from 'just-is-empty';
2import random from 'just-random';
3import get from 'just-safe-get';
4+import { Post } from "../classes/post";
5+import { Repost } from "../classes/repost";
6+import { QueueTaskData, TaskType } from "../types/queue";
7+import { Bindings } from '../types/settings';
89const queueContentType = 'v8';
10
+2-1
src/utils/r2Query.ts
···15 R2_FILE_SIZE_LIMIT,
16 R2_FILE_SIZE_LIMIT_IN_MB
17} from "../limits";
18-import { AllContext, EmbedData, EmbedDataType, R2BucketObject } from '../types';
019import { addFileListing, deleteFileListings } from './db/file';
2021type FileMetaData = {
···15 R2_FILE_SIZE_LIMIT,
16 R2_FILE_SIZE_LIMIT_IN_MB
17} from "../limits";
18+import { R2BucketObject } from '../types/data';
19+import { EmbedData, EmbedDataType } from "../types/posts";
20import { addFileListing, deleteFileListings } from './db/file';
2122type FileMetaData = {
+7-2
src/utils/scheduler.ts
···1import AtpAgent from '@atproto/api';
2import isEmpty from 'just-is-empty';
3-import { AllContext, Post, Repost, TaskType } from '../types';
004import { AgentMap } from './bskyAgents';
5import { makePost, makeRepost } from './bskyApi';
6import { pruneBskyPosts } from './bskyPrune';
···10 setPostNowOffForPost
11} from './db/data';
12import { getAllAbandonedMedia } from './db/file';
13-import { enqueuePost, enqueueRepost, isQueueEnabled, isRepostQueueEnabled, shouldPostNowQueue, shouldPostThreadQueue } from './queuePublisher';
00014import { deleteFromR2 } from './r2Query';
1516export const handlePostTask = async(runtime: AllContext, postData: Post, agent: AtpAgent|null) => {
···1import AtpAgent from '@atproto/api';
2import isEmpty from 'just-is-empty';
3+import { Post } from "../classes/post";
4+import { Repost } from "../classes/repost";
5+import { TaskType } from "../types/queue";
6import { AgentMap } from './bskyAgents';
7import { makePost, makeRepost } from './bskyApi';
8import { pruneBskyPosts } from './bskyPrune';
···12 setPostNowOffForPost
13} from './db/data';
14import { getAllAbandonedMedia } from './db/file';
15+import {
16+ enqueuePost, enqueueRepost, isQueueEnabled, isRepostQueueEnabled,
17+ shouldPostNowQueue, shouldPostThreadQueue
18+} from './queuePublisher';
19import { deleteFromR2 } from './r2Query';
2021export const handlePostTask = async(runtime: AllContext, postData: Post, agent: AtpAgent|null) => {
+1-1
src/validation/embedSchema.ts
···1import isEmpty from "just-is-empty";
2import * as z from "zod/v4";
3import { BSKY_VIDEO_LENGTH_LIMIT } from "../limits";
4-import { EmbedDataType } from "../types";
5import { FileContentSchema } from "./mediaSchema";
6import { atpRecordURI } from "./regexCases";
7import { AltTextSchema } from "./sharedValidations";
···1import isEmpty from "just-is-empty";
2import * as z from "zod/v4";
3import { BSKY_VIDEO_LENGTH_LIMIT } from "../limits";
4+import { EmbedDataType } from "../types/posts";
5import { FileContentSchema } from "./mediaSchema";
6import { atpRecordURI } from "./regexCases";
7import { AltTextSchema } from "./sharedValidations";
+9-3
src/validation/postSchema.ts
···1import * as z from "zod/v4";
2-import { MAX_LENGTH, MAX_REPOST_INTERVAL_LIMIT, MAX_REPOST_IN_HOURS, MIN_LENGTH } from "../limits";
3-import { EmbedDataType, PostLabel } from "../types";
4-import { ImageEmbedSchema, LinkEmbedSchema, PostRecordSchema, VideoEmbedSchema } from "./embedSchema";
0000005import { FileContentSchema } from "./mediaSchema";
6import { AltTextSchema } from "./sharedValidations";
7
···1import * as z from "zod/v4";
2+import {
3+ MAX_LENGTH, MAX_REPOST_INTERVAL_LIMIT,
4+ MAX_REPOST_IN_HOURS, MIN_LENGTH
5+} from "../limits";
6+import { EmbedDataType, PostLabel } from "../types/posts";
7+import {
8+ ImageEmbedSchema, LinkEmbedSchema,
9+ PostRecordSchema, VideoEmbedSchema
10+} from "./embedSchema";
11import { FileContentSchema } from "./mediaSchema";
12import { AltTextSchema } from "./sharedValidations";
13