codeblog-app 2.0.0 → 2.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 (68) hide show
  1. package/package.json +8 -71
  2. package/drizzle/0000_init.sql +0 -34
  3. package/drizzle/meta/_journal.json +0 -13
  4. package/drizzle.config.ts +0 -10
  5. package/src/ai/__tests__/chat.test.ts +0 -110
  6. package/src/ai/__tests__/provider.test.ts +0 -184
  7. package/src/ai/__tests__/tools.test.ts +0 -90
  8. package/src/ai/chat.ts +0 -169
  9. package/src/ai/configure.ts +0 -89
  10. package/src/ai/provider.ts +0 -238
  11. package/src/ai/tools.ts +0 -321
  12. package/src/auth/index.ts +0 -47
  13. package/src/auth/oauth.ts +0 -93
  14. package/src/cli/__tests__/commands.test.ts +0 -225
  15. package/src/cli/__tests__/setup.test.ts +0 -57
  16. package/src/cli/cmd/agent.ts +0 -102
  17. package/src/cli/cmd/chat.ts +0 -190
  18. package/src/cli/cmd/comment.ts +0 -70
  19. package/src/cli/cmd/config.ts +0 -153
  20. package/src/cli/cmd/feed.ts +0 -57
  21. package/src/cli/cmd/forum.ts +0 -123
  22. package/src/cli/cmd/login.ts +0 -45
  23. package/src/cli/cmd/logout.ts +0 -12
  24. package/src/cli/cmd/me.ts +0 -202
  25. package/src/cli/cmd/post.ts +0 -29
  26. package/src/cli/cmd/publish.ts +0 -70
  27. package/src/cli/cmd/scan.ts +0 -80
  28. package/src/cli/cmd/search.ts +0 -40
  29. package/src/cli/cmd/setup.ts +0 -201
  30. package/src/cli/cmd/tui.ts +0 -20
  31. package/src/cli/cmd/update.ts +0 -78
  32. package/src/cli/cmd/vote.ts +0 -50
  33. package/src/cli/cmd/whoami.ts +0 -21
  34. package/src/cli/ui.ts +0 -124
  35. package/src/config/index.ts +0 -54
  36. package/src/flag/index.ts +0 -23
  37. package/src/global/index.ts +0 -38
  38. package/src/id/index.ts +0 -20
  39. package/src/index.ts +0 -186
  40. package/src/mcp/__tests__/client.test.ts +0 -149
  41. package/src/mcp/__tests__/e2e.ts +0 -327
  42. package/src/mcp/__tests__/integration.ts +0 -148
  43. package/src/mcp/client.ts +0 -148
  44. package/src/server/index.ts +0 -48
  45. package/src/storage/chat.ts +0 -92
  46. package/src/storage/db.ts +0 -85
  47. package/src/storage/schema.sql.ts +0 -39
  48. package/src/storage/schema.ts +0 -1
  49. package/src/tui/app.tsx +0 -163
  50. package/src/tui/commands.ts +0 -177
  51. package/src/tui/context/exit.tsx +0 -15
  52. package/src/tui/context/helper.tsx +0 -25
  53. package/src/tui/context/route.tsx +0 -24
  54. package/src/tui/context/theme.tsx +0 -470
  55. package/src/tui/routes/home.tsx +0 -490
  56. package/src/tui/routes/model.tsx +0 -209
  57. package/src/tui/routes/notifications.tsx +0 -85
  58. package/src/tui/routes/post.tsx +0 -108
  59. package/src/tui/routes/search.tsx +0 -104
  60. package/src/tui/routes/setup.tsx +0 -255
  61. package/src/tui/routes/trending.tsx +0 -107
  62. package/src/util/__tests__/context.test.ts +0 -31
  63. package/src/util/__tests__/lazy.test.ts +0 -37
  64. package/src/util/context.ts +0 -23
  65. package/src/util/error.ts +0 -46
  66. package/src/util/lazy.ts +0 -18
  67. package/src/util/log.ts +0 -142
  68. package/tsconfig.json +0 -11
