Schedule posts to Bluesky with Cloudflare workers. skyscheduler.work
cf tool bsky-tool cloudflare bluesky schedule bsky service social-media cloudflare-workers
at main 110 lines 3.7 kB view raw
1import { relations, sql } from "drizzle-orm"; 2import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; 3 4export const users = sqliteTable("users", { 5 id: text("id").primaryKey(), 6 name: text("name").notNull(), 7 email: text("email").notNull().unique(), 8 emailVerified: integer("email_verified", { mode: "boolean" }) 9 .$defaultFn(() => false) 10 .notNull(), 11 image: text("image"), 12 createdAt: integer("created_at", { mode: "timestamp" }) 13 .$defaultFn(() => /* @__PURE__ */ new Date()) 14 .notNull(), 15 updatedAt: integer("updated_at", { mode: "timestamp" }) 16 .$defaultFn(() => /* @__PURE__ */ new Date()) 17 .notNull(), 18 username: text("username").unique(), 19 displayUsername: text("display_username"), 20 bskyAppPass: text("bsky_app_pass").notNull(), 21 pds: text("pds").default("https://bsky.social").notNull(), 22}); 23 24export const sessions = sqliteTable( 25 "sessions", 26 { 27 id: text("id").primaryKey(), 28 expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(), 29 token: text("token").notNull().unique(), 30 createdAt: integer("created_at", { mode: "timestamp_ms" }) 31 .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) 32 .notNull(), 33 updatedAt: integer("updated_at", { mode: "timestamp_ms" }) 34 .$onUpdate(() => /* @__PURE__ */ new Date()) 35 .notNull(), 36 ipAddress: text("ip_address"), 37 userAgent: text("user_agent"), 38 userId: text("user_id") 39 .notNull() 40 .references(() => users.id, { onDelete: "cascade" }), 41 }, 42 (table) => [index("sessions_userId_idx").on(table.userId)], 43); 44 45export const accounts = sqliteTable( 46 "accounts", 47 { 48 id: text("id").primaryKey(), 49 accountId: text("account_id").notNull(), 50 providerId: text("provider_id").notNull(), 51 userId: text("user_id") 52 .notNull() 53 .references(() => users.id, { onDelete: "cascade" }), 54 accessToken: text("access_token"), 55 refreshToken: text("refresh_token"), 56 idToken: text("id_token"), 57 accessTokenExpiresAt: integer("access_token_expires_at", { 58 mode: "timestamp_ms", 59 }), 60 refreshTokenExpiresAt: integer("refresh_token_expires_at", { 61 mode: "timestamp_ms", 62 }), 63 scope: text("scope"), 64 password: text("password"), 65 createdAt: integer("created_at", { mode: "timestamp_ms" }) 66 .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) 67 .notNull(), 68 updatedAt: integer("updated_at", { mode: "timestamp_ms" }) 69 .$onUpdate(() => /* @__PURE__ */ new Date()) 70 .notNull(), 71 }, 72 (table) => [index("accounts_userId_idx").on(table.userId)], 73); 74 75export const verifications = sqliteTable( 76 "verifications", 77 { 78 id: text("id").primaryKey(), 79 identifier: text("identifier").notNull(), 80 value: text("value").notNull(), 81 expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(), 82 createdAt: integer("created_at", { mode: "timestamp_ms" }) 83 .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) 84 .notNull(), 85 updatedAt: integer("updated_at", { mode: "timestamp_ms" }) 86 .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) 87 .$onUpdate(() => /* @__PURE__ */ new Date()) 88 .notNull(), 89 }, 90 (table) => [index("verifications_identifier_idx").on(table.identifier)], 91); 92 93export const usersRelations = relations(users, ({ many }) => ({ 94 sessions: many(sessions), 95 accounts: many(accounts), 96})); 97 98export const sessionsRelations = relations(sessions, ({ one }) => ({ 99 users: one(users, { 100 fields: [sessions.userId], 101 references: [users.id], 102 }), 103})); 104 105export const accountsRelations = relations(accounts, ({ one }) => ({ 106 users: one(users, { 107 fields: [accounts.userId], 108 references: [users.id], 109 }), 110}));