···128128 }
129129 }
130130 return response;
131131- } else if (url.pathname === "/add-account" || url.pathname === "/add-self") {
131131+ } else if (url.pathname === "/add-account") {
132132+ if (env.RATELIMIT === "true") {
133133+ const ipAddress = request.headers.get("cf-connecting-ip") || "";
134134+ const { success } = await env.BSKY_LABEL_LIMITER.limit({ key: ipAddress });
135135+ if (!success) {
136136+ return new Response("<b>ERROR</b>: You are adding too quickly, please slow down", {status: 429});
137137+ }
138138+ }
132139 // drop non post requests
133140 if (request.method !== "POST") {
134141 return new Response("<b>ERROR</b>: You cannot submit data this way", {status: 405});
+751-2
worker-configuration.d.ts
···11/* eslint-disable */
22-// Generated by Wrangler by running `wrangler types` (hash: a3a025b6baf0beefc4d917e42f0f0b05)
33-// Runtime types generated with workerd@1.20260312.1 2024-12-18 nodejs_compat
22+// Generated by Wrangler by running `wrangler types` (hash: 4fbff60ff6193980e25186a76790a338)
33+// Runtime types generated with workerd@1.20260317.1 2024-12-18 nodejs_compat
44declare namespace Cloudflare {
55 interface GlobalProps {
66 mainModule: typeof import("./src/index");
77 }
88 interface Env {
99 DB: D1Database;
1010+ BSKY_LABEL_LIMITER: RateLimit;
1011 ASSETS: Fetcher;
1112 COUNT_CACHE_HOUR: "4";
1313+ RATELIMIT: "true";
1214 SITE_TITLE: "Simple BSky Labeler";
1315 SITE_DESCRIPTION: "Allow people to obtain a bsky label you provide";
1416 SITE_SHORTNAME: "SBL";
···32933295}
32943296interface WorkerLoader {
32953297 get(name: string | null, getCode: () => WorkerLoaderWorkerCode | Promise<WorkerLoaderWorkerCode>): WorkerStub;
32983298+ load(code: WorkerLoaderWorkerCode): WorkerStub;
32963299}
32973300interface WorkerLoaderModule {
32983301 js?: string;
···1068610689declare module "cloudflare:sockets" {
1068710690 function _connect(address: string | SocketAddress, options?: SocketOptions): Socket;
1068810691 export { _connect as connect };
1069210692+}
1069310693+/**
1069410694+ * Binding entrypoint for Cloudflare Stream.
1069510695+ *
1069610696+ * Usage:
1069710697+ * - Binding-level operations:
1069810698+ * `await env.STREAM.videos.upload`
1069910699+ * `await env.STREAM.videos.createDirectUpload`
1070010700+ * `await env.STREAM.videos.*`
1070110701+ * `await env.STREAM.watermarks.*`
1070210702+ * - Per-video operations:
1070310703+ * `await env.STREAM.video(id).downloads.*`
1070410704+ * `await env.STREAM.video(id).captions.*`
1070510705+ *
1070610706+ * Example usage:
1070710707+ * ```ts
1070810708+ * await env.STREAM.video(id).downloads.generate();
1070910709+ *
1071010710+ * const video = env.STREAM.video(id)
1071110711+ * const captions = video.captions.list();
1071210712+ * const videoDetails = video.details()
1071310713+ * ```
1071410714+ */
1071510715+interface StreamBinding {
1071610716+ /**
1071710717+ * Returns a handle scoped to a single video for per-video operations.
1071810718+ * @param id The unique identifier for the video.
1071910719+ * @returns A handle for per-video operations.
1072010720+ */
1072110721+ video(id: string): StreamVideoHandle;
1072210722+ /**
1072310723+ * Uploads a new video from a File.
1072410724+ * @param file The video file to upload.
1072510725+ * @returns The uploaded video details.
1072610726+ * @throws {BadRequestError} if the upload parameter is invalid
1072710727+ * @throws {QuotaReachedError} if the account storage capacity is exceeded
1072810728+ * @throws {MaxFileSizeError} if the file size is too large
1072910729+ * @throws {RateLimitedError} if the server received too many requests
1073010730+ * @throws {InternalError} if an unexpected error occurs
1073110731+ */
1073210732+ upload(file: File): Promise<StreamVideo>;
1073310733+ /**
1073410734+ * Uploads a new video from a provided URL.
1073510735+ * @param url The URL to upload from.
1073610736+ * @param params Optional upload parameters.
1073710737+ * @returns The uploaded video details.
1073810738+ * @throws {BadRequestError} if the upload parameter is invalid or the URL is invalid
1073910739+ * @throws {QuotaReachedError} if the account storage capacity is exceeded
1074010740+ * @throws {MaxFileSizeError} if the file size is too large
1074110741+ * @throws {RateLimitedError} if the server received too many requests
1074210742+ * @throws {AlreadyUploadedError} if a video was already uploaded to this URL
1074310743+ * @throws {InternalError} if an unexpected error occurs
1074410744+ */
1074510745+ upload(url: string, params?: StreamUrlUploadParams): Promise<StreamVideo>;
1074610746+ /**
1074710747+ * Creates a direct upload that allows video uploads without an API key.
1074810748+ * @param params Parameters for the direct upload
1074910749+ * @returns The direct upload details.
1075010750+ * @throws {BadRequestError} if the parameters are invalid
1075110751+ * @throws {RateLimitedError} if the server received too many requests
1075210752+ * @throws {InternalError} if an unexpected error occurs
1075310753+ */
1075410754+ createDirectUpload(params: StreamDirectUploadCreateParams): Promise<StreamDirectUpload>;
1075510755+ videos: StreamVideos;
1075610756+ watermarks: StreamWatermarks;
1075710757+}
1075810758+/**
1075910759+ * Handle for operations scoped to a single Stream video.
1076010760+ */
1076110761+interface StreamVideoHandle {
1076210762+ /**
1076310763+ * The unique identifier for the video.
1076410764+ */
1076510765+ id: string;
1076610766+ /**
1076710767+ * Get a full videos details
1076810768+ * @returns The full video details.
1076910769+ * @throws {NotFoundError} if the video is not found
1077010770+ * @throws {InternalError} if an unexpected error occurs
1077110771+ */
1077210772+ details(): Promise<StreamVideo>;
1077310773+ /**
1077410774+ * Update details for a single video.
1077510775+ * @param params The fields to update for the video.
1077610776+ * @returns The updated video details.
1077710777+ * @throws {NotFoundError} if the video is not found
1077810778+ * @throws {BadRequestError} if the parameters are invalid
1077910779+ * @throws {InternalError} if an unexpected error occurs
1078010780+ */
1078110781+ update(params: StreamUpdateVideoParams): Promise<StreamVideo>;
1078210782+ /**
1078310783+ * Deletes a video and its copies from Cloudflare Stream.
1078410784+ * @returns A promise that resolves when deletion completes.
1078510785+ * @throws {NotFoundError} if the video is not found
1078610786+ * @throws {InternalError} if an unexpected error occurs
1078710787+ */
1078810788+ delete(): Promise<void>;
1078910789+ /**
1079010790+ * Creates a signed URL token for a video.
1079110791+ * @returns The signed token that was created.
1079210792+ * @throws {InternalError} if the signing key cannot be retrieved or the token cannot be signed
1079310793+ */
1079410794+ generateToken(): Promise<string>;
1079510795+ downloads: StreamScopedDownloads;
1079610796+ captions: StreamScopedCaptions;
1079710797+}
1079810798+interface StreamVideo {
1079910799+ /**
1080010800+ * The unique identifier for the video.
1080110801+ */
1080210802+ id: string;
1080310803+ /**
1080410804+ * A user-defined identifier for the media creator.
1080510805+ */
1080610806+ creator: string | null;
1080710807+ /**
1080810808+ * The thumbnail URL for the video.
1080910809+ */
1081010810+ thumbnail: string;
1081110811+ /**
1081210812+ * The thumbnail timestamp percentage.
1081310813+ */
1081410814+ thumbnailTimestampPct: number;
1081510815+ /**
1081610816+ * Indicates whether the video is ready to stream.
1081710817+ */
1081810818+ readyToStream: boolean;
1081910819+ /**
1082010820+ * The date and time the video became ready to stream.
1082110821+ */
1082210822+ readyToStreamAt: string | null;
1082310823+ /**
1082410824+ * Processing status information.
1082510825+ */
1082610826+ status: StreamVideoStatus;
1082710827+ /**
1082810828+ * A user modifiable key-value store.
1082910829+ */
1083010830+ meta: Record<string, string>;
1083110831+ /**
1083210832+ * The date and time the video was created.
1083310833+ */
1083410834+ created: string;
1083510835+ /**
1083610836+ * The date and time the video was last modified.
1083710837+ */
1083810838+ modified: string;
1083910839+ /**
1084010840+ * The date and time at which the video will be deleted.
1084110841+ */
1084210842+ scheduledDeletion: string | null;
1084310843+ /**
1084410844+ * The size of the video in bytes.
1084510845+ */
1084610846+ size: number;
1084710847+ /**
1084810848+ * The preview URL for the video.
1084910849+ */
1085010850+ preview?: string;
1085110851+ /**
1085210852+ * Origins allowed to display the video.
1085310853+ */
1085410854+ allowedOrigins: Array<string>;
1085510855+ /**
1085610856+ * Indicates whether signed URLs are required.
1085710857+ */
1085810858+ requireSignedURLs: boolean | null;
1085910859+ /**
1086010860+ * The date and time the video was uploaded.
1086110861+ */
1086210862+ uploaded: string | null;
1086310863+ /**
1086410864+ * The date and time when the upload URL expires.
1086510865+ */
1086610866+ uploadExpiry: string | null;
1086710867+ /**
1086810868+ * The maximum size in bytes for direct uploads.
1086910869+ */
1087010870+ maxSizeBytes: number | null;
1087110871+ /**
1087210872+ * The maximum duration in seconds for direct uploads.
1087310873+ */
1087410874+ maxDurationSeconds: number | null;
1087510875+ /**
1087610876+ * The video duration in seconds. -1 indicates unknown.
1087710877+ */
1087810878+ duration: number;
1087910879+ /**
1088010880+ * Input metadata for the original upload.
1088110881+ */
1088210882+ input: StreamVideoInput;
1088310883+ /**
1088410884+ * Playback URLs for the video.
1088510885+ */
1088610886+ hlsPlaybackUrl: string;
1088710887+ dashPlaybackUrl: string;
1088810888+ /**
1088910889+ * The watermark applied to the video, if any.
1089010890+ */
1089110891+ watermark: StreamWatermark | null;
1089210892+ /**
1089310893+ * The live input id associated with the video, if any.
1089410894+ */
1089510895+ liveInputId?: string | null;
1089610896+ /**
1089710897+ * The source video id if this is a clip.
1089810898+ */
1089910899+ clippedFromId: string | null;
1090010900+ /**
1090110901+ * Public details associated with the video.
1090210902+ */
1090310903+ publicDetails: StreamPublicDetails | null;
1090410904+}
1090510905+type StreamVideoStatus = {
1090610906+ /**
1090710907+ * The current processing state.
1090810908+ */
1090910909+ state: string;
1091010910+ /**
1091110911+ * The current processing step.
1091210912+ */
1091310913+ step?: string;
1091410914+ /**
1091510915+ * The percent complete as a string.
1091610916+ */
1091710917+ pctComplete?: string;
1091810918+ /**
1091910919+ * An error reason code, if applicable.
1092010920+ */
1092110921+ errorReasonCode: string;
1092210922+ /**
1092310923+ * An error reason text, if applicable.
1092410924+ */
1092510925+ errorReasonText: string;
1092610926+};
1092710927+type StreamVideoInput = {
1092810928+ /**
1092910929+ * The input width in pixels.
1093010930+ */
1093110931+ width: number;
1093210932+ /**
1093310933+ * The input height in pixels.
1093410934+ */
1093510935+ height: number;
1093610936+};
1093710937+type StreamPublicDetails = {
1093810938+ /**
1093910939+ * The public title for the video.
1094010940+ */
1094110941+ title: string | null;
1094210942+ /**
1094310943+ * The public share link.
1094410944+ */
1094510945+ share_link: string | null;
1094610946+ /**
1094710947+ * The public channel link.
1094810948+ */
1094910949+ channel_link: string | null;
1095010950+ /**
1095110951+ * The public logo URL.
1095210952+ */
1095310953+ logo: string | null;
1095410954+};
1095510955+type StreamDirectUpload = {
1095610956+ /**
1095710957+ * The URL an unauthenticated upload can use for a single multipart request.
1095810958+ */
1095910959+ uploadURL: string;
1096010960+ /**
1096110961+ * A Cloudflare-generated unique identifier for a media item.
1096210962+ */
1096310963+ id: string;
1096410964+ /**
1096510965+ * The watermark profile applied to the upload.
1096610966+ */
1096710967+ watermark: StreamWatermark | null;
1096810968+ /**
1096910969+ * The scheduled deletion time, if any.
1097010970+ */
1097110971+ scheduledDeletion: string | null;
1097210972+};
1097310973+type StreamDirectUploadCreateParams = {
1097410974+ /**
1097510975+ * The maximum duration in seconds for a video upload.
1097610976+ */
1097710977+ maxDurationSeconds: number;
1097810978+ /**
1097910979+ * The date and time after upload when videos will not be accepted.
1098010980+ */
1098110981+ expiry?: string;
1098210982+ /**
1098310983+ * A user-defined identifier for the media creator.
1098410984+ */
1098510985+ creator?: string;
1098610986+ /**
1098710987+ * A user modifiable key-value store used to reference other systems of record for
1098810988+ * managing videos.
1098910989+ */
1099010990+ meta?: Record<string, string>;
1099110991+ /**
1099210992+ * Lists the origins allowed to display the video.
1099310993+ */
1099410994+ allowedOrigins?: Array<string>;
1099510995+ /**
1099610996+ * Indicates whether the video can be accessed using the id. When set to `true`,
1099710997+ * a signed token must be generated with a signing key to view the video.
1099810998+ */
1099910999+ requireSignedURLs?: boolean;
1100011000+ /**
1100111001+ * The thumbnail timestamp percentage.
1100211002+ */
1100311003+ thumbnailTimestampPct?: number;
1100411004+ /**
1100511005+ * The date and time at which the video will be deleted. Include `null` to remove
1100611006+ * a scheduled deletion.
1100711007+ */
1100811008+ scheduledDeletion?: string | null;
1100911009+ /**
1101011010+ * The watermark profile to apply.
1101111011+ */
1101211012+ watermark?: StreamDirectUploadWatermark;
1101311013+};
1101411014+type StreamDirectUploadWatermark = {
1101511015+ /**
1101611016+ * The unique identifier for the watermark profile.
1101711017+ */
1101811018+ id: string;
1101911019+};
1102011020+type StreamUrlUploadParams = {
1102111021+ /**
1102211022+ * Lists the origins allowed to display the video. Enter allowed origin
1102311023+ * domains in an array and use `*` for wildcard subdomains. Empty arrays allow the
1102411024+ * video to be viewed on any origin.
1102511025+ */
1102611026+ allowedOrigins?: Array<string>;
1102711027+ /**
1102811028+ * A user-defined identifier for the media creator.
1102911029+ */
1103011030+ creator?: string;
1103111031+ /**
1103211032+ * A user modifiable key-value store used to reference other systems of
1103311033+ * record for managing videos.
1103411034+ */
1103511035+ meta?: Record<string, string>;
1103611036+ /**
1103711037+ * Indicates whether the video can be a accessed using the id. When
1103811038+ * set to `true`, a signed token must be generated with a signing key to view the
1103911039+ * video.
1104011040+ */
1104111041+ requireSignedURLs?: boolean;
1104211042+ /**
1104311043+ * Indicates the date and time at which the video will be deleted. Omit
1104411044+ * the field to indicate no change, or include with a `null` value to remove an
1104511045+ * existing scheduled deletion. If specified, must be at least 30 days from upload
1104611046+ * time.
1104711047+ */
1104811048+ scheduledDeletion?: string | null;
1104911049+ /**
1105011050+ * The timestamp for a thumbnail image calculated as a percentage value
1105111051+ * of the video's duration. To convert from a second-wise timestamp to a
1105211052+ * percentage, divide the desired timestamp by the total duration of the video. If
1105311053+ * this value is not set, the default thumbnail image is taken from 0s of the
1105411054+ * video.
1105511055+ */
1105611056+ thumbnailTimestampPct?: number;
1105711057+ /**
1105811058+ * The identifier for the watermark profile
1105911059+ */
1106011060+ watermarkId?: string;
1106111061+};
1106211062+interface StreamScopedCaptions {
1106311063+ /**
1106411064+ * Uploads the caption or subtitle file to the endpoint for a specific BCP47 language.
1106511065+ * One caption or subtitle file per language is allowed.
1106611066+ * @param language The BCP 47 language tag for the caption or subtitle.
1106711067+ * @param file The caption or subtitle file to upload.
1106811068+ * @returns The created caption entry.
1106911069+ * @throws {NotFoundError} if the video is not found
1107011070+ * @throws {BadRequestError} if the language or file is invalid
1107111071+ * @throws {MaxFileSizeError} if the file size is too large
1107211072+ * @throws {InternalError} if an unexpected error occurs
1107311073+ */
1107411074+ upload(language: string, file: File): Promise<StreamCaption>;
1107511075+ /**
1107611076+ * Generate captions or subtitles for the provided language via AI.
1107711077+ * @param language The BCP 47 language tag to generate.
1107811078+ * @returns The generated caption entry.
1107911079+ * @throws {NotFoundError} if the video is not found
1108011080+ * @throws {BadRequestError} if the language is invalid
1108111081+ * @throws {StreamError} if a generated caption already exists
1108211082+ * @throws {StreamError} if the video duration is too long
1108311083+ * @throws {StreamError} if the video is missing audio
1108411084+ * @throws {StreamError} if the requested language is not supported
1108511085+ * @throws {InternalError} if an unexpected error occurs
1108611086+ */
1108711087+ generate(language: string): Promise<StreamCaption>;
1108811088+ /**
1108911089+ * Lists the captions or subtitles.
1109011090+ * Use the language parameter to filter by a specific language.
1109111091+ * @param language The optional BCP 47 language tag to filter by.
1109211092+ * @returns The list of captions or subtitles.
1109311093+ * @throws {NotFoundError} if the video or caption is not found
1109411094+ * @throws {InternalError} if an unexpected error occurs
1109511095+ */
1109611096+ list(language?: string): Promise<StreamCaption[]>;
1109711097+ /**
1109811098+ * Removes the captions or subtitles from a video.
1109911099+ * @param language The BCP 47 language tag to remove.
1110011100+ * @returns A promise that resolves when deletion completes.
1110111101+ * @throws {NotFoundError} if the video or caption is not found
1110211102+ * @throws {InternalError} if an unexpected error occurs
1110311103+ */
1110411104+ delete(language: string): Promise<void>;
1110511105+}
1110611106+interface StreamScopedDownloads {
1110711107+ /**
1110811108+ * Generates a download for a video when a video is ready to view. Available
1110911109+ * types are `default` and `audio`. Defaults to `default` when omitted.
1111011110+ * @param downloadType The download type to create.
1111111111+ * @returns The current downloads for the video.
1111211112+ * @throws {NotFoundError} if the video is not found
1111311113+ * @throws {BadRequestError} if the download type is invalid
1111411114+ * @throws {StreamError} if the video duration is too long to generate a download
1111511115+ * @throws {StreamError} if the video is not ready to stream
1111611116+ * @throws {InternalError} if an unexpected error occurs
1111711117+ */
1111811118+ generate(downloadType?: StreamDownloadType): Promise<StreamDownloadGetResponse>;
1111911119+ /**
1112011120+ * Lists the downloads created for a video.
1112111121+ * @returns The current downloads for the video.
1112211122+ * @throws {NotFoundError} if the video or downloads are not found
1112311123+ * @throws {InternalError} if an unexpected error occurs
1112411124+ */
1112511125+ get(): Promise<StreamDownloadGetResponse>;
1112611126+ /**
1112711127+ * Delete the downloads for a video. Available types are `default` and `audio`.
1112811128+ * Defaults to `default` when omitted.
1112911129+ * @param downloadType The download type to delete.
1113011130+ * @returns A promise that resolves when deletion completes.
1113111131+ * @throws {NotFoundError} if the video or downloads are not found
1113211132+ * @throws {InternalError} if an unexpected error occurs
1113311133+ */
1113411134+ delete(downloadType?: StreamDownloadType): Promise<void>;
1113511135+}
1113611136+interface StreamVideos {
1113711137+ /**
1113811138+ * Lists all videos in a users account.
1113911139+ * @returns The list of videos.
1114011140+ * @throws {BadRequestError} if the parameters are invalid
1114111141+ * @throws {InternalError} if an unexpected error occurs
1114211142+ */
1114311143+ list(params?: StreamVideosListParams): Promise<StreamVideo[]>;
1114411144+}
1114511145+interface StreamWatermarks {
1114611146+ /**
1114711147+ * Generate a new watermark profile
1114811148+ * @param file The image file to upload
1114911149+ * @param params The watermark creation parameters.
1115011150+ * @returns The created watermark profile.
1115111151+ * @throws {BadRequestError} if the parameters are invalid
1115211152+ * @throws {InvalidURLError} if the URL is invalid
1115311153+ * @throws {MaxFileSizeError} if the file size is too large
1115411154+ * @throws {TooManyWatermarksError} if the number of allowed watermarks is reached
1115511155+ * @throws {InternalError} if an unexpected error occurs
1115611156+ */
1115711157+ generate(file: File, params: StreamWatermarkCreateParams): Promise<StreamWatermark>;
1115811158+ /**
1115911159+ * Generate a new watermark profile
1116011160+ * @param url The image url to upload
1116111161+ * @param params The watermark creation parameters.
1116211162+ * @returns The created watermark profile.
1116311163+ * @throws {BadRequestError} if the parameters are invalid
1116411164+ * @throws {InvalidURLError} if the URL is invalid
1116511165+ * @throws {MaxFileSizeError} if the file size is too large
1116611166+ * @throws {TooManyWatermarksError} if the number of allowed watermarks is reached
1116711167+ * @throws {InternalError} if an unexpected error occurs
1116811168+ */
1116911169+ generate(url: string, params: StreamWatermarkCreateParams): Promise<StreamWatermark>;
1117011170+ /**
1117111171+ * Lists all watermark profiles for an account.
1117211172+ * @returns The list of watermark profiles.
1117311173+ * @throws {InternalError} if an unexpected error occurs
1117411174+ */
1117511175+ list(): Promise<StreamWatermark[]>;
1117611176+ /**
1117711177+ * Retrieves details for a single watermark profile.
1117811178+ * @param watermarkId The watermark profile identifier.
1117911179+ * @returns The watermark profile details.
1118011180+ * @throws {NotFoundError} if the watermark is not found
1118111181+ * @throws {InternalError} if an unexpected error occurs
1118211182+ */
1118311183+ get(watermarkId: string): Promise<StreamWatermark>;
1118411184+ /**
1118511185+ * Deletes a watermark profile.
1118611186+ * @param watermarkId The watermark profile identifier.
1118711187+ * @returns A promise that resolves when deletion completes.
1118811188+ * @throws {NotFoundError} if the watermark is not found
1118911189+ * @throws {InternalError} if an unexpected error occurs
1119011190+ */
1119111191+ delete(watermarkId: string): Promise<void>;
1119211192+}
1119311193+type StreamUpdateVideoParams = {
1119411194+ /**
1119511195+ * Lists the origins allowed to display the video. Enter allowed origin
1119611196+ * domains in an array and use `*` for wildcard subdomains. Empty arrays allow the
1119711197+ * video to be viewed on any origin.
1119811198+ */
1119911199+ allowedOrigins?: Array<string>;
1120011200+ /**
1120111201+ * A user-defined identifier for the media creator.
1120211202+ */
1120311203+ creator?: string;
1120411204+ /**
1120511205+ * The maximum duration in seconds for a video upload. Can be set for a
1120611206+ * video that is not yet uploaded to limit its duration. Uploads that exceed the
1120711207+ * specified duration will fail during processing. A value of `-1` means the value
1120811208+ * is unknown.
1120911209+ */
1121011210+ maxDurationSeconds?: number;
1121111211+ /**
1121211212+ * A user modifiable key-value store used to reference other systems of
1121311213+ * record for managing videos.
1121411214+ */
1121511215+ meta?: Record<string, string>;
1121611216+ /**
1121711217+ * Indicates whether the video can be a accessed using the id. When
1121811218+ * set to `true`, a signed token must be generated with a signing key to view the
1121911219+ * video.
1122011220+ */
1122111221+ requireSignedURLs?: boolean;
1122211222+ /**
1122311223+ * Indicates the date and time at which the video will be deleted. Omit
1122411224+ * the field to indicate no change, or include with a `null` value to remove an
1122511225+ * existing scheduled deletion. If specified, must be at least 30 days from upload
1122611226+ * time.
1122711227+ */
1122811228+ scheduledDeletion?: string | null;
1122911229+ /**
1123011230+ * The timestamp for a thumbnail image calculated as a percentage value
1123111231+ * of the video's duration. To convert from a second-wise timestamp to a
1123211232+ * percentage, divide the desired timestamp by the total duration of the video. If
1123311233+ * this value is not set, the default thumbnail image is taken from 0s of the
1123411234+ * video.
1123511235+ */
1123611236+ thumbnailTimestampPct?: number;
1123711237+};
1123811238+type StreamCaption = {
1123911239+ /**
1124011240+ * Whether the caption was generated via AI.
1124111241+ */
1124211242+ generated?: boolean;
1124311243+ /**
1124411244+ * The language label displayed in the native language to users.
1124511245+ */
1124611246+ label: string;
1124711247+ /**
1124811248+ * The language tag in BCP 47 format.
1124911249+ */
1125011250+ language: string;
1125111251+ /**
1125211252+ * The status of a generated caption.
1125311253+ */
1125411254+ status?: 'ready' | 'inprogress' | 'error';
1125511255+};
1125611256+type StreamDownloadStatus = 'ready' | 'inprogress' | 'error';
1125711257+type StreamDownloadType = 'default' | 'audio';
1125811258+type StreamDownload = {
1125911259+ /**
1126011260+ * Indicates the progress as a percentage between 0 and 100.
1126111261+ */
1126211262+ percentComplete: number;
1126311263+ /**
1126411264+ * The status of a generated download.
1126511265+ */
1126611266+ status: StreamDownloadStatus;
1126711267+ /**
1126811268+ * The URL to access the generated download.
1126911269+ */
1127011270+ url?: string;
1127111271+};
1127211272+/**
1127311273+ * An object with download type keys. Each key is optional and only present if that
1127411274+ * download type has been created.
1127511275+ */
1127611276+type StreamDownloadGetResponse = {
1127711277+ /**
1127811278+ * The audio-only download. Only present if this download type has been created.
1127911279+ */
1128011280+ audio?: StreamDownload;
1128111281+ /**
1128211282+ * The default video download. Only present if this download type has been created.
1128311283+ */
1128411284+ default?: StreamDownload;
1128511285+};
1128611286+type StreamWatermarkPosition = 'upperRight' | 'upperLeft' | 'lowerLeft' | 'lowerRight' | 'center';
1128711287+type StreamWatermark = {
1128811288+ /**
1128911289+ * The unique identifier for a watermark profile.
1129011290+ */
1129111291+ id: string;
1129211292+ /**
1129311293+ * The size of the image in bytes.
1129411294+ */
1129511295+ size: number;
1129611296+ /**
1129711297+ * The height of the image in pixels.
1129811298+ */
1129911299+ height: number;
1130011300+ /**
1130111301+ * The width of the image in pixels.
1130211302+ */
1130311303+ width: number;
1130411304+ /**
1130511305+ * The date and a time a watermark profile was created.
1130611306+ */
1130711307+ created: string;
1130811308+ /**
1130911309+ * The source URL for a downloaded image. If the watermark profile was created via
1131011310+ * direct upload, this field is null.
1131111311+ */
1131211312+ downloadedFrom: string | null;
1131311313+ /**
1131411314+ * A short description of the watermark profile.
1131511315+ */
1131611316+ name: string;
1131711317+ /**
1131811318+ * The translucency of the image. A value of `0.0` makes the image completely
1131911319+ * transparent, and `1.0` makes the image completely opaque. Note that if the image
1132011320+ * is already semi-transparent, setting this to `1.0` will not make the image
1132111321+ * completely opaque.
1132211322+ */
1132311323+ opacity: number;
1132411324+ /**
1132511325+ * The whitespace between the adjacent edges (determined by position) of the video
1132611326+ * and the image. `0.0` indicates no padding, and `1.0` indicates a fully padded
1132711327+ * video width or length, as determined by the algorithm.
1132811328+ */
1132911329+ padding: number;
1133011330+ /**
1133111331+ * The size of the image relative to the overall size of the video. This parameter
1133211332+ * will adapt to horizontal and vertical videos automatically. `0.0` indicates no
1133311333+ * scaling (use the size of the image as-is), and `1.0 `fills the entire video.
1133411334+ */
1133511335+ scale: number;
1133611336+ /**
1133711337+ * The location of the image. Valid positions are: `upperRight`, `upperLeft`,
1133811338+ * `lowerLeft`, `lowerRight`, and `center`. Note that `center` ignores the
1133911339+ * `padding` parameter.
1134011340+ */
1134111341+ position: StreamWatermarkPosition;
1134211342+};
1134311343+type StreamWatermarkCreateParams = {
1134411344+ /**
1134511345+ * A short description of the watermark profile.
1134611346+ */
1134711347+ name?: string;
1134811348+ /**
1134911349+ * The translucency of the image. A value of `0.0` makes the image completely
1135011350+ * transparent, and `1.0` makes the image completely opaque. Note that if the
1135111351+ * image is already semi-transparent, setting this to `1.0` will not make the
1135211352+ * image completely opaque.
1135311353+ */
1135411354+ opacity?: number;
1135511355+ /**
1135611356+ * The whitespace between the adjacent edges (determined by position) of the
1135711357+ * video and the image. `0.0` indicates no padding, and `1.0` indicates a fully
1135811358+ * padded video width or length, as determined by the algorithm.
1135911359+ */
1136011360+ padding?: number;
1136111361+ /**
1136211362+ * The size of the image relative to the overall size of the video. This
1136311363+ * parameter will adapt to horizontal and vertical videos automatically. `0.0`
1136411364+ * indicates no scaling (use the size of the image as-is), and `1.0 `fills the
1136511365+ * entire video.
1136611366+ */
1136711367+ scale?: number;
1136811368+ /**
1136911369+ * The location of the image.
1137011370+ */
1137111371+ position?: StreamWatermarkPosition;
1137211372+};
1137311373+type StreamVideosListParams = {
1137411374+ /**
1137511375+ * The maximum number of videos to return.
1137611376+ */
1137711377+ limit?: number;
1137811378+ /**
1137911379+ * Return videos created before this timestamp.
1138011380+ * (RFC3339/RFC3339Nano)
1138111381+ */
1138211382+ before?: string;
1138311383+ /**
1138411384+ * Comparison operator for the `before` field.
1138511385+ * @default 'lt'
1138611386+ */
1138711387+ beforeComp?: StreamPaginationComparison;
1138811388+ /**
1138911389+ * Return videos created after this timestamp.
1139011390+ * (RFC3339/RFC3339Nano)
1139111391+ */
1139211392+ after?: string;
1139311393+ /**
1139411394+ * Comparison operator for the `after` field.
1139511395+ * @default 'gte'
1139611396+ */
1139711397+ afterComp?: StreamPaginationComparison;
1139811398+};
1139911399+type StreamPaginationComparison = 'eq' | 'gt' | 'gte' | 'lt' | 'lte';
1140011400+/**
1140111401+ * Error object for Stream binding operations.
1140211402+ */
1140311403+interface StreamError extends Error {
1140411404+ readonly code: number;
1140511405+ readonly statusCode: number;
1140611406+ readonly message: string;
1140711407+ readonly stack?: string;
1140811408+}
1140911409+interface InternalError extends StreamError {
1141011410+ name: 'InternalError';
1141111411+}
1141211412+interface BadRequestError extends StreamError {
1141311413+ name: 'BadRequestError';
1141411414+}
1141511415+interface NotFoundError extends StreamError {
1141611416+ name: 'NotFoundError';
1141711417+}
1141811418+interface ForbiddenError extends StreamError {
1141911419+ name: 'ForbiddenError';
1142011420+}
1142111421+interface RateLimitedError extends StreamError {
1142211422+ name: 'RateLimitedError';
1142311423+}
1142411424+interface QuotaReachedError extends StreamError {
1142511425+ name: 'QuotaReachedError';
1142611426+}
1142711427+interface MaxFileSizeError extends StreamError {
1142811428+ name: 'MaxFileSizeError';
1142911429+}
1143011430+interface InvalidURLError extends StreamError {
1143111431+ name: 'InvalidURLError';
1143211432+}
1143311433+interface AlreadyUploadedError extends StreamError {
1143411434+ name: 'AlreadyUploadedError';
1143511435+}
1143611436+interface TooManyWatermarksError extends StreamError {
1143711437+ name: 'TooManyWatermarksError';
1068911438}
1069011439type MarkdownDocument = {
1069111440 name: string;
+11
wrangler.toml
···2121database_name = "bskylabels"
2222database_id = ""
23232424+[[ratelimits]]
2525+name = "BSKY_LABEL_LIMITER"
2626+namespace_id = "461001"
2727+[ratelimits.simple]
2828+limit = 10
2929+period = 60
3030+2431[vars]
2532COUNT_CACHE_HOUR="4"
3333+3434+# use rate limits (recommended)
3535+RATELIMIT="true"
3636+2637# Site metadata
2738SITE_TITLE="Simple BSky Labeler"
2839SITE_DESCRIPTION="Allow people to obtain a bsky label you provide"