@bbki.ng/backend 0.3.8 → 0.3.9

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # backend
2
2
 
3
+ ## 0.3.9
4
+
5
+ ### Patch Changes
6
+
7
+ - 282af74: update ui components
8
+ - 558e40b: update compoennts
9
+
3
10
  ## 0.3.8
4
11
 
5
12
  ### Patch Changes
package/README.md CHANGED
@@ -17,5 +17,5 @@ Pass the `CloudflareBindings` as generics when instantiation `Hono`:
17
17
 
18
18
  ```ts
19
19
  // src/index.ts
20
- const app = new Hono<{ Bindings: CloudflareBindings }>()
20
+ const app = new Hono<{ Bindings: CloudflareBindings }>();
21
21
  ```
package/eslint.config.js CHANGED
@@ -6,7 +6,4 @@ import { fileURLToPath } from 'url';
6
6
  const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
 
9
- export default [
10
- includeIgnoreFile(path.resolve(__dirname, '.gitignore')),
11
- ...cloudflareConfig,
12
- ];
9
+ export default [includeIgnoreFile(path.resolve(__dirname, '.gitignore')), ...cloudflareConfig];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbki.ng/backend",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "@simplewebauthn/server": "13.2.2",
@@ -1,6 +1,6 @@
1
- import { Hono } from "hono";
2
- import type { D1Database } from "@cloudflare/workers-types";
3
- import { cors } from "hono/cors";
1
+ import { Hono } from 'hono';
2
+ import type { D1Database } from '@cloudflare/workers-types';
3
+ import { cors } from 'hono/cors';
4
4
 
5
5
  type Bindings = {
6
6
  DB: D1Database;
@@ -10,10 +10,10 @@ type Bindings = {
10
10
  const app = new Hono<{ Bindings: Bindings }>();
11
11
 
12
12
  app.use(
13
- "*",
13
+ '*',
14
14
  cors({
15
- origin: ["https://bbki.ng"],
16
- }),
15
+ origin: ['https://bbki.ng'],
16
+ })
17
17
  );
18
18
 
19
19
  export default app;
@@ -1,24 +1,24 @@
1
- import { Context } from "hono";
1
+ import { Context } from 'hono';
2
2
 