@@ -1,148 +0,0 @@
1
- /**
2
- * Integration test: verify all 26 MCP tools are accessible via McpBridge.
3
- *
4
- * This script:
5
- * 1. Connects to the MCP server (spawns codeblog-mcp subprocess)
6
- * 2. Lists all available tools
7
- * 3. Tests calling each tool that can be safely invoked without side effects
8
- * 4. Reports results
9
- *
10
- * Usage: bun run src/mcp/__tests__/integration.ts
11
- */
12
-
13
- import { McpBridge } from "../client"
14
-
15
- const EXPECTED_TOOLS = [
16
- "scan_sessions",
17
- "read_session",
18
- "analyze_session",
19
- "post_to_codeblog",
20
- "auto_post",
21
- "weekly_digest",
22
- "browse_posts",
23
- "search_posts",
24
- "read_post",
25
- "comment_on_post",
26
- "vote_on_post",
27
- "edit_post",
28
- "delete_post",
29
- "bookmark_post",
30
- "browse_by_tag",
31
- "trending_topics",
32
- "explore_and_engage",
33
- "join_debate",
34
- "my_notifications",
35
- "manage_agents",
36
- "my_posts",
37
- "my_dashboard",
38
- "follow_agent",
39
- "codeblog_status",
40
- "codeblog_setup",
41
- ]
42
-
43
- // Tools that are safe to call without side effects (read-only)
44
- const SAFE_TOOLS: Record<string, Record<string, unknown>> = {
45
- codeblog_status: {},
46
- scan_sessions: { limit: 3 },
47
- browse_posts: { sort: "new", limit: 2 },
48
- search_posts: { query: "test", limit: 2 },
49
- browse_by_tag: { action: "trending", limit: 3 },
50
- trending_topics: {},
51
- explore_and_engage: { action: "browse", limit: 2 },
52
- join_debate: { action: "list" },
53
- my_notifications: { action: "list", limit: 2 },
54
- manage_agents: { action: "list" },
55
- my_posts: { limit: 2 },
56
- my_dashboard: {},
57
- follow_agent: { action: "list_following", limit: 2 },
58
- bookmark_post: { action: "list" },
59
- }
60
-
61
- async function main() {
62
- console.log("=== MCP Integration Test ===\n")
63
-
64
- // Step 1: List tools
65
- console.log("1. Listing MCP tools...")
66
- let tools: Array<{ name: string; description?: string }>
67
- try {
68
- const result = await McpBridge.listTools()
69
- tools = result.tools
70
- console.log(` ✓ Found ${tools.length} tools\n`)
71
- } catch (err) {
72
- console.error(` ✗ Failed to list tools: ${err instanceof Error ? err.message : err}`)
73
- await McpBridge.disconnect()
74
- process.exit(1)
75
- return
76
- }
77
-
78
- // Step 2: Check expected tools
79
- console.log("2. Checking expected tools...")
80
- const toolNames = tools.map((t) => t.name)
81
- let missing = 0
82
- for (const expected of EXPECTED_TOOLS) {
83
- if (toolNames.includes(expected)) {
84
- console.log(` ✓ ${expected}`)
85
- } else {
86
- console.log(` ✗ MISSING: ${expected}`)
87
- missing++
88
- }
89
- }
90
-
91
- const extra = toolNames.filter((t) => !EXPECTED_TOOLS.includes(t))
92
- if (extra.length > 0) {
93
- console.log(`\n Extra tools not in expected list: ${extra.join(", ")}`)
94
- }
95
- console.log(`\n Expected: ${EXPECTED_TOOLS.length}, Found: ${toolNames.length}, Missing: ${missing}\n`)
96
-
97
- // Step 3: Call safe tools
98
- console.log("3. Testing safe tool calls...")
99
- let passed = 0
100
- let failed = 0
101
-
102
- for (const [name, args] of Object.entries(SAFE_TOOLS)) {
103
- if (!toolNames.includes(name)) {
104
- console.log(` ⊘ ${name} — skipped (not available)`)
105
- continue
106
- }
107
-
108
- try {
109
- const result = await McpBridge.callTool(name, args)
110
- const preview = result.slice(0, 80).replace(/\n/g, " ")
111
- console.log(` ✓ ${name} — ${preview}${result.length > 80 ? "..." : ""}`)
112
- passed++
113
- } catch (err) {
114
- const msg = err instanceof Error ? err.message : String(err)
115
- // Auth errors are expected in test environment
116
- if (msg.includes("auth") || msg.includes("API key") || msg.includes("token") || msg.includes("401") || msg.includes("unauthorized") || msg.includes("Unauthorized")) {
117
- console.log(` ⊘ ${name} — auth required (expected in test env)`)
118
- passed++ // Count as pass — tool is reachable, just needs auth
119
- } else {
120
- console.log(` ✗ ${name} — ${msg}`)
121
- failed++
122
- }
123
- }
124
- }
125
-
126
- console.log(`\n Passed: ${passed}, Failed: ${failed}\n`)
127
-
128
- // Cleanup
129
- console.log("4. Disconnecting...")
130
- await McpBridge.disconnect()
131
- console.log(" ✓ Disconnected\n")
132
-
133
- console.log("=== Summary ===")
134
- console.log(`Tools found: ${toolNames.length}`)
135
- console.log(`Tools tested: ${passed + failed}/${Object.keys(SAFE_TOOLS).length}`)
136
- console.log(`Tests passed: ${passed}`)
137
- console.log(`Tests failed: ${failed}`)
138
- console.log(`Missing expected tools: ${missing}`)
139
-
140
- if (failed > 0 || missing > 0) {
141
- process.exit(1)
142
- }
143
- }
144
-
145
- main().catch((err) => {
146
- console.error("Fatal error:", err)
147
- process.exit(1)
148
- })
package/src/mcp/client.ts DELETED
@@ -1,148 +0,0 @@
1
- import { Client } from "@modelcontextprotocol/sdk/client/index.js"
2
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
3
- import { resolve, dirname } from "path"
4
- import { Log } from "../util/log"
5
-
6
- const log = Log.create({ service: "mcp" })
7
-
8
- const CONNECTION_TIMEOUT_MS = 30_000
9
-
10
- let client: Client | null = null
11
- let transport: StdioClientTransport | null = null
12
- let connecting: Promise<Client> | null = null
13
-
14
- function getMcpBinaryPath(): string {
15
- try {
16
- const resolved = require.resolve("codeblog-mcp/dist/index.js")
17
- return resolved
18
- } catch {
19
- return resolve(dirname(new URL(import.meta.url).pathname), "../../node_modules/codeblog-mcp/dist/index.js")
20
- }
21
- }
22
-
23
- function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {
24
- return new Promise<T>((resolve, reject) => {
25
- const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms)
26
- promise.then(
27
- (v) => { clearTimeout(timer); resolve(v) },
28
- (e) => { clearTimeout(timer); reject(e) },
29
- )
30
- })
31
- }
32
-
33
- async function connect(): Promise<Client> {
34
- if (client) return client
35
-
36
- // If another caller is already connecting, reuse that promise
37
- if (connecting) return connecting
38
-
39
- connecting = (async (): Promise<Client> => {
40
- const mcpPath = getMcpBinaryPath()
41
- log.debug("connecting", { path: mcpPath })
42
-
43
- const env: Record<string, string> = {}
44
- for (const [k, v] of Object.entries(process.env)) {
45
- if (v !== undefined) env[k] = v
46
- }
47
-
48
- const t = new StdioClientTransport({
49
- command: "node",
50
- args: [mcpPath],
51
- env,
52
- stderr: "pipe",
53
- })
54
-
55
- const c = new Client({ name: "codeblog-cli", version: "2.0.0" })
56
-
57
- try {
58
- await withTimeout(c.connect(t), CONNECTION_TIMEOUT_MS, "MCP connection")
59
- } catch (err) {
60
- // Clean up on failure so next call can retry
61
- await t.close().catch(() => {})
62
- throw err
63
- }
64
-
65
- log.debug("connected", {
66
- server: c.getServerVersion()?.name,
67
- version: c.getServerVersion()?.version,
68
- })
69
-
70
- // Only assign to module-level vars after successful connection
71
- transport = t
72
- client = c
73
- return c
74
- })()
75
-
76
- try {
77
- return await connecting
78
- } catch (err) {
79
- // Reset connecting so next call can retry
80
- connecting = null
81
- throw err
82
- }
83
- }
84
-
85
- export namespace McpBridge {
86
- /**
87
- * Call an MCP tool by name with arguments.
88
- * Returns the text content from the tool result.
89
- */
90
- export async function callTool(
91
- name: string,
92
- args: Record<string, unknown> = {},
93
- ): Promise<string> {
94
- const c = await connect()
95
- const result = await c.callTool({ name, arguments: args })
96
-
97
- if (result.isError) {
98
- const text = extractText(result)
99
- throw new Error(text || `MCP tool "${name}" returned an error`)
100
- }
101
-
102
- return extractText(result)
103
- }
104
-
105
- /**
106
- * Call an MCP tool and parse the result as JSON.
107
- */
108
- export async function callToolJSON<T = unknown>(
109
- name: string,
110
- args: Record<string, unknown> = {},
111
- ): Promise<T> {
112
- const text = await callTool(name, args)
113
- try {
114
- return JSON.parse(text) as T
115
- } catch {
116
- return text as unknown as T
117
- }
118
- }
119
-
120
- /**
121
- * List all available MCP tools.
122
- */
123
- export async function listTools() {
124
- const c = await connect()
125
- return c.listTools()
126
- }
127
-
128
- /**
129
- * Disconnect the MCP client and kill the subprocess.
130
- */
131
- export async function disconnect(): Promise<void> {
132
- connecting = null
133
- if (transport) {
134
- await transport.close().catch(() => {})
135
- transport = null
136
- }
137
- client = null
138
- }
139
- }
140
-
141
- function extractText(result: unknown): string {
142
- const r = result as { content?: Array<{ type: string; text?: string }> }
143
- if (!r.content || !Array.isArray(r.content)) return ""
144
- return r.content
145
- .filter((c) => c.type === "text" && c.text)
146
- .map((c) => c.text!)
147
- .join("\n")
148
- }
@@ -1,48 +0,0 @@
1
- import { Hono } from "hono"
2
- import { Log } from "../util/log"
3
-
4
- const log = Log.create({ service: "server" })
5
-
6
- export namespace Server {
7
- let instance: ReturnType<typeof Bun.serve> | null = null
8
-
9
- export function start(app: Hono, port: number): ReturnType<typeof Bun.serve> {
10
- if (instance) {
11
- log.warn("server already running, stopping previous instance")
12
- instance.stop()
13
- }
14
- instance = Bun.serve({ port, fetch: app.fetch })
15
- log.info("server started", { port })
16
- return instance
17
- }
18
-
19
- export function stop() {
20
- if (instance) {
21
- instance.stop()
22
- instance = null
23
- log.info("server stopped")
24
- }
25
- }
26
-
27
- export function running(): boolean {
28
- return instance !== null
29
- }
30
-
31
- export function createCallbackServer(onCallback: (params: URLSearchParams) => Promise<string>): {
32
- app: Hono
33
- port: number
34
- } {
35
- const port = 19823
36
- const app = new Hono()
37
-
38
- app.get("/callback", async (c) => {
39
- const params = new URL(c.req.url).searchParams
40
- const html = await onCallback(params)
41
- return c.html(html)
42
- })
43
-
44
- app.get("/health", (c) => c.json({ ok: true }))
45
-
46
- return { app, port }
47
- }
48
- }
@@ -1,92 +0,0 @@
1
- import { Database as BunDatabase } from "bun:sqlite"
2
- import { Global } from "../global"
3
- import path from "path"
4
-
5
- function db() {
6
- const dbpath = path.join(Global.Path.data, "codeblog.db")
7
- const sqlite = new BunDatabase(dbpath, { create: true })
8
- sqlite.run("PRAGMA journal_mode = WAL")
9
- sqlite.run("PRAGMA foreign_keys = ON")
10
-
11
- sqlite.run(`CREATE TABLE IF NOT EXISTS chat_sessions (
12
- id TEXT PRIMARY KEY,
13
- title TEXT,
14
- time_created INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
15
- time_updated INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
16
- )`)
17
-
18
- sqlite.run(`CREATE TABLE IF NOT EXISTS chat_messages (
19
- id INTEGER PRIMARY KEY AUTOINCREMENT,
20
- session_id TEXT NOT NULL,
21
- role TEXT NOT NULL,
22
- content TEXT NOT NULL,
23
- tool_name TEXT,
24
- tool_status TEXT,
25
- time_created INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
26
- )`)
27
-
28
- return sqlite
29
- }
30
-
31
- export interface ChatMsg {
32
- role: "user" | "assistant" | "tool"
33
- content: string
34
- toolName?: string
35
- toolStatus?: "running" | "done" | "error"
36
- }
37
-
38
- export namespace ChatHistory {
39
- export function create(id: string, title?: string) {
40
- const d = db()
41
- d.run("INSERT OR REPLACE INTO chat_sessions (id, title, time_created, time_updated) VALUES (?, ?, ?, ?)", [id, title || null, Date.now(), Date.now()])
42
- d.close()
43
- }
44
-
45
- export function save(sessionId: string, messages: ChatMsg[]) {
46
- const d = db()
47
- d.run("DELETE FROM chat_messages WHERE session_id = ?", [sessionId])
48
- const stmt = d.prepare("INSERT INTO chat_messages (session_id, role, content, tool_name, tool_status, time_created) VALUES (?, ?, ?, ?, ?, ?)")
49
- for (const m of messages) {
50
- stmt.run(sessionId, m.role, m.content, m.toolName || null, m.toolStatus || null, Date.now())
51
- }
52
- // Update session title from first user message
53
- const first = messages.find((m) => m.role === "user")
54
- if (first) {
55
- const title = first.content.slice(0, 80)
56
- d.run("UPDATE chat_sessions SET title = ?, time_updated = ? WHERE id = ?", [title, Date.now(), sessionId])
57
- }
58
- d.close()
59
- }
60
-
61
- export function load(sessionId: string): ChatMsg[] {
62
- const d = db()
63
- const rows = d.query("SELECT role, content, tool_name, tool_status FROM chat_messages WHERE session_id = ? ORDER BY id ASC").all(sessionId) as any[]
64
- d.close()
65
- return rows.map((r) => ({
66
- role: r.role,
67
- content: r.content,
68
- ...(r.tool_name ? { toolName: r.tool_name } : {}),
69
- ...(r.tool_status ? { toolStatus: r.tool_status } : {}),
70
- }))
71
- }
72
-
73
- export function list(limit = 20): Array<{ id: string; title: string | null; time: number; count: number }> {
74
- const d = db()
75
- const rows = d.query(`
76
- SELECT s.id, s.title, s.time_updated as time,
77
- (SELECT COUNT(*) FROM chat_messages WHERE session_id = s.id) as count
78
- FROM chat_sessions s
79
- ORDER BY s.time_updated DESC
80
- LIMIT ?
81
- `).all(limit) as any[]
82
- d.close()
83
- return rows.map((r) => ({ id: r.id, title: r.title, time: r.time, count: r.count }))
84
- }
85
-
86
- export function remove(sessionId: string) {
87
- const d = db()
88
- d.run("DELETE FROM chat_messages WHERE session_id = ?", [sessionId])
89
- d.run("DELETE FROM chat_sessions WHERE id = ?", [sessionId])
90
- d.close()
91
- }
92
- }
package/src/storage/db.ts DELETED
@@ -1,85 +0,0 @@
1
- import { Database as BunDatabase } from "bun:sqlite"
2
- import { drizzle } from "drizzle-orm/bun-sqlite"
3
- import { Context } from "../util/context"
4
- import { lazy } from "../util/lazy"
5
- import { Global } from "../global"
6
- import { Log } from "../util/log"
7
- import path from "path"
8
- import * as schema from "./schema"
9
-
10
- const log = Log.create({ service: "db" })
11
-
12
- export namespace Database {
13
- type Schema = typeof schema
14
-
15
- export const Client = lazy(() => {
16
- const dbpath = path.join(Global.Path.data, "codeblog.db")
17
- log.info("opening database", { path: dbpath })
18
-
19
- const sqlite = new BunDatabase(dbpath, { create: true })
20
-
21
- sqlite.run("PRAGMA journal_mode = WAL")
22
- sqlite.run("PRAGMA synchronous = NORMAL")
23
- sqlite.run("PRAGMA busy_timeout = 5000")
24
- sqlite.run("PRAGMA cache_size = -64000")
25
- sqlite.run("PRAGMA foreign_keys = ON")
26
-
27
- // Auto-create tables
28
- sqlite.run(`CREATE TABLE IF NOT EXISTS published_sessions (
29
- id TEXT PRIMARY KEY,
30
- session_id TEXT NOT NULL,
31
- source TEXT NOT NULL,
32
- post_id TEXT,
33
- file_path TEXT NOT NULL,
34
- time_created INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
35
- time_updated INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
36
- )`)
37
-
38
- sqlite.run(`CREATE TABLE IF NOT EXISTS cached_posts (
39
- id TEXT PRIMARY KEY,
40
- title TEXT NOT NULL,
41
- content TEXT NOT NULL,
42
- author_name TEXT,
43
- votes INTEGER DEFAULT 0,
44
- comments_count INTEGER DEFAULT 0,
45
- tags TEXT,
46
- time_created INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
47
- time_updated INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
48
- )`)
49
-
50
- sqlite.run(`CREATE TABLE IF NOT EXISTS chat_sessions (
51
- id TEXT PRIMARY KEY,
52
- title TEXT,
53
- time_created INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
54
- time_updated INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
55
- )`)
56
-
57
- sqlite.run(`CREATE TABLE IF NOT EXISTS chat_messages (
58
- id INTEGER PRIMARY KEY AUTOINCREMENT,
59
- session_id TEXT NOT NULL REFERENCES chat_sessions(id) ON DELETE CASCADE,
60
- role TEXT NOT NULL,
61
- content TEXT NOT NULL,
62
- tool_name TEXT,
63
- tool_status TEXT,
64
- time_created INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
65
- )`)
66
-
67
- sqlite.run(`CREATE TABLE IF NOT EXISTS notifications_cache (
68
- id TEXT PRIMARY KEY,
69
- type TEXT NOT NULL,
70
- message TEXT NOT NULL,
71
- read INTEGER DEFAULT 0,
72
- post_id TEXT,
73
- time_created INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
74
- time_updated INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
75
- )`)
76
-
77
- return drizzle({ client: sqlite, schema })
78
- })
79
-
80
- const ctx = Context.create<{ tx: any; effects: (() => void | Promise<void>)[] }>("database")
81
-
82
- export function use<T>(callback: (db: ReturnType<typeof Client>) => T): T {
83
- return callback(Client())
84
- }
85
- }
@@ -1,39 +0,0 @@
1
- import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core"
2
-
3
- export const Timestamps = {
4
- time_created: integer()
5
- .notNull()
6
- .$default(() => Date.now()),
7
- time_updated: integer()
8
- .notNull()
9
- .$onUpdate(() => Date.now()),
10
- }
11
-
12
- export const published_sessions = sqliteTable("published_sessions", {
13
- id: text().primaryKey(),
14
- session_id: text().notNull(),
15
- source: text().notNull(),
16
- post_id: text(),
17
- file_path: text().notNull(),
18
- ...Timestamps,
19
- })
20
-
21
- export const cached_posts = sqliteTable("cached_posts", {
22
- id: text().primaryKey(),
23
- title: text().notNull(),
24
- content: text().notNull(),
25
- author_name: text(),
26
- votes: integer().default(0),
27
- comments_count: integer().default(0),
28
- tags: text(),
29
- ...Timestamps,
30
- })
31
-
32
- export const notifications_cache = sqliteTable("notifications_cache", {
33
- id: text().primaryKey(),
34
- type: text().notNull(),
35
- message: text().notNull(),
36
- read: integer().default(0),
37
- post_id: text(),
38
- ...Timestamps,
39
- })
@@ -1 +0,0 @@
1
- export { published_sessions, cached_posts, notifications_cache } from "./schema.sql"