3
3
  export const addComment = async (c: Context) => {
4
4
  const { articleId, author, content } = await c.req.json();
5
5
 
6
6
  try {
7
7
  let { results } = await c.env.DB.prepare(
8
- "INSERT INTO comment (article_id, author, content, created_at) VALUES (?, ?, ?, ?);",
8
+ 'INSERT INTO comment (article_id, author, content, created_at) VALUES (?, ?, ?, ?);'
9
9
  )
10
10
  .bind(articleId, author, content, new Date().toISOString())
11
11
  .run();
12
12
 
13
13
  return c.json({
14
- status: "success",
15
- message: "Comment added successfully",
14
+ status: 'success',
15
+ message: 'Comment added successfully',
16
16
  results,
17
17
  });
18
18
  } catch (error: any) {
19
19
  return c.json({
20
- status: "error",
21
- message: "Failed to add comment",
20
+ status: 'error',
21
+ message: 'Failed to add comment',
22
22
  error: error.message,
23
23
  });
24
24
  }
@@ -1,5 +1,5 @@
1
- import { Context } from "hono";
2
- import { HTTPException } from "hono/http-exception";
1
+ import { Context } from 'hono';
2
+ import { HTTPException } from 'hono/http-exception';
3
3
 
4
4
  interface AddStreamingRequest {
5
5
  author?: string;
@@ -25,25 +25,25 @@ export const addStreaming = async (c: Context) => {
25
25
  const streamApiKey = c.env?.STREAM_API_KEY;
26
26
  if (!streamApiKey) {
27
27
  console.error('STREAM_API_KEY not configured in environment');
28
- throw new HTTPException(500, { message: "Server configuration error" });
28
+ throw new HTTPException(500, { message: 'Server configuration error' });
29
29
  }
30
30
 
31
31
  // 1. 认证(Header 方式)
32
32
  const apiKey = c.req.header('x-api-key');
33
33
  if (!apiKey || !timingSafeEqual(apiKey, streamApiKey)) {
34
- throw new HTTPException(401, { message: "Invalid API key" });
34
+ throw new HTTPException(401, { message: 'Invalid API key' });
35
35
  }
36
36
 
37
37
  // 2. 解析与验证
38
38
  const body = await c.req.json<AddStreamingRequest>();
39
-
40
- if (!body.content || typeof body.content !== "string") {
41
- throw new HTTPException(400, { message: "Content is required" });
39
+
40
+ if (!body.content || typeof body.content !== 'string') {
41
+ throw new HTTPException(400, { message: 'Content is required' });
42
42
  }
43
-
43
+
44
44
  const content = body.content.trim();
45
45
  if (content.length === 0) {
46
- throw new HTTPException(400, { message: "Content cannot be empty" });
46
+ throw new HTTPException(400, { message: 'Content cannot be empty' });
47
47
  }
48
48
  if (content.length > MAX_CONTENT_LENGTH) {
49
49
  throw new HTTPException(413, { message: `Content exceeds ${MAX_CONTENT_LENGTH} chars` });
@@ -51,17 +51,17 @@ export const addStreaming = async (c: Context) => {
51
51
 
52
52
  const author = (body.author ?? 'bbki.ng').trim();
53
53
  if (author.length > 50) {
54
- throw new HTTPException(400, { message: "Author too long" });
54
+ throw new HTTPException(400, { message: 'Author too long' });
55
55
  }
56
56
 
57
57
  const type = body.type?.trim();
58
- if (type && !ALLOWED_TYPES.includes(type as typeof ALLOWED_TYPES[number])) {
59
- throw new HTTPException(400, { message: "Invalid type" });
58
+ if (type && !ALLOWED_TYPES.includes(type as (typeof ALLOWED_TYPES)[number])) {
59
+ throw new HTTPException(400, { message: 'Invalid type' });
60
60
  }
61
61
 
62
62
  // 3. 数据库检查
63
63
  if (!c.env?.DB) {
64
- throw new HTTPException(503, { message: "Database unavailable" });
64
+ throw new HTTPException(503, { message: 'Database unavailable' });
65
65
  }
66
66
 
67
67
  // 4. 写入
@@ -70,31 +70,36 @@ export const addStreaming = async (c: Context) => {
70
70
 
71
71
  try {
72
72
  await c.env.DB.prepare(
73
- "INSERT INTO streaming (id, author, content, type, created_at) VALUES (?, ?, ?, ?, ?)"
73
+ 'INSERT INTO streaming (id, author, content, type, created_at) VALUES (?, ?, ?, ?, ?)'
74
74
  )
75
75
  .bind(id, author, content, type || null, createdAt)
76
76
  .run();
77
77
  } catch (dbError) {
78
78
  if (dbError instanceof Error && dbError.message.includes('UNIQUE')) {
79
- throw new HTTPException(409, { message: "Duplicate entry" });
79
+ throw new HTTPException(409, { message: 'Duplicate entry' });
80
80
  }
81
81
  throw dbError;
82
82
  }
83
83
 
84
- return c.json({
85
- status: "success",
86
- data: { id, author, content, type, createdAt }
87
- }, 201);
88
-
84
+ return c.json(
85
+ {
86
+ status: 'success',
87
+ data: { id, author, content, type, createdAt },
88
+ },
89
+ 201
90
+ );
89
91
  } catch (error) {
90
92
  if (error instanceof HTTPException) {
91
- return c.json({ status: "error", message: error.message }, error.status);
93
+ return c.json({ status: 'error', message: error.message }, error.status);
92
94
  }
93
-
95
+
94
96
  console.error('Unexpected error:', error);
95
- return c.json({
96
- status: "error",
97
- message: "Internal server error"
98
- }, 500);
97
+ return c.json(
98
+ {
99
+ status: 'error',
100
+ message: 'Internal server error',
101
+ },
102
+ 500
103
+ );
99
104
  }
100
- };
105
+ };
@@ -1,4 +1,4 @@
1
- import { Context } from "hono";
1
+ import { Context } from 'hono';
2
2
 
3
3
  export const listStreaming = async (c: Context) => {
4
4
  try {
@@ -6,9 +6,9 @@ export const listStreaming = async (c: Context) => {
6
6
  // 'before' - fetch records older than this ID (for pagination / next page)
7
7
  // 'after' - fetch records newer than this ID (for polling / new messages)
8
8
  // 'offset' - number of records to fetch (default: 8, max: 100)
9
- const before = c.req.query("before");
10
- const after = c.req.query("after");
11
- const offset = Math.min(parseInt(c.req.query("offset") || "8", 10), 100);
9
+ const before = c.req.query('before');
10
+ const after = c.req.query('after');
11
+ const offset = Math.min(parseInt(c.req.query('offset') || '8', 10), 100);
12
12
 
13
13
  let results;
14
14
 
@@ -20,7 +20,9 @@ export const listStreaming = async (c: Context) => {
20
20
  WHERE created_at < (SELECT created_at FROM streaming WHERE id = ?)
21
21
  ORDER BY created_at DESC
22
22
  LIMIT ?`
23
- ).bind(before, offset).all();
23
+ )
24
+ .bind(before, offset)
25
+ .all();
24
26
  results = cursorResults;
25
27
  } else if (after) {
26
28
  // Fetch records newer than the specified id (polling - new messages)
@@ -31,7 +33,9 @@ export const listStreaming = async (c: Context) => {
31
33
  WHERE created_at > (SELECT created_at FROM streaming WHERE id = ?)
32
34
  ORDER BY created_at ASC
33
35
  LIMIT ?`
34
- ).bind(after, offset).all();
36
+ )
37
+ .bind(after, offset)
38
+ .all();
35
39
  results = cursorResults;
36
40
  } else {
37
41
  // Fetch the most recent records
@@ -40,19 +44,24 @@ export const listStreaming = async (c: Context) => {
40
44
  FROM streaming
41
45
  ORDER BY created_at DESC
42
46
  LIMIT ?`
43
- ).bind(offset).all();
47
+ )
48
+ .bind(offset)
49
+ .all();
44
50
  results = recentResults;
45
51
  }
46
52
 
47
53
  return c.json({
48
- status: "success",
54
+ status: 'success',
49
55
  data: results,
50
56
  });
51
57
  } catch (error: any) {
52
- return c.json({
53
- status: "error",
54
- message: "Failed to fetch streaming",
55
- error: error.message,
56
- }, 500);
58
+ return c.json(
59
+ {
60
+ status: 'error',
61
+ message: 'Failed to fetch streaming',
62
+ error: error.message,
63
+ },
64
+ 500
65
+ );
57
66
  }
58
67
  };
@@ -1,5 +1,5 @@
1
- import { Context } from "hono";
2
- import { HTTPException } from "hono/http-exception";
1
+ import { Context } from 'hono';
2
+ import { HTTPException } from 'hono/http-exception';
3
3
 
4
4
  const timingSafeEqual = (a: string, b: string): boolean => {
5
5
  if (a.length !== b.length) return false;
@@ -16,58 +16,57 @@ export const removeStreaming = async (c: Context) => {
16
16
  const streamApiKey = c.env?.STREAM_API_KEY;
17
17
  if (!streamApiKey) {
18
18
  console.error('STREAM_API_KEY not configured in environment');
19
- throw new HTTPException(500, { message: "Server configuration error" });
19
+ throw new HTTPException(500, { message: 'Server configuration error' });
20
20
  }
21
21
 
22
22
  // 1. Authentication (Header method)
23
23
  const apiKey = c.req.header('x-api-key');
24
24
  if (!apiKey || !timingSafeEqual(apiKey, streamApiKey)) {
25
- throw new HTTPException(401, { message: "Invalid API key" });
25
+ throw new HTTPException(401, { message: 'Invalid API key' });
26
26
  }
27
27
 
28
28
  // 2. Get ID from URL params
29
29
  const id = c.req.param('id');
30
30
  if (!id) {
31
- throw new HTTPException(400, { message: "ID is required" });
31
+ throw new HTTPException(400, { message: 'ID is required' });
32
32
  }
33
33
 
34
34
  // 3. Database check
35
35
  if (!c.env?.DB) {
36
- throw new HTTPException(503, { message: "Database unavailable" });
36
+ throw new HTTPException(503, { message: 'Database unavailable' });
37
37
  }
38
38
 
39
39
  // 4. Check if stream exists
40
- const existing = await c.env.DB.prepare(
41
- "SELECT id FROM streaming WHERE id = ?"
42
- )
40
+ const existing = await c.env.DB.prepare('SELECT id FROM streaming WHERE id = ?')
43
41
  .bind(id)
44
42
  .first();
45
43
 
46
44
  if (!existing) {
47
- throw new HTTPException(404, { message: "Stream not found" });
45
+ throw new HTTPException(404, { message: 'Stream not found' });
48
46
  }
49
47
 
50
48
  // 5. Delete the stream
51
- await c.env.DB.prepare(
52
- "DELETE FROM streaming WHERE id = ?"
53
- )
54
- .bind(id)
55
- .run();
56
-
57
- return c.json({
58
- status: "success",
59
- message: "Stream deleted successfully"
60
- }, 200);
49
+ await c.env.DB.prepare('DELETE FROM streaming WHERE id = ?').bind(id).run();
61
50
 
51
+ return c.json(
52
+ {
53
+ status: 'success',
54
+ message: 'Stream deleted successfully',
55
+ },
56
+ 200
57
+ );
62
58
  } catch (error) {
63
59
  if (error instanceof HTTPException) {
64
- return c.json({ status: "error", message: error.message }, error.status);
60
+ return c.json({ status: 'error', message: error.message }, error.status);
65
61
  }
66
62
 
67
63
  console.error('Unexpected error:', error);
68
- return c.json({
69
- status: "error",
70
- message: "Internal server error"
71
- }, 500);
64
+ return c.json(
65
+ {
66
+ status: 'error',
67
+ message: 'Internal server error',
68
+ },
69
+ 500
70
+ );
72
71
  }
73
72
  };
@@ -1,8 +1,8 @@
1
- import { Hono } from "hono";
2
- import { addComment } from "../controllers/comment/add.controller";
1
+ import { Hono } from 'hono';
2
+ import { addComment } from '../controllers/comment/add.controller';
3
3
 
4
4
  const commentRouter = new Hono();
5
5
 
6
- commentRouter.post("/add", addComment);
6
+ commentRouter.post('/add', addComment);
7
7
 
8
8
  export { commentRouter };
@@ -1,12 +1,12 @@
1
- import { Hono } from "hono";
2
- import { listStreaming } from "../controllers/streaming/list.controller";
3
- import { addStreaming } from "../controllers/streaming/add.controller";
4
- import { removeStreaming } from "../controllers/streaming/remove.controller";
1
+ import { Hono } from 'hono';
2
+ import { listStreaming } from '../controllers/streaming/list.controller';
3
+ import { addStreaming } from '../controllers/streaming/add.controller';
4
+ import { removeStreaming } from '../controllers/streaming/remove.controller';
5
5
 
6
6
  const streamingRouter = new Hono();
7
7
 
8
- streamingRouter.get("/", listStreaming);
9
- streamingRouter.post("/", addStreaming);
10
- streamingRouter.delete("/:id", removeStreaming);
8
+ streamingRouter.get('/', listStreaming);
9
+ streamingRouter.post('/', addStreaming);
10
+ streamingRouter.delete('/:id', removeStreaming);
11
11
 
12
12
  export { streamingRouter };
package/tsconfig.json CHANGED
@@ -4,6 +4,6 @@
4
4
  "moduleResolution": "bundler",
5
5
  "jsx": "react-jsx",
6
6
  "jsxImportSource": "hono/jsx",
7
- "types": ["@cloudflare/workers-types", "node"],
8
- },
7
+ "types": ["@cloudflare/workers-types", "node"]
8
+ }
9
9
  }